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