github.com/nikandfor/tlog@v0.21.5-0.20231108111739-3ef89426a96d/tlwire/encoder.go (about) 1 package tlwire 2 3 import ( 4 "math" 5 "time" 6 7 "github.com/nikandfor/hacked/hfmt" 8 "github.com/nikandfor/hacked/htime" 9 ) 10 11 type ( 12 Encoder struct { 13 LowEncoder 14 15 custom encoders 16 } 17 18 LowEncoder struct{} 19 ) 20 21 func (e Encoder) AppendKey(b []byte, key string) []byte { 22 b = e.AppendTag(b, String, len(key)) 23 return append(b, key...) 24 } 25 26 func (e Encoder) AppendKeyString(b []byte, k, v string) []byte { 27 b = e.AppendTag(b, String, len(k)) 28 b = append(b, k...) 29 30 b = e.AppendTag(b, String, len(v)) 31 b = append(b, v...) 32 33 return b 34 } 35 36 func (e Encoder) AppendKeyInt(b []byte, k string, v int) []byte { 37 b = e.AppendTag(b, String, len(k)) 38 b = append(b, k...) 39 return e.AppendInt(b, v) 40 } 41 42 func (e Encoder) AppendKeyUint(b []byte, k string, v uint) []byte { 43 b = e.AppendTag(b, String, len(k)) 44 b = append(b, k...) 45 return e.AppendTag64(b, Int, uint64(v)) 46 } 47 48 func (e Encoder) AppendKeyInt64(b []byte, k string, v int64) []byte { 49 b = e.AppendTag(b, String, len(k)) 50 b = append(b, k...) 51 52 if v < 0 { 53 return e.AppendTag64(b, Neg, uint64(-v)) 54 } 55 56 return e.AppendTag64(b, Int, uint64(v)) 57 } 58 59 func (e Encoder) AppendKeyUint64(b []byte, k string, v uint64) []byte { 60 b = e.AppendTag(b, String, len(k)) 61 b = append(b, k...) 62 return e.AppendTag64(b, Int, v) 63 } 64 65 func (e Encoder) AppendError(b []byte, err error) []byte { 66 b = append(b, Semantic|Error) 67 68 if err == nil { 69 return append(b, Special|Nil) 70 } 71 72 return e.AppendString(b, err.Error()) 73 } 74 75 func (e Encoder) AppendTime(b []byte, t time.Time) []byte { 76 b = append(b, Semantic|Time) 77 return e.AppendInt64(b, t.UnixNano()) 78 } 79 80 func (e Encoder) AppendTimeTZ(b []byte, t time.Time) []byte { 81 b = append(b, Semantic|Time) 82 b = append(b, Map|2) 83 84 b = e.AppendKeyInt64(b, "t", t.UnixNano()) 85 86 b = e.AppendKey(b, "z") 87 b = append(b, Array|2) 88 89 n, off := t.Zone() 90 b = e.AppendString(b, n) 91 b = e.AppendInt(b, off) 92 93 return b 94 } 95 96 func (e Encoder) AppendTimeMonoTZ(b []byte, t time.Time) []byte { 97 b = append(b, Semantic|Time) 98 99 mono := htime.MonotonicOf(t) 100 fields := 2 101 102 if mono != 0 { 103 fields++ 104 } 105 106 b = append(b, Map|byte(fields)) 107 108 b = e.AppendKeyInt64(b, "t", t.UnixNano()) 109 110 if mono != 0 { 111 b = e.AppendKeyInt64(b, "m", mono) 112 } 113 114 b = e.AppendKey(b, "z") 115 b = append(b, Array|2) 116 117 n, off := t.Zone() 118 b = e.AppendString(b, n) 119 b = e.AppendInt(b, off) 120 121 return b 122 } 123 124 func (e Encoder) AppendTimestamp(b []byte, t int64) []byte { 125 b = append(b, Semantic|Time) 126 return e.AppendInt64(b, t) 127 } 128 129 func (e Encoder) AppendDuration(b []byte, d time.Duration) []byte { 130 b = append(b, Semantic|Duration) 131 return e.AppendInt64(b, d.Nanoseconds()) 132 } 133 134 func (e Encoder) AppendFormat(b []byte, fmt string, args ...interface{}) []byte { 135 b = append(b, String) 136 st := len(b) 137 138 if fmt == "" { 139 b = hfmt.Append(b, args...) 140 } else { 141 b = hfmt.Appendf(b, fmt, args...) 142 } 143 144 l := len(b) - st 145 146 return e.InsertLen(b, st, l) 147 } 148 149 // InsertLen inserts length l before value starting at st copying l bytes forward if needed. 150 // It is created for AppendFormat because we don't know the final message length. 151 // But it can be also used in other similar situations. 152 func (e Encoder) InsertLen(b []byte, st, l int) []byte { 153 if l < 0 { 154 panic(l) 155 } 156 157 b[st-1] &= TagMask 158 159 if l < Len1 { 160 b[st-1] |= byte(l) 161 162 return b 163 } 164 165 sz := e.TagSize(l) - 1 166 167 b = append(b, " "[:sz]...) 168 copy(b[st+sz:], b[st:]) 169 170 _ = e.AppendTag(b[:st-1], b[st-1], l) 171 172 return b 173 } 174 175 func (e LowEncoder) AppendMap(b []byte, l int) []byte { 176 return e.AppendTag(b, Map, l) 177 } 178 179 func (e LowEncoder) AppendArray(b []byte, l int) []byte { 180 return e.AppendTag(b, Array, l) 181 } 182 183 func (e LowEncoder) AppendString(b []byte, s string) []byte { 184 b = e.AppendTag(b, String, len(s)) 185 return append(b, s...) 186 } 187 188 func (e LowEncoder) AppendBytes(b, s []byte) []byte { 189 b = e.AppendTag(b, Bytes, len(s)) 190 return append(b, s...) 191 } 192 193 func (e LowEncoder) AppendTagString(b []byte, tag byte, s string) []byte { 194 b = e.AppendTag(b, tag, len(s)) 195 return append(b, s...) 196 } 197 198 func (e LowEncoder) AppendTagBytes(b []byte, tag byte, s []byte) []byte { 199 b = e.AppendTag(b, tag, len(s)) 200 return append(b, s...) 201 } 202 203 func (e LowEncoder) AppendInt(b []byte, v int) []byte { 204 if v < 0 { 205 return e.AppendTag64(b, Neg, uint64(-v)) 206 } 207 208 return e.AppendTag64(b, Int, uint64(v)) 209 } 210 211 func (e LowEncoder) AppendUint(b []byte, v uint) []byte { 212 return e.AppendTag64(b, Int, uint64(v)) 213 } 214 215 func (e LowEncoder) AppendInt64(b []byte, v int64) []byte { 216 if v < 0 { 217 return e.AppendTag64(b, Neg, uint64(-v)) 218 } 219 220 return e.AppendTag64(b, Int, uint64(v)) 221 } 222 223 func (e LowEncoder) AppendUint64(b []byte, v uint64) []byte { 224 return e.AppendTag64(b, Int, v) 225 } 226 227 func (e LowEncoder) AppendFloat(b []byte, v float64) []byte { 228 if q := int8(v); float64(q) == v { 229 return append(b, Special|Float8, byte(q)) 230 } 231 232 if q := float32(v); float64(q) == v { 233 r := math.Float32bits(q) 234 235 return append(b, Special|Float32, byte(r>>24), byte(r>>16), byte(r>>8), byte(r)) 236 } 237 238 r := math.Float64bits(v) 239 240 return append(b, Special|Float64, byte(r>>56), byte(r>>48), byte(r>>40), byte(r>>32), byte(r>>24), byte(r>>16), byte(r>>8), byte(r)) 241 } 242 243 func (e LowEncoder) AppendTag(b []byte, tag byte, v int) []byte { 244 switch { 245 case v == -1: 246 return append(b, tag|LenBreak) 247 case v < Len1: 248 return append(b, tag|byte(v)) 249 case v <= 0xff: 250 return append(b, tag|Len1, byte(v)) 251 case v <= 0xffff: 252 return append(b, tag|Len2, byte(v>>8), byte(v)) 253 case v <= 0xffff_ffff: 254 return append(b, tag|Len4, byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) 255 default: 256 return append(b, tag|Len8, byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) 257 } 258 } 259 260 func (e LowEncoder) AppendTag64(b []byte, tag byte, v uint64) []byte { 261 switch { 262 case v < Len1: 263 return append(b, tag|byte(v)) 264 case v <= 0xff: 265 return append(b, tag|Len1, byte(v)) 266 case v <= 0xffff: 267 return append(b, tag|Len2, byte(v>>8), byte(v)) 268 case v <= 0xffff_ffff: 269 return append(b, tag|Len4, byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) 270 default: 271 return append(b, tag|Len8, byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) 272 } 273 } 274 275 func (e LowEncoder) AppendTagBreak(b []byte, tag byte) []byte { 276 return append(b, tag|LenBreak) 277 } 278 279 func (e LowEncoder) AppendSemantic(b []byte, x int) []byte { 280 return e.AppendTag(b, Semantic, x) 281 } 282 283 func (e LowEncoder) AppendSpecial(b []byte, x byte) []byte { 284 return append(b, Special|x) 285 } 286 287 func (e LowEncoder) AppendBool(b []byte, v bool) []byte { 288 if v { 289 return append(b, Special|True) 290 } 291 292 return append(b, Special|False) 293 } 294 295 func (e LowEncoder) AppendNil(b []byte) []byte { 296 return append(b, Special|Nil) 297 } 298 299 func (e LowEncoder) AppendUndefined(b []byte) []byte { 300 return append(b, Special|Undefined) 301 } 302 303 func (e LowEncoder) AppendBreak(b []byte) []byte { 304 return append(b, Special|Break) 305 } 306 307 func (e LowEncoder) TagSize(v int) int { 308 switch { 309 case v == -1: 310 return 1 311 case v < Len1: 312 return 1 313 case v <= 0xff: 314 return 1 + 1 315 case v <= 0xffff: 316 return 1 + 2 317 case v <= 0xffff_ffff: 318 return 1 + 4 319 default: 320 return 1 + 8 321 } 322 } 323 324 func (e LowEncoder) Tag64Size(v uint64) int { 325 switch { 326 case v < Len1: 327 return 1 328 case v <= 0xff: 329 return 1 + 1 330 case v <= 0xffff: 331 return 1 + 2 332 case v <= 0xffff_ffff: 333 return 1 + 4 334 default: 335 return 1 + 8 336 } 337 }