github.com/night-codes/go-json@v0.9.15/internal/encoder/code.go (about) 1 package encoder 2 3 import ( 4 "fmt" 5 "reflect" 6 "unsafe" 7 8 "github.com/night-codes/go-json/internal/runtime" 9 ) 10 11 type Code interface { 12 Kind() CodeKind 13 ToOpcode(*compileContext) Opcodes 14 Filter(*FieldQuery) Code 15 } 16 17 type AnonymousCode interface { 18 ToAnonymousOpcode(*compileContext) Opcodes 19 } 20 21 type Opcodes []*Opcode 22 23 func (o Opcodes) First() *Opcode { 24 if len(o) == 0 { 25 return nil 26 } 27 return o[0] 28 } 29 30 func (o Opcodes) Last() *Opcode { 31 if len(o) == 0 { 32 return nil 33 } 34 return o[len(o)-1] 35 } 36 37 func (o Opcodes) Add(codes ...*Opcode) Opcodes { 38 return append(o, codes...) 39 } 40 41 type CodeKind int 42 43 const ( 44 CodeKindInterface CodeKind = iota 45 CodeKindPtr 46 CodeKindInt 47 CodeKindUint 48 CodeKindFloat 49 CodeKindString 50 CodeKindBool 51 CodeKindStruct 52 CodeKindMap 53 CodeKindSlice 54 CodeKindArray 55 CodeKindBytes 56 CodeKindMarshalJSON 57 CodeKindMarshalText 58 CodeKindRecursive 59 ) 60 61 type IntCode struct { 62 typ *runtime.Type 63 bitSize uint8 64 isString bool 65 isPtr bool 66 } 67 68 func (c *IntCode) Kind() CodeKind { 69 return CodeKindInt 70 } 71 72 func (c *IntCode) ToOpcode(ctx *compileContext) Opcodes { 73 var code *Opcode 74 switch { 75 case c.isPtr: 76 code = newOpCode(ctx, c.typ, OpIntPtr) 77 case c.isString: 78 code = newOpCode(ctx, c.typ, OpIntString) 79 default: 80 code = newOpCode(ctx, c.typ, OpInt) 81 } 82 code.NumBitSize = c.bitSize 83 ctx.incIndex() 84 return Opcodes{code} 85 } 86 87 func (c *IntCode) Filter(_ *FieldQuery) Code { 88 return c 89 } 90 91 type UintCode struct { 92 typ *runtime.Type 93 bitSize uint8 94 isString bool 95 isPtr bool 96 } 97 98 func (c *UintCode) Kind() CodeKind { 99 return CodeKindUint 100 } 101 102 func (c *UintCode) ToOpcode(ctx *compileContext) Opcodes { 103 var code *Opcode 104 switch { 105 case c.isPtr: 106 code = newOpCode(ctx, c.typ, OpUintPtr) 107 case c.isString: 108 code = newOpCode(ctx, c.typ, OpUintString) 109 default: 110 code = newOpCode(ctx, c.typ, OpUint) 111 } 112 code.NumBitSize = c.bitSize 113 ctx.incIndex() 114 return Opcodes{code} 115 } 116 117 func (c *UintCode) Filter(_ *FieldQuery) Code { 118 return c 119 } 120 121 type FloatCode struct { 122 typ *runtime.Type 123 bitSize uint8 124 isPtr bool 125 } 126 127 func (c *FloatCode) Kind() CodeKind { 128 return CodeKindFloat 129 } 130 131 func (c *FloatCode) ToOpcode(ctx *compileContext) Opcodes { 132 var code *Opcode 133 switch { 134 case c.isPtr: 135 switch c.bitSize { 136 case 32: 137 code = newOpCode(ctx, c.typ, OpFloat32Ptr) 138 default: 139 code = newOpCode(ctx, c.typ, OpFloat64Ptr) 140 } 141 default: 142 switch c.bitSize { 143 case 32: 144 code = newOpCode(ctx, c.typ, OpFloat32) 145 default: 146 code = newOpCode(ctx, c.typ, OpFloat64) 147 } 148 } 149 ctx.incIndex() 150 return Opcodes{code} 151 } 152 153 func (c *FloatCode) Filter(_ *FieldQuery) Code { 154 return c 155 } 156 157 type StringCode struct { 158 typ *runtime.Type 159 isPtr bool 160 } 161 162 func (c *StringCode) Kind() CodeKind { 163 return CodeKindString 164 } 165 166 func (c *StringCode) ToOpcode(ctx *compileContext) Opcodes { 167 isJSONNumberType := c.typ == runtime.Type2RType(jsonNumberType) 168 var code *Opcode 169 if c.isPtr { 170 if isJSONNumberType { 171 code = newOpCode(ctx, c.typ, OpNumberPtr) 172 } else { 173 code = newOpCode(ctx, c.typ, OpStringPtr) 174 } 175 } else { 176 if isJSONNumberType { 177 code = newOpCode(ctx, c.typ, OpNumber) 178 } else { 179 code = newOpCode(ctx, c.typ, OpString) 180 } 181 } 182 ctx.incIndex() 183 return Opcodes{code} 184 } 185 186 func (c *StringCode) Filter(_ *FieldQuery) Code { 187 return c 188 } 189 190 type BoolCode struct { 191 typ *runtime.Type 192 isPtr bool 193 } 194 195 func (c *BoolCode) Kind() CodeKind { 196 return CodeKindBool 197 } 198 199 func (c *BoolCode) ToOpcode(ctx *compileContext) Opcodes { 200 var code *Opcode 201 switch { 202 case c.isPtr: 203 code = newOpCode(ctx, c.typ, OpBoolPtr) 204 default: 205 code = newOpCode(ctx, c.typ, OpBool) 206 } 207 ctx.incIndex() 208 return Opcodes{code} 209 } 210 211 func (c *BoolCode) Filter(_ *FieldQuery) Code { 212 return c 213 } 214 215 type BytesCode struct { 216 typ *runtime.Type 217 isPtr bool 218 } 219 220 func (c *BytesCode) Kind() CodeKind { 221 return CodeKindBytes 222 } 223 224 func (c *BytesCode) ToOpcode(ctx *compileContext) Opcodes { 225 var code *Opcode 226 switch { 227 case c.isPtr: 228 code = newOpCode(ctx, c.typ, OpBytesPtr) 229 default: 230 code = newOpCode(ctx, c.typ, OpBytes) 231 } 232 ctx.incIndex() 233 return Opcodes{code} 234 } 235 236 func (c *BytesCode) Filter(_ *FieldQuery) Code { 237 return c 238 } 239 240 type SliceCode struct { 241 typ *runtime.Type 242 value Code 243 } 244 245 func (c *SliceCode) Kind() CodeKind { 246 return CodeKindSlice 247 } 248 249 func (c *SliceCode) ToOpcode(ctx *compileContext) Opcodes { 250 // header => opcode => elem => end 251 // ^ | 252 // |________| 253 size := c.typ.Elem().Size() 254 header := newSliceHeaderCode(ctx, c.typ) 255 ctx.incIndex() 256 257 ctx.incIndent() 258 codes := c.value.ToOpcode(ctx) 259 ctx.decIndent() 260 261 codes.First().Flags |= IndirectFlags 262 elemCode := newSliceElemCode(ctx, c.typ.Elem(), header, size) 263 ctx.incIndex() 264 end := newOpCode(ctx, c.typ, OpSliceEnd) 265 ctx.incIndex() 266 header.End = end 267 header.Next = codes.First() 268 codes.Last().Next = elemCode 269 elemCode.Next = codes.First() 270 elemCode.End = end 271 return Opcodes{header}.Add(codes...).Add(elemCode).Add(end) 272 } 273 274 func (c *SliceCode) Filter(_ *FieldQuery) Code { 275 return c 276 } 277 278 type ArrayCode struct { 279 typ *runtime.Type 280 value Code 281 } 282 283 func (c *ArrayCode) Kind() CodeKind { 284 return CodeKindArray 285 } 286 287 func (c *ArrayCode) ToOpcode(ctx *compileContext) Opcodes { 288 // header => opcode => elem => end 289 // ^ | 290 // |________| 291 elem := c.typ.Elem() 292 alen := c.typ.Len() 293 size := elem.Size() 294 295 header := newArrayHeaderCode(ctx, c.typ, alen) 296 ctx.incIndex() 297 298 ctx.incIndent() 299 codes := c.value.ToOpcode(ctx) 300 ctx.decIndent() 301 302 codes.First().Flags |= IndirectFlags 303 304 elemCode := newArrayElemCode(ctx, elem, header, alen, size) 305 ctx.incIndex() 306 307 end := newOpCode(ctx, c.typ, OpArrayEnd) 308 ctx.incIndex() 309 310 header.End = end 311 header.Next = codes.First() 312 codes.Last().Next = elemCode 313 elemCode.Next = codes.First() 314 elemCode.End = end 315 316 return Opcodes{header}.Add(codes...).Add(elemCode).Add(end) 317 } 318 319 func (c *ArrayCode) Filter(_ *FieldQuery) Code { 320 return c 321 } 322 323 type MapCode struct { 324 typ *runtime.Type 325 key Code 326 value Code 327 } 328 329 func (c *MapCode) Kind() CodeKind { 330 return CodeKindMap 331 } 332 333 func (c *MapCode) ToOpcode(ctx *compileContext) Opcodes { 334 // header => code => value => code => key => code => value => code => end 335 // ^ | 336 // |_______________________| 337 header := newMapHeaderCode(ctx, c.typ) 338 ctx.incIndex() 339 340 keyCodes := c.key.ToOpcode(ctx) 341 342 value := newMapValueCode(ctx, c.typ.Elem(), header) 343 ctx.incIndex() 344 345 ctx.incIndent() 346 valueCodes := c.value.ToOpcode(ctx) 347 ctx.decIndent() 348 349 valueCodes.First().Flags |= IndirectFlags 350 351 key := newMapKeyCode(ctx, c.typ.Key(), header) 352 ctx.incIndex() 353 354 end := newMapEndCode(ctx, c.typ, header) 355 ctx.incIndex() 356 357 header.Next = keyCodes.First() 358 keyCodes.Last().Next = value 359 value.Next = valueCodes.First() 360 valueCodes.Last().Next = key 361 key.Next = keyCodes.First() 362 363 header.End = end 364 key.End = end 365 value.End = end 366 return Opcodes{header}.Add(keyCodes...).Add(value).Add(valueCodes...).Add(key).Add(end) 367 } 368 369 func (c *MapCode) Filter(_ *FieldQuery) Code { 370 return c 371 } 372 373 type StructCode struct { 374 typ *runtime.Type 375 fields []*StructFieldCode 376 isPtr bool 377 disableIndirectConversion bool 378 isIndirect bool 379 isRecursive bool 380 } 381 382 func (c *StructCode) Kind() CodeKind { 383 return CodeKindStruct 384 } 385 386 func (c *StructCode) lastFieldCode(field *StructFieldCode, firstField *Opcode) *Opcode { 387 if isEmbeddedStruct(field) { 388 return c.lastAnonymousFieldCode(firstField) 389 } 390 lastField := firstField 391 for lastField.NextField != nil { 392 lastField = lastField.NextField 393 } 394 return lastField 395 } 396 397 func (c *StructCode) lastAnonymousFieldCode(firstField *Opcode) *Opcode { 398 // firstField is special StructHead operation for anonymous structure. 399 // So, StructHead's next operation is truly struct head operation. 400 lastField := firstField.Next 401 for lastField.NextField != nil { 402 lastField = lastField.NextField 403 } 404 return lastField 405 } 406 407 func (c *StructCode) ToOpcode(ctx *compileContext) Opcodes { 408 // header => code => structField => code => end 409 // ^ | 410 // |__________| 411 if c.isRecursive { 412 recursive := newRecursiveCode(ctx, c.typ, &CompiledCode{}) 413 recursive.Type = c.typ 414 ctx.incIndex() 415 *ctx.recursiveCodes = append(*ctx.recursiveCodes, recursive) 416 return Opcodes{recursive} 417 } 418 codes := Opcodes{} 419 var prevField *Opcode 420 ctx.incIndent() 421 for idx, field := range c.fields { 422 isFirstField := idx == 0 423 isEndField := idx == len(c.fields)-1 424 fieldCodes := field.ToOpcode(ctx, isFirstField, isEndField) 425 for _, code := range fieldCodes { 426 if c.isIndirect { 427 code.Flags |= IndirectFlags 428 } 429 } 430 firstField := fieldCodes.First() 431 if len(codes) > 0 { 432 codes.Last().Next = firstField 433 firstField.Idx = codes.First().Idx 434 } 435 if prevField != nil { 436 prevField.NextField = firstField 437 } 438 if isEndField { 439 endField := fieldCodes.Last() 440 if isEmbeddedStruct(field) { 441 firstField.End = endField 442 lastField := c.lastAnonymousFieldCode(firstField) 443 lastField.NextField = endField 444 } 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 codes.First().NextField = end 702 codes = codes.Add(end) 703 ctx.incOpcodeIndex() 704 return codes 705 } 706 707 func (c *StructFieldCode) structKey(ctx *compileContext) string { 708 if ctx.escapeKey { 709 rctx := &RuntimeContext{Option: &Option{Flag: HTMLEscapeOption}} 710 return fmt.Sprintf(`%s:`, string(AppendString(rctx, []byte{}, c.key))) 711 } 712 return fmt.Sprintf(`"%s":`, c.key) 713 } 714 715 func (c *StructFieldCode) flags() OpFlags { 716 var flags OpFlags 717 if c.isTaggedKey { 718 flags |= IsTaggedKeyFlags 719 } 720 if c.isNilableType { 721 flags |= IsNilableTypeFlags 722 } 723 if c.isNilCheck { 724 flags |= NilCheckFlags 725 } 726 if c.isAddrForMarshaler { 727 flags |= AddrForMarshalerFlags 728 } 729 if c.isNextOpPtrType { 730 flags |= IsNextOpPtrTypeFlags 731 } 732 if c.isAnonymous { 733 flags |= AnonymousKeyFlags 734 } 735 if c.isMarshalerContext { 736 flags |= MarshalerContextFlags 737 } 738 return flags 739 } 740 741 func (c *StructFieldCode) toValueOpcodes(ctx *compileContext) Opcodes { 742 if c.isAnonymous { 743 anonymCode, ok := c.value.(AnonymousCode) 744 if ok { 745 return anonymCode.ToAnonymousOpcode(ctx) 746 } 747 } 748 return c.value.ToOpcode(ctx) 749 } 750 751 func (c *StructFieldCode) ToOpcode(ctx *compileContext, isFirstField, isEndField bool) Opcodes { 752 field := &Opcode{ 753 Idx: opcodeOffset(ctx.ptrIndex), 754 Flags: c.flags(), 755 Key: c.structKey(ctx), 756 Offset: uint32(c.offset), 757 Type: c.typ, 758 DisplayIdx: ctx.opcodeIndex, 759 Indent: ctx.indent, 760 DisplayKey: c.key, 761 } 762 ctx.incIndex() 763 valueCodes := c.toValueOpcodes(ctx) 764 if isFirstField { 765 codes := c.headerOpcodes(ctx, field, valueCodes) 766 if isEndField { 767 codes = c.addStructEndCode(ctx, codes) 768 } 769 return codes 770 } 771 codes := c.fieldOpcodes(ctx, field, valueCodes) 772 if isEndField { 773 if isEnableStructEndOptimization(c.value) { 774 field.Op = field.Op.FieldToEnd() 775 } else { 776 codes = c.addStructEndCode(ctx, codes) 777 } 778 } 779 return codes 780 } 781 782 func (c *StructFieldCode) ToAnonymousOpcode(ctx *compileContext, isFirstField, isEndField bool) Opcodes { 783 field := &Opcode{ 784 Idx: opcodeOffset(ctx.ptrIndex), 785 Flags: c.flags() | AnonymousHeadFlags, 786 Key: c.structKey(ctx), 787 Offset: uint32(c.offset), 788 Type: c.typ, 789 DisplayIdx: ctx.opcodeIndex, 790 Indent: ctx.indent, 791 DisplayKey: c.key, 792 } 793 ctx.incIndex() 794 valueCodes := c.toValueOpcodes(ctx) 795 if isFirstField { 796 return c.headerOpcodes(ctx, field, valueCodes) 797 } 798 return c.fieldOpcodes(ctx, field, valueCodes) 799 } 800 801 func isEnableStructEndOptimization(value Code) bool { 802 switch value.Kind() { 803 case CodeKindInt, 804 CodeKindUint, 805 CodeKindFloat, 806 CodeKindString, 807 CodeKindBool, 808 CodeKindBytes: 809 return true 810 case CodeKindPtr: 811 return isEnableStructEndOptimization(value.(*PtrCode).value) 812 default: 813 return false 814 } 815 } 816 817 type InterfaceCode struct { 818 typ *runtime.Type 819 fieldQuery *FieldQuery 820 isPtr bool 821 } 822 823 func (c *InterfaceCode) Kind() CodeKind { 824 return CodeKindInterface 825 } 826 827 func (c *InterfaceCode) ToOpcode(ctx *compileContext) Opcodes { 828 var code *Opcode 829 switch { 830 case c.isPtr: 831 code = newOpCode(ctx, c.typ, OpInterfacePtr) 832 default: 833 code = newOpCode(ctx, c.typ, OpInterface) 834 } 835 code.FieldQuery = c.fieldQuery 836 if c.typ.NumMethod() > 0 { 837 code.Flags |= NonEmptyInterfaceFlags 838 } 839 ctx.incIndex() 840 return Opcodes{code} 841 } 842 843 func (c *InterfaceCode) Filter(query *FieldQuery) Code { 844 return &InterfaceCode{ 845 typ: c.typ, 846 fieldQuery: query, 847 isPtr: c.isPtr, 848 } 849 } 850 851 type MarshalJSONCode struct { 852 typ *runtime.Type 853 fieldQuery *FieldQuery 854 isAddrForMarshaler bool 855 isNilableType bool 856 isMarshalerContext bool 857 } 858 859 func (c *MarshalJSONCode) Kind() CodeKind { 860 return CodeKindMarshalJSON 861 } 862 863 func (c *MarshalJSONCode) ToOpcode(ctx *compileContext) Opcodes { 864 code := newOpCode(ctx, c.typ, OpMarshalJSON) 865 code.FieldQuery = c.fieldQuery 866 if c.isAddrForMarshaler { 867 code.Flags |= AddrForMarshalerFlags 868 } 869 if c.isMarshalerContext { 870 code.Flags |= MarshalerContextFlags 871 } 872 if c.isNilableType { 873 code.Flags |= IsNilableTypeFlags 874 } else { 875 code.Flags &= ^IsNilableTypeFlags 876 } 877 ctx.incIndex() 878 return Opcodes{code} 879 } 880 881 func (c *MarshalJSONCode) Filter(query *FieldQuery) Code { 882 return &MarshalJSONCode{ 883 typ: c.typ, 884 fieldQuery: query, 885 isAddrForMarshaler: c.isAddrForMarshaler, 886 isNilableType: c.isNilableType, 887 isMarshalerContext: c.isMarshalerContext, 888 } 889 } 890 891 type MarshalTextCode struct { 892 typ *runtime.Type 893 fieldQuery *FieldQuery 894 isAddrForMarshaler bool 895 isNilableType bool 896 } 897 898 func (c *MarshalTextCode) Kind() CodeKind { 899 return CodeKindMarshalText 900 } 901 902 func (c *MarshalTextCode) ToOpcode(ctx *compileContext) Opcodes { 903 code := newOpCode(ctx, c.typ, OpMarshalText) 904 code.FieldQuery = c.fieldQuery 905 if c.isAddrForMarshaler { 906 code.Flags |= AddrForMarshalerFlags 907 } 908 if c.isNilableType { 909 code.Flags |= IsNilableTypeFlags 910 } else { 911 code.Flags &= ^IsNilableTypeFlags 912 } 913 ctx.incIndex() 914 return Opcodes{code} 915 } 916 917 func (c *MarshalTextCode) Filter(query *FieldQuery) Code { 918 return &MarshalTextCode{ 919 typ: c.typ, 920 fieldQuery: query, 921 isAddrForMarshaler: c.isAddrForMarshaler, 922 isNilableType: c.isNilableType, 923 } 924 } 925 926 type PtrCode struct { 927 typ *runtime.Type 928 value Code 929 ptrNum uint8 930 } 931 932 func (c *PtrCode) Kind() CodeKind { 933 return CodeKindPtr 934 } 935 936 func (c *PtrCode) ToOpcode(ctx *compileContext) Opcodes { 937 codes := c.value.ToOpcode(ctx) 938 codes.First().Op = convertPtrOp(codes.First()) 939 codes.First().PtrNum = c.ptrNum 940 return codes 941 } 942 943 func (c *PtrCode) ToAnonymousOpcode(ctx *compileContext) Opcodes { 944 var codes Opcodes 945 anonymCode, ok := c.value.(AnonymousCode) 946 if ok { 947 codes = anonymCode.ToAnonymousOpcode(ctx) 948 } else { 949 codes = c.value.ToOpcode(ctx) 950 } 951 codes.First().Op = convertPtrOp(codes.First()) 952 codes.First().PtrNum = c.ptrNum 953 return codes 954 } 955 956 func (c *PtrCode) Filter(query *FieldQuery) Code { 957 return &PtrCode{ 958 typ: c.typ, 959 value: c.value.Filter(query), 960 ptrNum: c.ptrNum, 961 } 962 } 963 964 func convertPtrOp(code *Opcode) OpType { 965 ptrHeadOp := code.Op.HeadToPtrHead() 966 if code.Op != ptrHeadOp { 967 if code.PtrNum > 0 { 968 // ptr field and ptr head 969 code.PtrNum-- 970 } 971 return ptrHeadOp 972 } 973 switch code.Op { 974 case OpInt: 975 return OpIntPtr 976 case OpUint: 977 return OpUintPtr 978 case OpFloat32: 979 return OpFloat32Ptr 980 case OpFloat64: 981 return OpFloat64Ptr 982 case OpString: 983 return OpStringPtr 984 case OpBool: 985 return OpBoolPtr 986 case OpBytes: 987 return OpBytesPtr 988 case OpNumber: 989 return OpNumberPtr 990 case OpArray: 991 return OpArrayPtr 992 case OpSlice: 993 return OpSlicePtr 994 case OpMap: 995 return OpMapPtr 996 case OpMarshalJSON: 997 return OpMarshalJSONPtr 998 case OpMarshalText: 999 return OpMarshalTextPtr 1000 case OpInterface: 1001 return OpInterfacePtr 1002 case OpRecursive: 1003 return OpRecursivePtr 1004 } 1005 return code.Op 1006 } 1007 1008 func isEmbeddedStruct(field *StructFieldCode) bool { 1009 if !field.isAnonymous { 1010 return false 1011 } 1012 t := field.typ 1013 if t.Kind() == reflect.Ptr { 1014 t = t.Elem() 1015 } 1016 return t.Kind() == reflect.Struct 1017 }