github.com/grbit/go-json@v0.11.0/internal/encoder/code.go (about) 1 package encoder 2 3 import ( 4 "fmt" 5 "reflect" 6 "unsafe" 7 8 "github.com/grbit/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 for firstField.Op == OpStructHead || firstField.Op == OpStructField { 401 firstField = firstField.Next 402 } 403 lastField := firstField 404 for lastField.NextField != nil { 405 lastField = lastField.NextField 406 } 407 return lastField 408 } 409 410 func (c *StructCode) ToOpcode(ctx *compileContext) Opcodes { 411 // header => code => structField => code => end 412 // ^ | 413 // |__________| 414 if c.isRecursive { 415 recursive := newRecursiveCode(ctx, c.typ, &CompiledCode{}) 416 recursive.Type = c.typ 417 ctx.incIndex() 418 *ctx.recursiveCodes = append(*ctx.recursiveCodes, recursive) 419 return Opcodes{recursive} 420 } 421 codes := Opcodes{} 422 var prevField *Opcode 423 ctx.incIndent() 424 for idx, field := range c.fields { 425 isFirstField := idx == 0 426 isEndField := idx == len(c.fields)-1 427 fieldCodes := field.ToOpcode(ctx, isFirstField, isEndField) 428 for _, code := range fieldCodes { 429 if c.isIndirect { 430 code.Flags |= IndirectFlags 431 } 432 } 433 firstField := fieldCodes.First() 434 if len(codes) > 0 { 435 codes.Last().Next = firstField 436 firstField.Idx = codes.First().Idx 437 } 438 if prevField != nil { 439 prevField.NextField = firstField 440 } 441 if isEndField { 442 endField := fieldCodes.Last() 443 if len(codes) > 0 { 444 codes.First().End = endField 445 } else { 446 firstField.End = endField 447 } 448 codes = codes.Add(fieldCodes...) 449 break 450 } 451 prevField = c.lastFieldCode(field, firstField) 452 codes = codes.Add(fieldCodes...) 453 } 454 if len(codes) == 0 { 455 head := &Opcode{ 456 Op: OpStructHead, 457 Idx: opcodeOffset(ctx.ptrIndex), 458 Type: c.typ, 459 DisplayIdx: ctx.opcodeIndex, 460 Indent: ctx.indent, 461 } 462 ctx.incOpcodeIndex() 463 end := &Opcode{ 464 Op: OpStructEnd, 465 Idx: opcodeOffset(ctx.ptrIndex), 466 DisplayIdx: ctx.opcodeIndex, 467 Indent: ctx.indent, 468 } 469 head.NextField = end 470 head.Next = end 471 head.End = end 472 codes = codes.Add(head, end) 473 ctx.incIndex() 474 } 475 ctx.decIndent() 476 ctx.structTypeToCodes[uintptr(unsafe.Pointer(c.typ))] = codes 477 return codes 478 } 479 480 func (c *StructCode) ToAnonymousOpcode(ctx *compileContext) Opcodes { 481 // header => code => structField => code => end 482 // ^ | 483 // |__________| 484 if c.isRecursive { 485 recursive := newRecursiveCode(ctx, c.typ, &CompiledCode{}) 486 recursive.Type = c.typ 487 ctx.incIndex() 488 *ctx.recursiveCodes = append(*ctx.recursiveCodes, recursive) 489 return Opcodes{recursive} 490 } 491 codes := Opcodes{} 492 var prevField *Opcode 493 for idx, field := range c.fields { 494 isFirstField := idx == 0 495 isEndField := idx == len(c.fields)-1 496 fieldCodes := field.ToAnonymousOpcode(ctx, isFirstField, isEndField) 497 for _, code := range fieldCodes { 498 if c.isIndirect { 499 code.Flags |= IndirectFlags 500 } 501 } 502 firstField := fieldCodes.First() 503 if len(codes) > 0 { 504 codes.Last().Next = firstField 505 firstField.Idx = codes.First().Idx 506 } 507 if prevField != nil { 508 prevField.NextField = firstField 509 } 510 if isEndField { 511 lastField := fieldCodes.Last() 512 if len(codes) > 0 { 513 codes.First().End = lastField 514 } else { 515 firstField.End = lastField 516 } 517 } 518 prevField = firstField 519 codes = codes.Add(fieldCodes...) 520 } 521 return codes 522 } 523 524 func (c *StructCode) removeFieldsByTags(tags runtime.StructTags) { 525 fields := make([]*StructFieldCode, 0, len(c.fields)) 526 for _, field := range c.fields { 527 if field.isAnonymous { 528 structCode := field.getAnonymousStruct() 529 if structCode != nil && !structCode.isRecursive { 530 structCode.removeFieldsByTags(tags) 531 if len(structCode.fields) > 0 { 532 fields = append(fields, field) 533 } 534 continue 535 } 536 } 537 if tags.ExistsKey(field.key) { 538 continue 539 } 540 fields = append(fields, field) 541 } 542 c.fields = fields 543 } 544 545 func (c *StructCode) enableIndirect() { 546 if c.isIndirect { 547 return 548 } 549 c.isIndirect = true 550 if len(c.fields) == 0 { 551 return 552 } 553 structCode := c.fields[0].getStruct() 554 if structCode == nil { 555 return 556 } 557 structCode.enableIndirect() 558 } 559 560 func (c *StructCode) Filter(query *FieldQuery) Code { 561 fieldMap := map[string]*FieldQuery{} 562 for _, field := range query.Fields { 563 fieldMap[field.Name] = field 564 } 565 fields := make([]*StructFieldCode, 0, len(c.fields)) 566 for _, field := range c.fields { 567 query, exists := fieldMap[field.key] 568 if !exists { 569 continue 570 } 571 fieldCode := &StructFieldCode{ 572 typ: field.typ, 573 key: field.key, 574 tag: field.tag, 575 value: field.value, 576 offset: field.offset, 577 isAnonymous: field.isAnonymous, 578 isTaggedKey: field.isTaggedKey, 579 isNilableType: field.isNilableType, 580 isNilCheck: field.isNilCheck, 581 isAddrForMarshaler: field.isAddrForMarshaler, 582 isNextOpPtrType: field.isNextOpPtrType, 583 } 584 if len(query.Fields) > 0 { 585 fieldCode.value = fieldCode.value.Filter(query) 586 } 587 fields = append(fields, fieldCode) 588 } 589 return &StructCode{ 590 typ: c.typ, 591 fields: fields, 592 isPtr: c.isPtr, 593 disableIndirectConversion: c.disableIndirectConversion, 594 isIndirect: c.isIndirect, 595 isRecursive: c.isRecursive, 596 } 597 } 598 599 type StructFieldCode struct { 600 typ *runtime.Type 601 key string 602 tag *runtime.StructTag 603 value Code 604 offset uintptr 605 isAnonymous bool 606 isTaggedKey bool 607 isNilableType bool 608 isNilCheck bool 609 isAddrForMarshaler bool 610 isNextOpPtrType bool 611 isMarshalerContext bool 612 } 613 614 func (c *StructFieldCode) getStruct() *StructCode { 615 value := c.value 616 ptr, ok := value.(*PtrCode) 617 if ok { 618 value = ptr.value 619 } 620 structCode, ok := value.(*StructCode) 621 if ok { 622 return structCode 623 } 624 return nil 625 } 626 627 func (c *StructFieldCode) getAnonymousStruct() *StructCode { 628 if !c.isAnonymous { 629 return nil 630 } 631 return c.getStruct() 632 } 633 634 func optimizeStructHeader(code *Opcode, tag *runtime.StructTag) OpType { 635 headType := code.ToHeaderType(tag.IsString) 636 if tag.IsOmitEmpty { 637 headType = headType.HeadToOmitEmptyHead() 638 } 639 return headType 640 } 641 642 func optimizeStructField(code *Opcode, tag *runtime.StructTag) OpType { 643 fieldType := code.ToFieldType(tag.IsString) 644 if tag.IsOmitEmpty { 645 fieldType = fieldType.FieldToOmitEmptyField() 646 } 647 return fieldType 648 } 649 650 func (c *StructFieldCode) headerOpcodes(ctx *compileContext, field *Opcode, valueCodes Opcodes) Opcodes { 651 value := valueCodes.First() 652 op := optimizeStructHeader(value, c.tag) 653 field.Op = op 654 if value.Flags&MarshalerContextFlags != 0 { 655 field.Flags |= MarshalerContextFlags 656 } 657 field.NumBitSize = value.NumBitSize 658 field.PtrNum = value.PtrNum 659 field.FieldQuery = value.FieldQuery 660 fieldCodes := Opcodes{field} 661 if op.IsMultipleOpHead() { 662 field.Next = value 663 fieldCodes = fieldCodes.Add(valueCodes...) 664 } else { 665 ctx.decIndex() 666 } 667 return fieldCodes 668 } 669 670 func (c *StructFieldCode) fieldOpcodes(ctx *compileContext, field *Opcode, valueCodes Opcodes) Opcodes { 671 value := valueCodes.First() 672 op := optimizeStructField(value, c.tag) 673 field.Op = op 674 if value.Flags&MarshalerContextFlags != 0 { 675 field.Flags |= MarshalerContextFlags 676 } 677 field.NumBitSize = value.NumBitSize 678 field.PtrNum = value.PtrNum 679 field.FieldQuery = value.FieldQuery 680 681 fieldCodes := Opcodes{field} 682 if op.IsMultipleOpField() { 683 field.Next = value 684 fieldCodes = fieldCodes.Add(valueCodes...) 685 } else { 686 ctx.decIndex() 687 } 688 return fieldCodes 689 } 690 691 func (c *StructFieldCode) addStructEndCode(ctx *compileContext, codes Opcodes) Opcodes { 692 end := &Opcode{ 693 Op: OpStructEnd, 694 Idx: opcodeOffset(ctx.ptrIndex), 695 DisplayIdx: ctx.opcodeIndex, 696 Indent: ctx.indent, 697 } 698 codes.Last().Next = end 699 code := codes.First() 700 for code.Op == OpStructField || code.Op == OpStructHead { 701 code = code.Next 702 } 703 for code.NextField != nil { 704 code = code.NextField 705 } 706 code.NextField = end 707 708 codes = codes.Add(end) 709 ctx.incOpcodeIndex() 710 return codes 711 } 712 713 func (c *StructFieldCode) structKey(ctx *compileContext) string { 714 if ctx.escapeKey { 715 rctx := &RuntimeContext{Option: &Option{Flag: HTMLEscapeOption}} 716 return fmt.Sprintf(`%s:`, string(AppendString(rctx, []byte{}, c.key))) 717 } 718 return fmt.Sprintf(`"%s":`, c.key) 719 } 720 721 func (c *StructFieldCode) flags() OpFlags { 722 var flags OpFlags 723 if c.isTaggedKey { 724 flags |= IsTaggedKeyFlags 725 } 726 if c.isNilableType { 727 flags |= IsNilableTypeFlags 728 } 729 if c.isNilCheck { 730 flags |= NilCheckFlags 731 } 732 if c.isAddrForMarshaler { 733 flags |= AddrForMarshalerFlags 734 } 735 if c.isNextOpPtrType { 736 flags |= IsNextOpPtrTypeFlags 737 } 738 if c.isAnonymous { 739 flags |= AnonymousKeyFlags 740 } 741 if c.isMarshalerContext { 742 flags |= MarshalerContextFlags 743 } 744 return flags 745 } 746 747 func (c *StructFieldCode) toValueOpcodes(ctx *compileContext) Opcodes { 748 if c.isAnonymous { 749 anonymCode, ok := c.value.(AnonymousCode) 750 if ok { 751 return anonymCode.ToAnonymousOpcode(ctx) 752 } 753 } 754 return c.value.ToOpcode(ctx) 755 } 756 757 func (c *StructFieldCode) ToOpcode(ctx *compileContext, isFirstField, isEndField bool) Opcodes { 758 field := &Opcode{ 759 Idx: opcodeOffset(ctx.ptrIndex), 760 Flags: c.flags(), 761 Key: c.structKey(ctx), 762 Offset: uint32(c.offset), 763 Type: c.typ, 764 DisplayIdx: ctx.opcodeIndex, 765 Indent: ctx.indent, 766 DisplayKey: c.key, 767 } 768 ctx.incIndex() 769 valueCodes := c.toValueOpcodes(ctx) 770 if isFirstField { 771 codes := c.headerOpcodes(ctx, field, valueCodes) 772 if isEndField { 773 codes = c.addStructEndCode(ctx, codes) 774 } 775 return codes 776 } 777 codes := c.fieldOpcodes(ctx, field, valueCodes) 778 if isEndField { 779 if isEnableStructEndOptimization(c.value) { 780 field.Op = field.Op.FieldToEnd() 781 } else { 782 codes = c.addStructEndCode(ctx, codes) 783 } 784 } 785 return codes 786 } 787 788 func (c *StructFieldCode) ToAnonymousOpcode(ctx *compileContext, isFirstField, isEndField bool) Opcodes { 789 field := &Opcode{ 790 Idx: opcodeOffset(ctx.ptrIndex), 791 Flags: c.flags() | AnonymousHeadFlags, 792 Key: c.structKey(ctx), 793 Offset: uint32(c.offset), 794 Type: c.typ, 795 DisplayIdx: ctx.opcodeIndex, 796 Indent: ctx.indent, 797 DisplayKey: c.key, 798 } 799 ctx.incIndex() 800 valueCodes := c.toValueOpcodes(ctx) 801 if isFirstField { 802 return c.headerOpcodes(ctx, field, valueCodes) 803 } 804 return c.fieldOpcodes(ctx, field, valueCodes) 805 } 806 807 func isEnableStructEndOptimization(value Code) bool { 808 switch value.Kind() { 809 case CodeKindInt, 810 CodeKindUint, 811 CodeKindFloat, 812 CodeKindString, 813 CodeKindBool, 814 CodeKindBytes: 815 return true 816 case CodeKindPtr: 817 return isEnableStructEndOptimization(value.(*PtrCode).value) 818 default: 819 return false 820 } 821 } 822 823 type InterfaceCode struct { 824 typ *runtime.Type 825 fieldQuery *FieldQuery 826 isPtr bool 827 } 828 829 func (c *InterfaceCode) Kind() CodeKind { 830 return CodeKindInterface 831 } 832 833 func (c *InterfaceCode) ToOpcode(ctx *compileContext) Opcodes { 834 var code *Opcode 835 switch { 836 case c.isPtr: 837 code = newOpCode(ctx, c.typ, OpInterfacePtr) 838 default: 839 code = newOpCode(ctx, c.typ, OpInterface) 840 } 841 code.FieldQuery = c.fieldQuery 842 if c.typ.NumMethod() > 0 { 843 code.Flags |= NonEmptyInterfaceFlags 844 } 845 ctx.incIndex() 846 return Opcodes{code} 847 } 848 849 func (c *InterfaceCode) Filter(query *FieldQuery) Code { 850 return &InterfaceCode{ 851 typ: c.typ, 852 fieldQuery: query, 853 isPtr: c.isPtr, 854 } 855 } 856 857 type MarshalJSONCode struct { 858 typ *runtime.Type 859 fieldQuery *FieldQuery 860 isAddrForMarshaler bool 861 isNilableType bool 862 isMarshalerContext bool 863 } 864 865 func (c *MarshalJSONCode) Kind() CodeKind { 866 return CodeKindMarshalJSON 867 } 868 869 func (c *MarshalJSONCode) ToOpcode(ctx *compileContext) Opcodes { 870 code := newOpCode(ctx, c.typ, OpMarshalJSON) 871 code.FieldQuery = c.fieldQuery 872 if c.isAddrForMarshaler { 873 code.Flags |= AddrForMarshalerFlags 874 } 875 if c.isMarshalerContext { 876 code.Flags |= MarshalerContextFlags 877 } 878 if c.isNilableType { 879 code.Flags |= IsNilableTypeFlags 880 } else { 881 code.Flags &= ^IsNilableTypeFlags 882 } 883 ctx.incIndex() 884 return Opcodes{code} 885 } 886 887 func (c *MarshalJSONCode) Filter(query *FieldQuery) Code { 888 return &MarshalJSONCode{ 889 typ: c.typ, 890 fieldQuery: query, 891 isAddrForMarshaler: c.isAddrForMarshaler, 892 isNilableType: c.isNilableType, 893 isMarshalerContext: c.isMarshalerContext, 894 } 895 } 896 897 type MarshalTextCode struct { 898 typ *runtime.Type 899 fieldQuery *FieldQuery 900 isAddrForMarshaler bool 901 isNilableType bool 902 } 903 904 func (c *MarshalTextCode) Kind() CodeKind { 905 return CodeKindMarshalText 906 } 907 908 func (c *MarshalTextCode) ToOpcode(ctx *compileContext) Opcodes { 909 code := newOpCode(ctx, c.typ, OpMarshalText) 910 code.FieldQuery = c.fieldQuery 911 if c.isAddrForMarshaler { 912 code.Flags |= AddrForMarshalerFlags 913 } 914 if c.isNilableType { 915 code.Flags |= IsNilableTypeFlags 916 } else { 917 code.Flags &= ^IsNilableTypeFlags 918 } 919 ctx.incIndex() 920 return Opcodes{code} 921 } 922 923 func (c *MarshalTextCode) Filter(query *FieldQuery) Code { 924 return &MarshalTextCode{ 925 typ: c.typ, 926 fieldQuery: query, 927 isAddrForMarshaler: c.isAddrForMarshaler, 928 isNilableType: c.isNilableType, 929 } 930 } 931 932 type PtrCode struct { 933 typ *runtime.Type 934 value Code 935 ptrNum uint8 936 } 937 938 func (c *PtrCode) Kind() CodeKind { 939 return CodeKindPtr 940 } 941 942 func (c *PtrCode) ToOpcode(ctx *compileContext) Opcodes { 943 codes := c.value.ToOpcode(ctx) 944 codes.First().Op = convertPtrOp(codes.First()) 945 codes.First().PtrNum = c.ptrNum 946 return codes 947 } 948 949 func (c *PtrCode) ToAnonymousOpcode(ctx *compileContext) Opcodes { 950 var codes Opcodes 951 anonymCode, ok := c.value.(AnonymousCode) 952 if ok { 953 codes = anonymCode.ToAnonymousOpcode(ctx) 954 } else { 955 codes = c.value.ToOpcode(ctx) 956 } 957 codes.First().Op = convertPtrOp(codes.First()) 958 codes.First().PtrNum = c.ptrNum 959 return codes 960 } 961 962 func (c *PtrCode) Filter(query *FieldQuery) Code { 963 return &PtrCode{ 964 typ: c.typ, 965 value: c.value.Filter(query), 966 ptrNum: c.ptrNum, 967 } 968 } 969 970 func convertPtrOp(code *Opcode) OpType { 971 ptrHeadOp := code.Op.HeadToPtrHead() 972 if code.Op != ptrHeadOp { 973 if code.PtrNum > 0 { 974 // ptr field and ptr head 975 code.PtrNum-- 976 } 977 return ptrHeadOp 978 } 979 switch code.Op { 980 case OpInt: 981 return OpIntPtr 982 case OpUint: 983 return OpUintPtr 984 case OpFloat32: 985 return OpFloat32Ptr 986 case OpFloat64: 987 return OpFloat64Ptr 988 case OpString: 989 return OpStringPtr 990 case OpBool: 991 return OpBoolPtr 992 case OpBytes: 993 return OpBytesPtr 994 case OpNumber: 995 return OpNumberPtr 996 case OpArray: 997 return OpArrayPtr 998 case OpSlice: 999 return OpSlicePtr 1000 case OpMap: 1001 return OpMapPtr 1002 case OpMarshalJSON: 1003 return OpMarshalJSONPtr 1004 case OpMarshalText: 1005 return OpMarshalTextPtr 1006 case OpInterface: 1007 return OpInterfacePtr 1008 case OpRecursive: 1009 return OpRecursivePtr 1010 } 1011 return code.Op 1012 } 1013 1014 func isEmbeddedStruct(field *StructFieldCode) bool { 1015 if !field.isAnonymous { 1016 return false 1017 } 1018 t := field.typ 1019 if t.Kind() == reflect.Ptr { 1020 t = t.Elem() 1021 } 1022 return t.Kind() == reflect.Struct 1023 }