github.com/nikandfor/tlog@v0.21.3/tlwire/decoder.go (about) 1 package tlwire 2 3 import ( 4 "math" 5 "time" 6 ) 7 8 type ( 9 Decoder struct { 10 LowDecoder 11 } 12 13 LowDecoder struct{} 14 ) 15 16 func (d Decoder) Time(p []byte, st int) (t time.Time, i int) { 17 if p[st] != Semantic|Time { 18 panic("not a time") 19 } 20 21 tag, sub, i := d.Tag(p, st+1) 22 23 if tag == Int { 24 return time.Unix(0, sub), i 25 } 26 27 if tag != Map || sub == -1 { 28 panic("unsupported time") 29 } 30 31 var ( 32 k []byte 33 ts int64 34 tzN []byte 35 tzOff int64 36 ) 37 38 for el := 0; el < int(sub); el++ { 39 k, i = d.Bytes(p, i) 40 41 switch string(k) { 42 case "t": 43 ts, i = d.Signed(p, i) 44 case "z": 45 if p[i] != Array|2 { 46 panic("unsupported time zone") 47 } 48 i++ 49 50 tzN, i = d.Bytes(p, i) 51 tzOff, i = d.Signed(p, i) 52 default: 53 i = d.Skip(p, i) 54 } 55 } 56 57 if ts != 0 { 58 t = time.Unix(0, ts) 59 } 60 61 if tzN != nil || tzOff != 0 { 62 l := time.FixedZone(string(tzN), int(tzOff)) 63 t = t.In(l) 64 } 65 66 return 67 } 68 69 func (d Decoder) Timestamp(p []byte, st int) (ts int64, i int) { 70 if p[st] != Semantic|Time { 71 panic("not a time") 72 } 73 74 tag, sub, i := d.Tag(p, st+1) 75 76 if tag == Int { 77 return sub, i 78 } 79 80 if tag != Map || sub == -1 { 81 panic("unsupported time") 82 } 83 84 var k []byte 85 86 for el := 0; el < int(sub); el++ { 87 k, i = d.Bytes(p, i) 88 89 switch string(k) { 90 case "t": 91 ts, i = d.Signed(p, i) 92 default: 93 i = d.Skip(p, i) 94 } 95 } 96 97 return 98 } 99 100 func (d Decoder) Duration(p []byte, st int) (dr time.Duration, i int) { 101 if p[st] != Semantic|Duration { 102 panic("not a duration") 103 } 104 105 tag, sub, i := d.Tag(p, st+1) 106 107 if tag != Int && tag != Neg { 108 panic("unsupported duration") 109 } 110 111 if tag == Neg { 112 sub = -sub 113 } 114 115 return time.Duration(sub), i 116 } 117 118 func (d LowDecoder) Skip(b []byte, st int) (i int) { 119 _, _, i = d.SkipTag(b, st) 120 return 121 } 122 123 func (d LowDecoder) SkipTag(b []byte, st int) (tag byte, sub int64, i int) { 124 tag, sub, i = d.Tag(b, st) 125 126 // println(fmt.Sprintf("Skip %x tag %x %x %x data % x", st, tag, sub, i, b[st:])) 127 128 switch tag { 129 case Int, Neg: 130 _, i = d.Unsigned(b, st) 131 case String, Bytes: 132 _, i = d.Bytes(b, st) 133 case Array, Map: 134 for el := 0; sub == -1 || el < int(sub); el++ { 135 if sub == -1 && d.Break(b, &i) { 136 break 137 } 138 139 if tag == Map { 140 _, i = d.Bytes(b, i) 141 } 142 143 i = d.Skip(b, i) 144 } 145 case Semantic: 146 i = d.Skip(b, i) 147 case Special: 148 switch sub { 149 case False, 150 True, 151 Nil, 152 Undefined, 153 None, 154 Break: 155 case Float8, Float16, Float32, Float64: 156 i += 1 << (int(sub) - Float8) 157 default: 158 panic("unsupported special") 159 } 160 } 161 162 return 163 } 164 165 func (d LowDecoder) Break(b []byte, i *int) bool { 166 if b[*i] != Special|Break { 167 return false 168 } 169 170 *i++ 171 172 return true 173 } 174 175 func (d LowDecoder) Bytes(b []byte, st int) (v []byte, i int) { 176 _, l, i := d.Tag(b, st) 177 178 return b[i : i+int(l)], i + int(l) 179 } 180 181 func (d LowDecoder) TagOnly(b []byte, st int) (tag byte) { 182 return b[st] & TagMask 183 } 184 185 func (d LowDecoder) Tag(b []byte, st int) (tag byte, sub int64, i int) { 186 i = st 187 188 tag = b[i] & TagMask 189 sub = int64(b[i] & TagDetMask) 190 i++ 191 192 if tag == Special { 193 return 194 } 195 196 switch { 197 case sub < Len1: 198 // we are ok 199 case sub == LenBreak: 200 sub = -1 201 case sub == Len1: 202 sub = int64(b[i]) 203 i++ 204 case sub == Len2: 205 sub = int64(b[i])<<8 | int64(b[i+1]) 206 i += 2 207 case sub == Len4: 208 sub = int64(b[i])<<24 | int64(b[i+1])<<16 | int64(b[i+2])<<8 | int64(b[i+3]) 209 i += 4 210 case sub == Len8: 211 sub = int64(b[i])<<56 | int64(b[i+1])<<48 | int64(b[i+2])<<40 | int64(b[i+3])<<32 | 212 int64(b[i+4])<<24 | int64(b[i+5])<<16 | int64(b[i+6])<<8 | int64(b[i+7]) 213 i += 8 214 default: 215 panic("malformed message") 216 } 217 218 return 219 } 220 221 func (d LowDecoder) Signed(b []byte, st int) (v int64, i int) { 222 u, i := d.Unsigned(b, st) 223 224 if b[st]&TagMask == Int { 225 return int64(u), i 226 } 227 228 return -int64(u), i 229 } 230 231 func (d LowDecoder) Unsigned(b []byte, st int) (v uint64, i int) { 232 i = st 233 234 v = uint64(b[i]) & TagDetMask 235 i++ 236 237 switch { 238 case v < Len1: 239 // we are ok 240 case v == Len1: 241 v = uint64(b[i]) 242 i++ 243 case v == Len2: 244 v = uint64(b[i])<<8 | uint64(b[i+1]) 245 i += 2 246 case v == Len4: 247 v = uint64(b[i])<<24 | uint64(b[i+1])<<16 | uint64(b[i+2])<<8 | uint64(b[i+3]) 248 i += 4 249 case v == Len8: 250 v = uint64(b[i])<<56 | uint64(b[i+1])<<48 | uint64(b[i+2])<<40 | uint64(b[i+3])<<32 | 251 uint64(b[i+4])<<24 | uint64(b[i+5])<<16 | uint64(b[i+6])<<8 | uint64(b[i+7]) 252 i += 8 253 default: 254 panic("malformed message") 255 } 256 257 return 258 } 259 260 func (d LowDecoder) Float(b []byte, st int) (v float64, i int) { 261 i = st 262 263 st = int(b[i]) & TagDetMask 264 i++ 265 266 switch { 267 case st == Float8: 268 v = float64(int8(b[i])) 269 i++ 270 case st == Float32: 271 v = float64(math.Float32frombits( 272 uint32(b[i])<<24 | uint32(b[i+1])<<16 | uint32(b[i+2])<<8 | uint32(b[i+3]), 273 )) 274 275 i += 4 276 case st == Float64: 277 v = math.Float64frombits( 278 uint64(b[i])<<56 | uint64(b[i+1])<<48 | uint64(b[i+2])<<40 | uint64(b[i+3])<<32 | 279 uint64(b[i+4])<<24 | uint64(b[i+5])<<16 | uint64(b[i+6])<<8 | uint64(b[i+7]), 280 ) 281 282 i += 8 283 default: 284 panic("malformed message") 285 } 286 287 return 288 }