github.com/grbit/go-json@v0.11.0/internal/encoder/encoder.go (about) 1 package encoder 2 3 import ( 4 "bytes" 5 "encoding" 6 "encoding/base64" 7 "encoding/json" 8 "fmt" 9 "math" 10 "reflect" 11 "strconv" 12 "strings" 13 "sync" 14 "unsafe" 15 16 "github.com/grbit/go-json/internal/errors" 17 "github.com/grbit/go-json/internal/runtime" 18 ) 19 20 func (t OpType) IsMultipleOpHead() bool { 21 switch t { 22 case OpStructHead: 23 return true 24 case OpStructHeadSlice: 25 return true 26 case OpStructHeadArray: 27 return true 28 case OpStructHeadMap: 29 return true 30 case OpStructHeadStruct: 31 return true 32 case OpStructHeadOmitEmpty: 33 return true 34 case OpStructHeadOmitEmptySlice: 35 return true 36 case OpStructHeadOmitEmptyArray: 37 return true 38 case OpStructHeadOmitEmptyMap: 39 return true 40 case OpStructHeadOmitEmptyStruct: 41 return true 42 case OpStructHeadSlicePtr: 43 return true 44 case OpStructHeadOmitEmptySlicePtr: 45 return true 46 case OpStructHeadArrayPtr: 47 return true 48 case OpStructHeadOmitEmptyArrayPtr: 49 return true 50 case OpStructHeadMapPtr: 51 return true 52 case OpStructHeadOmitEmptyMapPtr: 53 return true 54 } 55 return false 56 } 57 58 func (t OpType) IsMultipleOpField() bool { 59 switch t { 60 case OpStructField: 61 return true 62 case OpStructFieldSlice: 63 return true 64 case OpStructFieldArray: 65 return true 66 case OpStructFieldMap: 67 return true 68 case OpStructFieldStruct: 69 return true 70 case OpStructFieldOmitEmpty: 71 return true 72 case OpStructFieldOmitEmptySlice: 73 return true 74 case OpStructFieldOmitEmptyArray: 75 return true 76 case OpStructFieldOmitEmptyMap: 77 return true 78 case OpStructFieldOmitEmptyStruct: 79 return true 80 case OpStructFieldSlicePtr: 81 return true 82 case OpStructFieldOmitEmptySlicePtr: 83 return true 84 case OpStructFieldArrayPtr: 85 return true 86 case OpStructFieldOmitEmptyArrayPtr: 87 return true 88 case OpStructFieldMapPtr: 89 return true 90 case OpStructFieldOmitEmptyMapPtr: 91 return true 92 } 93 return false 94 } 95 96 type OpcodeSet struct { 97 Type *runtime.Type 98 NoescapeKeyCode *Opcode 99 EscapeKeyCode *Opcode 100 InterfaceNoescapeKeyCode *Opcode 101 InterfaceEscapeKeyCode *Opcode 102 CodeLength int 103 EndCode *Opcode 104 Code Code 105 QueryCache map[string]*OpcodeSet 106 cacheMu sync.RWMutex 107 } 108 109 func (s *OpcodeSet) getQueryCache(hash string) *OpcodeSet { 110 s.cacheMu.RLock() 111 codeSet := s.QueryCache[hash] 112 s.cacheMu.RUnlock() 113 return codeSet 114 } 115 116 func (s *OpcodeSet) setQueryCache(hash string, codeSet *OpcodeSet) { 117 s.cacheMu.Lock() 118 s.QueryCache[hash] = codeSet 119 s.cacheMu.Unlock() 120 } 121 122 type CompiledCode struct { 123 Code *Opcode 124 Linked bool // whether recursive code already have linked 125 CurLen uintptr 126 NextLen uintptr 127 } 128 129 const StartDetectingCyclesAfter = 1000 130 131 func Load(base uintptr, idx uintptr) uintptr { 132 addr := base + idx 133 return **(**uintptr)(unsafe.Pointer(&addr)) 134 } 135 136 func Store(base uintptr, idx uintptr, p uintptr) { 137 addr := base + idx 138 **(**uintptr)(unsafe.Pointer(&addr)) = p 139 } 140 141 func LoadNPtr(base uintptr, idx uintptr, ptrNum int) uintptr { 142 addr := base + idx 143 p := **(**uintptr)(unsafe.Pointer(&addr)) 144 if p == 0 { 145 return 0 146 } 147 return PtrToPtr(p) 148 /* 149 for i := 0; i < ptrNum; i++ { 150 if p == 0 { 151 return p 152 } 153 p = PtrToPtr(p) 154 } 155 return p 156 */ 157 } 158 159 func PtrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) } 160 func PtrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) } 161 func PtrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) } 162 func PtrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) } 163 func PtrToBytes(p uintptr) []byte { return **(**[]byte)(unsafe.Pointer(&p)) } 164 func PtrToNumber(p uintptr) json.Number { return **(**json.Number)(unsafe.Pointer(&p)) } 165 func PtrToString(p uintptr) string { return **(**string)(unsafe.Pointer(&p)) } 166 func PtrToSlice(p uintptr) *runtime.SliceHeader { return *(**runtime.SliceHeader)(unsafe.Pointer(&p)) } 167 func PtrToPtr(p uintptr) uintptr { 168 return uintptr(**(**unsafe.Pointer)(unsafe.Pointer(&p))) 169 } 170 func PtrToNPtr(p uintptr, ptrNum int) uintptr { 171 for i := 0; i < ptrNum; i++ { 172 if p == 0 { 173 return 0 174 } 175 p = PtrToPtr(p) 176 } 177 return p 178 } 179 180 func PtrToUnsafePtr(p uintptr) unsafe.Pointer { 181 return *(*unsafe.Pointer)(unsafe.Pointer(&p)) 182 } 183 func PtrToInterface(code *Opcode, p uintptr) interface{} { 184 return *(*interface{})(unsafe.Pointer(&emptyInterface{ 185 typ: code.Type, 186 ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)), 187 })) 188 } 189 190 func ErrUnsupportedValue(code *Opcode, ptr uintptr) *errors.UnsupportedValueError { 191 v := *(*interface{})(unsafe.Pointer(&emptyInterface{ 192 typ: code.Type, 193 ptr: *(*unsafe.Pointer)(unsafe.Pointer(&ptr)), 194 })) 195 return &errors.UnsupportedValueError{ 196 Value: reflect.ValueOf(v), 197 Str: fmt.Sprintf("encountered a cycle via %s", code.Type), 198 } 199 } 200 201 func ErrUnsupportedFloat(v float64) *errors.UnsupportedValueError { 202 return &errors.UnsupportedValueError{ 203 Value: reflect.ValueOf(v), 204 Str: strconv.FormatFloat(v, 'g', -1, 64), 205 } 206 } 207 208 func ErrMarshalerWithCode(code *Opcode, err error) *errors.MarshalerError { 209 return &errors.MarshalerError{ 210 Type: runtime.RType2Type(code.Type), 211 Err: err, 212 } 213 } 214 215 type emptyInterface struct { 216 typ *runtime.Type 217 ptr unsafe.Pointer 218 } 219 220 type MapItem struct { 221 Key []byte 222 Value []byte 223 } 224 225 type Mapslice struct { 226 Items []MapItem 227 } 228 229 func (m *Mapslice) Len() int { 230 return len(m.Items) 231 } 232 233 func (m *Mapslice) Less(i, j int) bool { 234 return bytes.Compare(m.Items[i].Key, m.Items[j].Key) < 0 235 } 236 237 func (m *Mapslice) Swap(i, j int) { 238 m.Items[i], m.Items[j] = m.Items[j], m.Items[i] 239 } 240 241 //nolint:structcheck,unused 242 type mapIter struct { 243 key unsafe.Pointer 244 elem unsafe.Pointer 245 t unsafe.Pointer 246 h unsafe.Pointer 247 buckets unsafe.Pointer 248 bptr unsafe.Pointer 249 overflow unsafe.Pointer 250 oldoverflow unsafe.Pointer 251 startBucket uintptr 252 offset uint8 253 wrapped bool 254 B uint8 255 i uint8 256 bucket uintptr 257 checkBucket uintptr 258 } 259 260 type MapContext struct { 261 Start int 262 First int 263 Idx int 264 Slice *Mapslice 265 Buf []byte 266 Len int 267 Iter mapIter 268 } 269 270 var mapContextPool = sync.Pool{ 271 New: func() interface{} { 272 return &MapContext{ 273 Slice: &Mapslice{}, 274 } 275 }, 276 } 277 278 func NewMapContext(mapLen int, unorderedMap bool) *MapContext { 279 ctx := mapContextPool.Get().(*MapContext) 280 if !unorderedMap { 281 if len(ctx.Slice.Items) < mapLen { 282 ctx.Slice.Items = make([]MapItem, mapLen) 283 } else { 284 ctx.Slice.Items = ctx.Slice.Items[:mapLen] 285 } 286 } 287 ctx.Buf = ctx.Buf[:0] 288 ctx.Iter = mapIter{} 289 ctx.Idx = 0 290 ctx.Len = mapLen 291 return ctx 292 } 293 294 func ReleaseMapContext(c *MapContext) { 295 mapContextPool.Put(c) 296 } 297 298 //go:linkname MapIterInit runtime.mapiterinit 299 //go:noescape 300 func MapIterInit(mapType *runtime.Type, m unsafe.Pointer, it *mapIter) 301 302 //go:linkname MapIterKey reflect.mapiterkey 303 //go:noescape 304 func MapIterKey(it *mapIter) unsafe.Pointer 305 306 //go:linkname MapIterNext reflect.mapiternext 307 //go:noescape 308 func MapIterNext(it *mapIter) 309 310 //go:linkname MapLen reflect.maplen 311 //go:noescape 312 func MapLen(m unsafe.Pointer) int 313 314 func AppendByteSlice(_ *RuntimeContext, b []byte, src []byte) []byte { 315 if src == nil { 316 return append(b, `null`...) 317 } 318 encodedLen := base64.StdEncoding.EncodedLen(len(src)) 319 b = append(b, '"') 320 pos := len(b) 321 remainLen := cap(b[pos:]) 322 var buf []byte 323 if remainLen > encodedLen { 324 buf = b[pos : pos+encodedLen] 325 } else { 326 buf = make([]byte, encodedLen) 327 } 328 base64.StdEncoding.Encode(buf, src) 329 return append(append(b, buf...), '"') 330 } 331 332 func AppendFloat32(_ *RuntimeContext, b []byte, v float32) []byte { 333 f64 := float64(v) 334 abs := math.Abs(f64) 335 fmt := byte('f') 336 // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. 337 if abs != 0 { 338 f32 := float32(abs) 339 if f32 < 1e-6 || f32 >= 1e21 { 340 fmt = 'e' 341 } 342 } 343 return strconv.AppendFloat(b, f64, fmt, -1, 32) 344 } 345 346 func AppendFloat64(_ *RuntimeContext, b []byte, v float64) []byte { 347 abs := math.Abs(v) 348 fmt := byte('f') 349 // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. 350 if abs != 0 { 351 if abs < 1e-6 || abs >= 1e21 { 352 fmt = 'e' 353 } 354 } 355 return strconv.AppendFloat(b, v, fmt, -1, 64) 356 } 357 358 func AppendBool(_ *RuntimeContext, b []byte, v bool) []byte { 359 if v { 360 return append(b, "true"...) 361 } 362 return append(b, "false"...) 363 } 364 365 var ( 366 floatTable = [256]bool{ 367 '0': true, 368 '1': true, 369 '2': true, 370 '3': true, 371 '4': true, 372 '5': true, 373 '6': true, 374 '7': true, 375 '8': true, 376 '9': true, 377 '.': true, 378 'e': true, 379 'E': true, 380 '+': true, 381 '-': true, 382 } 383 ) 384 385 func AppendNumber(_ *RuntimeContext, b []byte, n json.Number) ([]byte, error) { 386 if len(n) == 0 { 387 return append(b, '0'), nil 388 } 389 for i := 0; i < len(n); i++ { 390 if !floatTable[n[i]] { 391 return nil, fmt.Errorf("json: invalid number literal %q", n) 392 } 393 } 394 b = append(b, n...) 395 return b, nil 396 } 397 398 func AppendMarshalJSON(ctx *RuntimeContext, code *Opcode, b []byte, v interface{}) ([]byte, error) { 399 rv := reflect.ValueOf(v) // convert by dynamic interface type 400 if (code.Flags & AddrForMarshalerFlags) != 0 { 401 if rv.CanAddr() { 402 rv = rv.Addr() 403 } else { 404 newV := reflect.New(rv.Type()) 405 newV.Elem().Set(rv) 406 rv = newV 407 } 408 } 409 v = rv.Interface() 410 var bb []byte 411 if (code.Flags & MarshalerContextFlags) != 0 { 412 marshaler, ok := v.(marshalerContext) 413 if !ok { 414 return AppendNull(ctx, b), nil 415 } 416 stdctx := ctx.Option.Context 417 if ctx.Option.Flag&FieldQueryOption != 0 { 418 stdctx = SetFieldQueryToContext(stdctx, code.FieldQuery) 419 } 420 b, err := marshaler.MarshalJSON(stdctx) 421 if err != nil { 422 return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} 423 } 424 bb = b 425 } else { 426 marshaler, ok := v.(json.Marshaler) 427 if !ok { 428 return AppendNull(ctx, b), nil 429 } 430 b, err := marshaler.MarshalJSON() 431 if err != nil { 432 return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} 433 } 434 bb = b 435 } 436 marshalBuf := ctx.MarshalBuf[:0] 437 marshalBuf = append(append(marshalBuf, bb...), nul) 438 compactedBuf, err := compact(b, marshalBuf, (ctx.Option.Flag&HTMLEscapeOption) != 0) 439 if err != nil { 440 return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} 441 } 442 ctx.MarshalBuf = marshalBuf 443 return compactedBuf, nil 444 } 445 446 func AppendMarshalJSONIndent(ctx *RuntimeContext, code *Opcode, b []byte, v interface{}) ([]byte, error) { 447 rv := reflect.ValueOf(v) // convert by dynamic interface type 448 if (code.Flags & AddrForMarshalerFlags) != 0 { 449 if rv.CanAddr() { 450 rv = rv.Addr() 451 } else { 452 newV := reflect.New(rv.Type()) 453 newV.Elem().Set(rv) 454 rv = newV 455 } 456 } 457 v = rv.Interface() 458 var bb []byte 459 if (code.Flags & MarshalerContextFlags) != 0 { 460 marshaler, ok := v.(marshalerContext) 461 if !ok { 462 return AppendNull(ctx, b), nil 463 } 464 b, err := marshaler.MarshalJSON(ctx.Option.Context) 465 if err != nil { 466 return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} 467 } 468 bb = b 469 } else { 470 marshaler, ok := v.(json.Marshaler) 471 if !ok { 472 return AppendNull(ctx, b), nil 473 } 474 b, err := marshaler.MarshalJSON() 475 if err != nil { 476 return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} 477 } 478 bb = b 479 } 480 marshalBuf := ctx.MarshalBuf[:0] 481 marshalBuf = append(append(marshalBuf, bb...), nul) 482 indentedBuf, err := doIndent( 483 b, 484 marshalBuf, 485 string(ctx.Prefix)+strings.Repeat(string(ctx.IndentStr), int(ctx.BaseIndent+code.Indent)), 486 string(ctx.IndentStr), 487 (ctx.Option.Flag&HTMLEscapeOption) != 0, 488 ) 489 if err != nil { 490 return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} 491 } 492 ctx.MarshalBuf = marshalBuf 493 return indentedBuf, nil 494 } 495 496 func AppendMarshalText(ctx *RuntimeContext, code *Opcode, b []byte, v interface{}) ([]byte, error) { 497 rv := reflect.ValueOf(v) // convert by dynamic interface type 498 if (code.Flags & AddrForMarshalerFlags) != 0 { 499 if rv.CanAddr() { 500 rv = rv.Addr() 501 } else { 502 newV := reflect.New(rv.Type()) 503 newV.Elem().Set(rv) 504 rv = newV 505 } 506 } 507 v = rv.Interface() 508 marshaler, ok := v.(encoding.TextMarshaler) 509 if !ok { 510 return AppendNull(ctx, b), nil 511 } 512 bytes, err := marshaler.MarshalText() 513 if err != nil { 514 return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} 515 } 516 return AppendString(ctx, b, *(*string)(unsafe.Pointer(&bytes))), nil 517 } 518 519 func AppendMarshalTextIndent(ctx *RuntimeContext, code *Opcode, b []byte, v interface{}) ([]byte, error) { 520 rv := reflect.ValueOf(v) // convert by dynamic interface type 521 if (code.Flags & AddrForMarshalerFlags) != 0 { 522 if rv.CanAddr() { 523 rv = rv.Addr() 524 } else { 525 newV := reflect.New(rv.Type()) 526 newV.Elem().Set(rv) 527 rv = newV 528 } 529 } 530 v = rv.Interface() 531 marshaler, ok := v.(encoding.TextMarshaler) 532 if !ok { 533 return AppendNull(ctx, b), nil 534 } 535 bytes, err := marshaler.MarshalText() 536 if err != nil { 537 return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} 538 } 539 return AppendString(ctx, b, *(*string)(unsafe.Pointer(&bytes))), nil 540 } 541 542 func AppendNull(_ *RuntimeContext, b []byte) []byte { 543 return append(b, "null"...) 544 } 545 546 func AppendComma(_ *RuntimeContext, b []byte) []byte { 547 return append(b, ',') 548 } 549 550 func AppendCommaIndent(_ *RuntimeContext, b []byte) []byte { 551 return append(b, ',', '\n') 552 } 553 554 func AppendStructEnd(_ *RuntimeContext, b []byte) []byte { 555 return append(b, '}', ',') 556 } 557 558 func AppendStructEndIndent(ctx *RuntimeContext, code *Opcode, b []byte) []byte { 559 b = append(b, '\n') 560 b = append(b, ctx.Prefix...) 561 indentNum := ctx.BaseIndent + code.Indent - 1 562 for i := uint32(0); i < indentNum; i++ { 563 b = append(b, ctx.IndentStr...) 564 } 565 return append(b, '}', ',', '\n') 566 } 567 568 func AppendIndent(ctx *RuntimeContext, b []byte, indent uint32) []byte { 569 b = append(b, ctx.Prefix...) 570 indentNum := ctx.BaseIndent + indent 571 for i := uint32(0); i < indentNum; i++ { 572 b = append(b, ctx.IndentStr...) 573 } 574 return b 575 } 576 577 func IsNilForMarshaler(v interface{}) bool { 578 rv := reflect.ValueOf(v) 579 switch rv.Kind() { 580 case reflect.Bool: 581 return !rv.Bool() 582 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 583 return rv.Int() == 0 584 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 585 return rv.Uint() == 0 586 case reflect.Float32, reflect.Float64: 587 return math.Float64bits(rv.Float()) == 0 588 case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Func: 589 return rv.IsNil() 590 case reflect.Slice: 591 return rv.IsNil() || rv.Len() == 0 592 case reflect.String: 593 return rv.Len() == 0 594 } 595 return false 596 }