github.com/3JoB/go-json@v0.10.4/internal/encoder/code.go (about) 1 package encoder 2 3 import ( 4 "fmt" 5 "unsafe" 6 7 "github.com/3JoB/go-reflect" 8 "github.com/3JoB/unsafeConvert" 9 10 "github.com/3JoB/go-json/internal/runtime" 11 ) 12 13 type Code interface { 14 Kind() CodeKind 15 ToOpcode(*compileContext) Opcodes 16 Filter(*FieldQuery) Code 17 } 18 19 type AnonymousCode interface { 20 ToAnonymousOpcode(*compileContext) Opcodes 21 } 22 23 type Opcodes []*Opcode 24 25 func (o Opcodes) First() *Opcode { 26 if len(o) == 0 { 27 return nil 28 } 29 return o[0] 30 } 31 32 func (o Opcodes) Last() *Opcode { 33 if len(o) == 0 { 34 return nil 35 } 36 return o[len(o)-1] 37 } 38 39 func (o Opcodes) Add(codes ...*Opcode) Opcodes { 40 return append(o, codes...) 41 } 42 43 type CodeKind int 44 45 const ( 46 CodeKindInterface CodeKind = iota 47 CodeKindPtr 48 CodeKindInt 49 CodeKindUint 50 CodeKindFloat 51 CodeKindString 52 CodeKindBool 53 CodeKindStruct 54 CodeKindMap 55 CodeKindSlice 56 CodeKindArray 57 CodeKindBytes 58 CodeKindMarshalJSON 59 CodeKindMarshalText 60 CodeKindRecursive 61 ) 62 63 type IntCode struct { 64 typ *runtime.Type 65 bitSize uint8 66 isString bool 67 isPtr bool 68 } 69 70 func (c *IntCode) Kind() CodeKind { 71 return CodeKindInt 72 } 73 74 func (c *IntCode) ToOpcode(ctx *compileContext) Opcodes { 75 var code *Opcode 76 switch { 77 case c.isPtr: 78 code = newOpCode(ctx, c.typ, OpIntPtr) 79 case c.isString: 80 code = newOpCode(ctx, c.typ, OpIntString) 81 default: 82 code = newOpCode(ctx, c.typ, OpInt) 83 } 84 code.NumBitSize = c.bitSize 85 ctx.incIndex() 86 return Opcodes{code} 87 } 88 89 func (c *IntCode) Filter(_ *FieldQuery) Code { 90 return c 91 } 92 93 type UintCode struct { 94 typ *runtime.Type 95 bitSize uint8 96 isString bool 97 isPtr bool 98 } 99 100 func (c *UintCode) Kind() CodeKind { 101 return CodeKindUint 102 } 103 104 func (c *UintCode) ToOpcode(ctx *compileContext) Opcodes { 105 var code *Opcode 106 switch { 107 case c.isPtr: 108 code = newOpCode(ctx, c.typ, OpUintPtr) 109 case c.isString: 110 code = newOpCode(ctx, c.typ, OpUintString) 111 default: 112 code = newOpCode(ctx, c.typ, OpUint) 113 } 114 code.NumBitSize = c.bitSize 115 ctx.incIndex() 116 return Opcodes{code} 117 } 118 119 func (c *UintCode) Filter(_ *FieldQuery) Code { 120 return c 121 } 122 123 type FloatCode struct { 124 typ *runtime.Type 125 bitSize uint8 126 isPtr bool 127 } 128 129 func (c *FloatCode) Kind() CodeKind { 130 return CodeKindFloat 131 } 132 133 func (c *FloatCode) ToOpcode(ctx *compileContext) Opcodes { 134 var code *Opcode 135 switch { 136 case c.isPtr: 137 switch c.bitSize { 138 case 32: 139 code = newOpCode(ctx, c.typ, OpFloat32Ptr) 140 default: 141 code = newOpCode(ctx, c.typ, OpFloat64Ptr) 142 } 143 default: 144 switch c.bitSize { 145 case 32: 146 code = newOpCode(ctx, c.typ, OpFloat32) 147 default: 148 code = newOpCode(ctx, c.typ, OpFloat64) 149 } 150 } 151 ctx.incIndex() 152 return Opcodes{code} 153 } 154 155 func (c *FloatCode) Filter(_ *FieldQuery) Code { 156 return c 157 } 158 159 type StringCode struct { 160 typ *runtime.Type 161 isPtr bool 162 } 163 164 func (c *StringCode) Kind() CodeKind { 165 return CodeKindString 166 } 167 168 func (c *StringCode) ToOpcode(ctx *compileContext) Opcodes { 169 isJSONNumberType := c.typ == runtime.Type2RType(reflect.ToRT(jsonNumberType)) 170 var code *Opcode 171 if c.isPtr { 172 if isJSONNumberType { 173 code = newOpCode(ctx, c.typ, OpNumberPtr) 174 } else { 175 code = newOpCode(ctx, c.typ, OpStringPtr) 176 } 177 } else { 178 if isJSONNumberType { 179 code = newOpCode(ctx, c.typ, OpNumber) 180 } else { 181 code = newOpCode(ctx, c.typ, OpString) 182 } 183 } 184 ctx.incIndex() 185 return Opcodes{code} 186 } 187 188 func (c *StringCode) Filter(_ *FieldQuery) Code { 189 return c 190 } 191 192 type BoolCode struct { 193 typ *runtime.Type 194 isPtr bool 195 } 196 197 func (c *BoolCode) Kind() CodeKind { 198 return CodeKindBool 199 } 200 201 func (c *BoolCode) ToOpcode(ctx *compileContext) Opcodes { 202 var code *Opcode 203 switch { 204 case c.isPtr: 205 code = newOpCode(ctx, c.typ, OpBoolPtr) 206 default: 207 code = newOpCode(ctx, c.typ, OpBool) 208 } 209 ctx.incIndex() 210 return Opcodes{code} 211 } 212 213 func (c *BoolCode) Filter(_ *FieldQuery) Code { 214 return c 215 } 216 217 type BytesCode struct { 218 typ *runtime.Type 219 isPtr bool 220 } 221 222 func (c *BytesCode) Kind() CodeKind { 223 return CodeKindBytes 224 } 225 226 func (c *BytesCode) ToOpcode(ctx *compileContext) Opcodes { 227 var code *Opcode 228 switch { 229 case c.isPtr: 230 code = newOpCode(ctx, c.typ, OpBytesPtr) 231 default: 232 code = newOpCode(ctx, c.typ, OpBytes) 233 } 234 ctx.incIndex() 235 return Opcodes{code} 236 } 237 238 func (c *BytesCode) Filter(_ *FieldQuery) Code { 239 return c 240 } 241 242 type SliceCode struct { 243 typ *runtime.Type 244 value Code 245 } 246 247 func (c *SliceCode) Kind() CodeKind { 248 return CodeKindSlice 249 } 250 251 func (c *SliceCode) ToOpcode(ctx *compileContext) Opcodes { 252 // header => opcode => elem => end 253 // ^ | 254 // |________| 255 size := c.typ.Elem().Size() 256 header := newSliceHeaderCode(ctx, c.typ) 257 ctx.incIndex() 258 259 ctx.incIndent() 260 codes := c.value.ToOpcode(ctx) 261 ctx.decIndent() 262 263 codes.First().Flags |= IndirectFlags 264 elemCode := newSliceElemCode(ctx, c.typ.Elem(), header, size) 265 ctx.incIndex() 266 end := newOpCode(ctx, c.typ, OpSliceEnd) 267 ctx.incIndex() 268 header.End = end 269 header.Next = codes.First() 270 codes.Last().Next = elemCode 271 elemCode.Next = codes.First() 272 elemCode.End = end 273 return Opcodes{header}.Add(codes...).Add(elemCode).Add(end) 274 } 275 276 func (c *SliceCode) Filter(_ *FieldQuery) Code { 277 return c 278 } 279 280 type ArrayCode struct { 281 typ *runtime.Type 282 value Code 283 } 284 285 func (c *ArrayCode) Kind() CodeKind { 286 return CodeKindArray 287 } 288 289 func (c *ArrayCode) ToOpcode(ctx *compileContext) Opcodes { 290 // header => opcode => elem => end 291 // ^ | 292 // |________| 293 elem := c.typ.Elem() 294 alen := c.typ.Len() 295 size := elem.Size() 296 297 header := newArrayHeaderCode(ctx, c.typ, alen) 298 ctx.incIndex() 299 300 ctx.incIndent() 301 codes := c.value.ToOpcode(ctx) 302 ctx.decIndent() 303 304 codes.First().Flags |= IndirectFlags 305 306 elemCode := newArrayElemCode(ctx, elem, header, alen, size) 307 ctx.incIndex() 308 309 end := newOpCode(ctx, c.typ, OpArrayEnd) 310 ctx.incIndex() 311 312 header.End = end 313 header.Next = codes.First() 314 codes.Last().Next = elemCode 315 elemCode.Next = codes.First() 316 elemCode.End = end 317 318 return Opcodes{header}.Add(codes...).Add(elemCode).Add(end) 319 } 320 321 func (c *ArrayCode) Filter(_ *FieldQuery) Code { 322 return c 323 } 324 325 type MapCode struct { 326 typ *runtime.Type 327 key Code 328 value Code 329 } 330 331 func (c *MapCode) Kind() CodeKind { 332 return CodeKindMap 333 } 334 335 func (c *MapCode) ToOpcode(ctx *compileContext) Opcodes { 336 // header => code => value => code => key => code => value => code => end 337 // ^ | 338 // |_______________________| 339 header := newMapHeaderCode(ctx, c.typ) 340 ctx.incIndex() 341 342 keyCodes := c.key.ToOpcode(ctx) 343 344 value := newMapValueCode(ctx, c.typ.Elem(), header) 345 ctx.incIndex() 346 347 ctx.incIndent() 348 valueCodes := c.value.ToOpcode(ctx) 349 ctx.decIndent() 350 351 valueCodes.First().Flags |= IndirectFlags 352 353 key := newMapKeyCode(ctx, c.typ.Key(), header) 354 ctx.incIndex() 355 356 end := newMapEndCode(ctx, c.typ, header) 357 ctx.incIndex() 358 359 header.Next = keyCodes.First() 360 keyCodes.Last().Next = value 361 value.Next = valueCodes.First() 362 valueCodes.Last().Next = key 363 key.Next = keyCodes.First() 364 365 header.End = end 366 key.End = end 367 value.End = end 368 return Opcodes{header}.Add(keyCodes...).Add(value).Add(valueCodes...).Add(key).Add(end) 369 } 370 371 func (c *MapCode) Filter(_ *FieldQuery) Code { 372 return c 373 } 374 375 type StructCode struct { 376 typ *runtime.Type 377 fields []*StructFieldCode 378 isPtr bool 379 disableIndirectConversion bool 380 isIndirect bool 381 isRecursive bool 382 } 383 384 func (c *StructCode) Kind() CodeKind { 385 return CodeKindStruct 386 } 387 388 func (c *StructCode) lastFieldCode(field *StructFieldCode, firstField *Opcode) *Opcode { 389 if isEmbeddedStruct(field) { 390 return c.lastAnonymousFieldCode(firstField) 391 } 392 lastField := firstField 393 for lastField.NextField != nil { 394 lastField = lastField.NextField 395 } 396 return lastField 397 } 398 399 func (c *StructCode) lastAnonymousFieldCode(firstField *Opcode) *Opcode { 400 // firstField is special StructHead operation for anonymous structure. 401 // So, StructHead's next operation is truly struct head operation. 402 for firstField.Op == OpStructHead || firstField.Op == OpStructField { 403 firstField = firstField.Next 404 } 405 lastField := firstField 406 for lastField.NextField != nil { 407 lastField = lastField.NextField 408 } 409 return lastField 410 } 411 412 func (c *StructCode) ToOpcode(ctx *compileContext) Opcodes { 413 // header => code => structField => code => end 414 // ^ | 415 // |__________| 416 if c.isRecursive { 417 recursive := newRecursiveCode(ctx, c.typ, &CompiledCode{}) 418 recursive.Type = c.typ 419 ctx.incIndex() 420 *ctx.recursiveCodes = append(*ctx.recursiveCodes, recursive) 421 return Opcodes{recursive} 422 } 423 codes := Opcodes{} 424 var prevField *Opcode 425 ctx.incIndent() 426 for idx, field := range c.fields { 427 isFirstField := idx == 0 428 isEndField := idx == len(c.fields)-1 429 fieldCodes := field.ToOpcode(ctx, isFirstField, isEndField) 430 for _, code := range fieldCodes { 431 if c.isIndirect { 432 code.Flags |= IndirectFlags 433 } 434 } 435 firstField := fieldCodes.First() 436 if len(codes) > 0 { 437 codes.Last().Next = firstField 438 firstField.Idx = codes.First().Idx 439 } 440 if prevField != nil { 441 prevField.NextField = firstField 442 } 443 if isEndField { 444 endField := fieldCodes.Last() 445 if len(codes) > 0 { 446 codes.First().End = endField 447 } else { 448 firstField.End = endField 449 } 450 codes = codes.Add(fieldCodes...) 451 break 452 } 453 prevField = c.lastFieldCode(field, firstField) 454 codes = codes.Add(fieldCodes...) 455 } 456 if len(codes) == 0 { 457 head := &Opcode{ 458 Op: OpStructHead, 459 Idx: opcodeOffset(ctx.ptrIndex), 460 Type: c.typ, 461 DisplayIdx: ctx.opcodeIndex, 462 Indent: ctx.indent, 463 } 464 ctx.incOpcodeIndex() 465 end := &Opcode{ 466 Op: OpStructEnd, 467 Idx: opcodeOffset(ctx.ptrIndex), 468 DisplayIdx: ctx.opcodeIndex, 469 Indent: ctx.indent, 470 } 471 head.NextField = end 472 head.Next = end 473 head.End = end 474 codes = codes.Add(head, end) 475 ctx.incIndex() 476 } 477 ctx.decIndent() 478 ctx.structTypeToCodes[uintptr(unsafe.Pointer(c.typ))] = codes 479 return codes 480 } 481 482 func (c *StructCode) ToAnonymousOpcode(ctx *compileContext) Opcodes { 483 // header => code => structField => code => end 484 // ^ | 485 // |__________| 486 if c.isRecursive { 487 recursive := newRecursiveCode(ctx, c.typ, &CompiledCode{}) 488 recursive.Type = c.typ 489 ctx.incIndex() 490 *ctx.recursiveCodes = append(*ctx.recursiveCodes, recursive) 491 return Opcodes{recursive} 492 } 493 codes := Opcodes{} 494 var prevField *Opcode 495 for idx, field := range c.fields { 496 isFirstField := idx == 0 497 isEndField := idx == len(c.fields)-1 498 fieldCodes := field.ToAnonymousOpcode(ctx, isFirstField, isEndField) 499 for _, code := range fieldCodes { 500 if c.isIndirect { 501 code.Flags |= IndirectFlags 502 } 503 } 504 firstField := fieldCodes.First() 505 if len(codes) > 0 { 506 codes.Last().Next = firstField 507 firstField.Idx = codes.First().Idx 508 } 509 if prevField != nil { 510 prevField.NextField = firstField 511 } 512 if isEndField { 513 lastField := fieldCodes.Last() 514 if len(codes) > 0 { 515 codes.First().End = lastField 516 } else { 517 firstField.End = lastField 518 } 519 } 520 prevField = firstField 521 codes = codes.Add(fieldCodes...) 522 } 523 return codes 524 } 525 526 func (c *StructCode) removeFieldsByTags(tags runtime.StructTags) { 527 fields := make([]*StructFieldCode, 0, len(c.fields)) 528 for _, field := range c.fields { 529 if field.isAnonymous { 530 structCode := field.getAnonymousStruct() 531 if structCode != nil && !structCode.isRecursive { 532 structCode.removeFieldsByTags(tags) 533 if len(structCode.fields) > 0 { 534 fields = append(fields, field) 535 } 536 continue 537 } 538 } 539 if tags.ExistsKey(field.key) { 540 continue 541 } 542 fields = append(fields, field) 543 } 544 c.fields = fields 545 } 546 547 func (c *StructCode) enableIndirect() { 548 if c.isIndirect { 549 return 550 } 551 c.isIndirect = true 552 if len(c.fields) == 0 { 553 return 554 } 555 structCode := c.fields[0].getStruct() 556 if structCode == nil { 557 return 558 } 559 structCode.enableIndirect() 560 } 561 562 func (c *StructCode) Filter(query *FieldQuery) Code { 563 fieldMap := map[string]*FieldQuery{} 564 for _, field := range query.Fields { 565 fieldMap[field.Name] = field 566 } 567 fields := make([]*StructFieldCode, 0, len(c.fields)) 568 for _, field := range c.fields { 569 query, exists := fieldMap[field.key] 570 if !exists { 571 continue 572 } 573 fieldCode := &StructFieldCode{ 574 typ: field.typ, 575 key: field.key, 576 tag: field.tag, 577 value: field.value, 578 offset: field.offset, 579 isAnonymous: field.isAnonymous, 580 isTaggedKey: field.isTaggedKey, 581 isNilableType: field.isNilableType, 582 isNilCheck: field.isNilCheck, 583 isAddrForMarshaler: field.isAddrForMarshaler, 584 isNextOpPtrType: field.isNextOpPtrType, 585 } 586 if len(query.Fields) > 0 { 587 fieldCode.value = fieldCode.value.Filter(query) 588 } 589 fields = append(fields, fieldCode) 590 } 591 return &StructCode{ 592 typ: c.typ, 593 fields: fields, 594 isPtr: c.isPtr, 595 disableIndirectConversion: c.disableIndirectConversion, 596 isIndirect: c.isIndirect, 597 isRecursive: c.isRecursive, 598 } 599 } 600 601 type StructFieldCode struct { 602 typ *runtime.Type 603 key string 604 tag *runtime.StructTag 605 value Code 606 offset uintptr 607 isAnonymous bool 608 isTaggedKey bool 609 isNilableType bool 610 isNilCheck bool 611 isAddrForMarshaler bool 612 isNextOpPtrType bool 613 isMarshalerContext bool 614 } 615 616 func (c *StructFieldCode) getStruct() *StructCode { 617 value := c.value 618 ptr, ok := value.(*PtrCode) 619 if ok { 620 value = ptr.value 621 } 622 structCode, ok := value.(*StructCode) 623 if ok { 624 return structCode 625 } 626 return nil 627 } 628 629 func (c *StructFieldCode) getAnonymousStruct() *StructCode { 630 if !c.isAnonymous { 631 return nil 632 } 633 return c.getStruct() 634 } 635 636 func optimizeStructHeader(code *Opcode, tag *runtime.StructTag) OpType { 637 headType := code.ToHeaderType(tag.IsString) 638 if tag.IsOmitEmpty { 639 headType = headType.HeadToOmitEmptyHead() 640 } 641 return headType 642 } 643 644 func optimizeStructField(code *Opcode, tag *runtime.StructTag) OpType { 645 fieldType := code.ToFieldType(tag.IsString) 646 if tag.IsOmitEmpty { 647 fieldType = fieldType.FieldToOmitEmptyField() 648 } 649 return fieldType 650 } 651 652 func (c *StructFieldCode) headerOpcodes(ctx *compileContext, field *Opcode, valueCodes Opcodes) Opcodes { 653 value := valueCodes.First() 654 op := optimizeStructHeader(value, c.tag) 655 field.Op = op 656 if value.Flags&MarshalerContextFlags != 0 { 657 field.Flags |= MarshalerContextFlags 658 } 659 field.NumBitSize = value.NumBitSize 660 field.PtrNum = value.PtrNum 661 field.FieldQuery = value.FieldQuery 662 fieldCodes := Opcodes{field} 663 if op.IsMultipleOpHead() { 664 field.Next = value 665 fieldCodes = fieldCodes.Add(valueCodes...) 666 } else { 667 ctx.decIndex() 668 } 669 return fieldCodes 670 } 671 672 func (c *StructFieldCode) fieldOpcodes(ctx *compileContext, field *Opcode, valueCodes Opcodes) Opcodes { 673 value := valueCodes.First() 674 op := optimizeStructField(value, c.tag) 675 field.Op = op 676 if value.Flags&MarshalerContextFlags != 0 { 677 field.Flags |= MarshalerContextFlags 678 } 679 field.NumBitSize = value.NumBitSize 680 field.PtrNum = value.PtrNum 681 field.FieldQuery = value.FieldQuery 682 683 fieldCodes := Opcodes{field} 684 if op.IsMultipleOpField() { 685 field.Next = value 686 fieldCodes = fieldCodes.Add(valueCodes...) 687 } else { 688 ctx.decIndex() 689 } 690 return fieldCodes 691 } 692 693 func (c *StructFieldCode) addStructEndCode(ctx *compileContext, codes Opcodes) Opcodes { 694 end := &Opcode{ 695 Op: OpStructEnd, 696 Idx: opcodeOffset(ctx.ptrIndex), 697 DisplayIdx: ctx.opcodeIndex, 698 Indent: ctx.indent, 699 } 700 codes.Last().Next = end 701 code := codes.First() 702 for code.Op == OpStructField || code.Op == OpStructHead { 703 code = code.Next 704 } 705 for code.NextField != nil { 706 code = code.NextField 707 } 708 code.NextField = end 709 710 codes = codes.Add(end) 711 ctx.incOpcodeIndex() 712 return codes 713 } 714 715 func (c *StructFieldCode) structKey(ctx *compileContext) string { 716 if ctx.escapeKey { 717 rctx := &RuntimeContext{Option: &Option{Flag: HTMLEscapeOption}} 718 return fmt.Sprintf(`%s:`, unsafeConvert.StringReflect(AppendString(rctx, []byte{}, c.key))) 719 } 720 return fmt.Sprintf(`"%s":`, c.key) 721 } 722 723 func (c *StructFieldCode) flags() OpFlags { 724 var flags OpFlags 725 if c.isTaggedKey { 726 flags |= IsTaggedKeyFlags 727 } 728 if c.isNilableType { 729 flags |= IsNilableTypeFlags 730 } 731 if c.isNilCheck { 732 flags |= NilCheckFlags 733 } 734 if c.isAddrForMarshaler { 735 flags |= AddrForMarshalerFlags 736 } 737 if c.isNextOpPtrType { 738 flags |= IsNextOpPtrTypeFlags 739 } 740 if c.isAnonymous { 741 flags |= AnonymousKeyFlags 742 } 743 if c.isMarshalerContext { 744 flags |= MarshalerContextFlags 745 } 746 return flags 747 } 748 749 func (c *StructFieldCode) toValueOpcodes(ctx *compileContext) Opcodes { 750 if c.isAnonymous { 751 anonymCode, ok := c.value.(AnonymousCode) 752 if ok { 753 return anonymCode.ToAnonymousOpcode(ctx) 754 } 755 } 756 return c.value.ToOpcode(ctx) 757 } 758 759 func (c *StructFieldCode) ToOpcode(ctx *compileContext, isFirstField, isEndField bool) Opcodes { 760 field := &Opcode{ 761 Idx: opcodeOffset(ctx.ptrIndex), 762 Flags: c.flags(), 763 Key: c.structKey(ctx), 764 Offset: uint32(c.offset), 765 Type: c.typ, 766 DisplayIdx: ctx.opcodeIndex, 767 Indent: ctx.indent, 768 DisplayKey: c.key, 769 } 770 ctx.incIndex() 771 valueCodes := c.toValueOpcodes(ctx) 772 if isFirstField { 773 codes := c.headerOpcodes(ctx, field, valueCodes) 774 if isEndField { 775 codes = c.addStructEndCode(ctx, codes) 776 } 777 return codes 778 } 779 codes := c.fieldOpcodes(ctx, field, valueCodes) 780 if isEndField { 781 if isEnableStructEndOptimization(c.value) { 782 field.Op = field.Op.FieldToEnd() 783 } else { 784 codes = c.addStructEndCode(ctx, codes) 785 } 786 } 787 return codes 788 } 789 790 func (c *StructFieldCode) ToAnonymousOpcode(ctx *compileContext, isFirstField, isEndField bool) Opcodes { 791 field := &Opcode{ 792 Idx: opcodeOffset(ctx.ptrIndex), 793 Flags: c.flags() | AnonymousHeadFlags, 794 Key: c.structKey(ctx), 795 Offset: uint32(c.offset), 796 Type: c.typ, 797 DisplayIdx: ctx.opcodeIndex, 798 Indent: ctx.indent, 799 DisplayKey: c.key, 800 } 801 ctx.incIndex() 802 valueCodes := c.toValueOpcodes(ctx) 803 if isFirstField { 804 return c.headerOpcodes(ctx, field, valueCodes) 805 } 806 return c.fieldOpcodes(ctx, field, valueCodes) 807 } 808 809 func isEnableStructEndOptimization(value Code) bool { 810 switch value.Kind() { 811 case CodeKindInt, 812 CodeKindUint, 813 CodeKindFloat, 814 CodeKindString, 815 CodeKindBool, 816 CodeKindBytes: 817 return true 818 case CodeKindPtr: 819 return isEnableStructEndOptimization(value.(*PtrCode).value) 820 default: 821 return false 822 } 823 } 824 825 type InterfaceCode struct { 826 typ *runtime.Type 827 fieldQuery *FieldQuery 828 isPtr bool 829 } 830 831 func (c *InterfaceCode) Kind() CodeKind { 832 return CodeKindInterface 833 } 834 835 func (c *InterfaceCode) ToOpcode(ctx *compileContext) Opcodes { 836 var code *Opcode 837 switch { 838 case c.isPtr: 839 code = newOpCode(ctx, c.typ, OpInterfacePtr) 840 default: 841 code = newOpCode(ctx, c.typ, OpInterface) 842 } 843 code.FieldQuery = c.fieldQuery 844 if c.typ.NumMethod() > 0 { 845 code.Flags |= NonEmptyInterfaceFlags 846 } 847 ctx.incIndex() 848 return Opcodes{code} 849 } 850 851 func (c *InterfaceCode) Filter(query *FieldQuery) Code { 852 return &InterfaceCode{ 853 typ: c.typ, 854 fieldQuery: query, 855 isPtr: c.isPtr, 856 } 857 } 858 859 type MarshalJSONCode struct { 860 typ *runtime.Type 861 fieldQuery *FieldQuery 862 isAddrForMarshaler bool 863 isNilableType bool 864 isMarshalerContext bool 865 } 866 867 func (c *MarshalJSONCode) Kind() CodeKind { 868 return CodeKindMarshalJSON 869 } 870 871 func (c *MarshalJSONCode) ToOpcode(ctx *compileContext) Opcodes { 872 code := newOpCode(ctx, c.typ, OpMarshalJSON) 873 code.FieldQuery = c.fieldQuery 874 if c.isAddrForMarshaler { 875 code.Flags |= AddrForMarshalerFlags 876 } 877 if c.isMarshalerContext { 878 code.Flags |= MarshalerContextFlags 879 } 880 if c.isNilableType { 881 code.Flags |= IsNilableTypeFlags 882 } else { 883 code.Flags &= ^IsNilableTypeFlags 884 } 885 ctx.incIndex() 886 return Opcodes{code} 887 } 888 889 func (c *MarshalJSONCode) Filter(query *FieldQuery) Code { 890 return &MarshalJSONCode{ 891 typ: c.typ, 892 fieldQuery: query, 893 isAddrForMarshaler: c.isAddrForMarshaler, 894 isNilableType: c.isNilableType, 895 isMarshalerContext: c.isMarshalerContext, 896 } 897 } 898 899 type MarshalTextCode struct { 900 typ *runtime.Type 901 fieldQuery *FieldQuery 902 isAddrForMarshaler bool 903 isNilableType bool 904 } 905 906 func (c *MarshalTextCode) Kind() CodeKind { 907 return CodeKindMarshalText 908 } 909 910 func (c *MarshalTextCode) ToOpcode(ctx *compileContext) Opcodes { 911 code := newOpCode(ctx, c.typ, OpMarshalText) 912 code.FieldQuery = c.fieldQuery 913 if c.isAddrForMarshaler { 914 code.Flags |= AddrForMarshalerFlags 915 } 916 if c.isNilableType { 917 code.Flags |= IsNilableTypeFlags 918 } else { 919 code.Flags &= ^IsNilableTypeFlags 920 } 921 ctx.incIndex() 922 return Opcodes{code} 923 } 924 925 func (c *MarshalTextCode) Filter(query *FieldQuery) Code { 926 return &MarshalTextCode{ 927 typ: c.typ, 928 fieldQuery: query, 929 isAddrForMarshaler: c.isAddrForMarshaler, 930 isNilableType: c.isNilableType, 931 } 932 } 933 934 type PtrCode struct { 935 typ *runtime.Type 936 value Code 937 ptrNum uint8 938 } 939 940 func (c *PtrCode) Kind() CodeKind { 941 return CodeKindPtr 942 } 943 944 func (c *PtrCode) ToOpcode(ctx *compileContext) Opcodes { 945 codes := c.value.ToOpcode(ctx) 946 codes.First().Op = convertPtrOp(codes.First()) 947 codes.First().PtrNum = c.ptrNum 948 return codes 949 } 950 951 func (c *PtrCode) ToAnonymousOpcode(ctx *compileContext) Opcodes { 952 var codes Opcodes 953 anonymCode, ok := c.value.(AnonymousCode) 954 if ok { 955 codes = anonymCode.ToAnonymousOpcode(ctx) 956 } else { 957 codes = c.value.ToOpcode(ctx) 958 } 959 codes.First().Op = convertPtrOp(codes.First()) 960 codes.First().PtrNum = c.ptrNum 961 return codes 962 } 963 964 func (c *PtrCode) Filter(query *FieldQuery) Code { 965 return &PtrCode{ 966 typ: c.typ, 967 value: c.value.Filter(query), 968 ptrNum: c.ptrNum, 969 } 970 } 971 972 func convertPtrOp(code *Opcode) OpType { 973 ptrHeadOp := code.Op.HeadToPtrHead() 974 if code.Op != ptrHeadOp { 975 if code.PtrNum > 0 { 976 // ptr field and ptr head 977 code.PtrNum-- 978 } 979 return ptrHeadOp 980 } 981 switch code.Op { 982 case OpInt: 983 return OpIntPtr 984 case OpUint: 985 return OpUintPtr 986 case OpFloat32: 987 return OpFloat32Ptr 988 case OpFloat64: 989 return OpFloat64Ptr 990 case OpString: 991 return OpStringPtr 992 case OpBool: 993 return OpBoolPtr 994 case OpBytes: 995 return OpBytesPtr 996 case OpNumber: 997 return OpNumberPtr 998 case OpArray: 999 return OpArrayPtr 1000 case OpSlice: 1001 return OpSlicePtr 1002 case OpMap: 1003 return OpMapPtr 1004 case OpMarshalJSON: 1005 return OpMarshalJSONPtr 1006 case OpMarshalText: 1007 return OpMarshalTextPtr 1008 case OpInterface: 1009 return OpInterfacePtr 1010 case OpRecursive: 1011 return OpRecursivePtr 1012 } 1013 return code.Op 1014 } 1015 1016 func isEmbeddedStruct(field *StructFieldCode) bool { 1017 if !field.isAnonymous { 1018 return false 1019 } 1020 t := field.typ 1021 if t.Kind() == reflect.Ptr { 1022 t = t.Elem() 1023 } 1024 return t.Kind() == reflect.Struct 1025 }