1package jsoniter 2 3import ( 4 "fmt" 5 "github.com/modern-go/reflect2" 6 "io" 7 "reflect" 8 "unsafe" 9) 10 11func encoderOfStruct(ctx *ctx, typ reflect2.Type) ValEncoder { 12 type bindingTo struct { 13 binding *Binding 14 toName string 15 ignored bool 16 } 17 orderedBindings := []*bindingTo{} 18 structDescriptor := describeStruct(ctx, typ) 19 for _, binding := range structDescriptor.Fields { 20 for _, toName := range binding.ToNames { 21 new := &bindingTo{ 22 binding: binding, 23 toName: toName, 24 } 25 for _, old := range orderedBindings { 26 if old.toName != toName { 27 continue 28 } 29 old.ignored, new.ignored = resolveConflictBinding(ctx.frozenConfig, old.binding, new.binding) 30 } 31 orderedBindings = append(orderedBindings, new) 32 } 33 } 34 if len(orderedBindings) == 0 { 35 return &emptyStructEncoder{} 36 } 37 finalOrderedFields := []structFieldTo{} 38 for _, bindingTo := range orderedBindings { 39 if !bindingTo.ignored { 40 finalOrderedFields = append(finalOrderedFields, structFieldTo{ 41 encoder: bindingTo.binding.Encoder.(*structFieldEncoder), 42 toName: bindingTo.toName, 43 }) 44 } 45 } 46 return &structEncoder{typ, finalOrderedFields} 47} 48 49func createCheckIsEmpty(ctx *ctx, typ reflect2.Type) checkIsEmpty { 50 encoder := createEncoderOfNative(ctx, typ) 51 if encoder != nil { 52 return encoder 53 } 54 kind := typ.Kind() 55 switch kind { 56 case reflect.Interface: 57 return &dynamicEncoder{typ} 58 case reflect.Struct: 59 return &structEncoder{typ: typ} 60 case reflect.Array: 61 return &arrayEncoder{} 62 case reflect.Slice: 63 return &sliceEncoder{} 64 case reflect.Map: 65 return encoderOfMap(ctx, typ) 66 case reflect.Ptr: 67 return &OptionalEncoder{} 68 default: 69 return &lazyErrorEncoder{err: fmt.Errorf("unsupported type: %v", typ)} 70 } 71} 72 73func resolveConflictBinding(cfg *frozenConfig, old, new *Binding) (ignoreOld, ignoreNew bool) { 74 newTagged := new.Field.Tag().Get(cfg.getTagKey()) != "" 75 oldTagged := old.Field.Tag().Get(cfg.getTagKey()) != "" 76 if newTagged { 77 if oldTagged { 78 if len(old.levels) > len(new.levels) { 79 return true, false 80 } else if len(new.levels) > len(old.levels) { 81 return false, true 82 } else { 83 return true, true 84 } 85 } else { 86 return true, false 87 } 88 } else { 89 if oldTagged { 90 return true, false 91 } 92 if len(old.levels) > len(new.levels) { 93 return true, false 94 } else if len(new.levels) > len(old.levels) { 95 return false, true 96 } else { 97 return true, true 98 } 99 } 100} 101 102type structFieldEncoder struct { 103 field reflect2.StructField 104 fieldEncoder ValEncoder 105 omitempty bool 106} 107 108func (encoder *structFieldEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { 109 fieldPtr := encoder.field.UnsafeGet(ptr) 110 encoder.fieldEncoder.Encode(fieldPtr, stream) 111 if stream.Error != nil && stream.Error != io.EOF { 112 stream.Error = fmt.Errorf("%s: %s", encoder.field.Name(), stream.Error.Error()) 113 } 114} 115 116func (encoder *structFieldEncoder) IsEmpty(ptr unsafe.Pointer) bool { 117 fieldPtr := encoder.field.UnsafeGet(ptr) 118 return encoder.fieldEncoder.IsEmpty(fieldPtr) 119} 120 121func (encoder *structFieldEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool { 122 isEmbeddedPtrNil, converted := encoder.fieldEncoder.(IsEmbeddedPtrNil) 123 if !converted { 124 return false 125 } 126 fieldPtr := encoder.field.UnsafeGet(ptr) 127 return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr) 128} 129 130type IsEmbeddedPtrNil interface { 131 IsEmbeddedPtrNil(ptr unsafe.Pointer) bool 132} 133 134type structEncoder struct { 135 typ reflect2.Type 136 fields []structFieldTo 137} 138 139type structFieldTo struct { 140 encoder *structFieldEncoder 141 toName string 142} 143 144func (encoder *structEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { 145 stream.WriteObjectStart() 146 isNotFirst := false 147 for _, field := range encoder.fields { 148 if field.encoder.omitempty && field.encoder.IsEmpty(ptr) { 149 continue 150 } 151 if field.encoder.IsEmbeddedPtrNil(ptr) { 152 continue 153 } 154 if isNotFirst { 155 stream.WriteMore() 156 } 157 stream.WriteObjectField(field.toName) 158 field.encoder.Encode(ptr, stream) 159 isNotFirst = true 160 } 161 stream.WriteObjectEnd() 162 if stream.Error != nil && stream.Error != io.EOF { 163 stream.Error = fmt.Errorf("%v.%s", encoder.typ, stream.Error.Error()) 164 } 165} 166 167func (encoder *structEncoder) IsEmpty(ptr unsafe.Pointer) bool { 168 return false 169} 170 171type emptyStructEncoder struct { 172} 173 174func (encoder *emptyStructEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { 175 stream.WriteEmptyObject() 176} 177 178func (encoder *emptyStructEncoder) IsEmpty(ptr unsafe.Pointer) bool { 179 return false 180} 181 182type stringModeNumberEncoder struct { 183 elemEncoder ValEncoder 184} 185 186func (encoder *stringModeNumberEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { 187 stream.writeByte('"') 188 encoder.elemEncoder.Encode(ptr, stream) 189 stream.writeByte('"') 190} 191 192func (encoder *stringModeNumberEncoder) IsEmpty(ptr unsafe.Pointer) bool { 193 return encoder.elemEncoder.IsEmpty(ptr) 194} 195 196type stringModeStringEncoder struct { 197 elemEncoder ValEncoder 198 cfg *frozenConfig 199} 200 201func (encoder *stringModeStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { 202 tempStream := encoder.cfg.BorrowStream(nil) 203 defer encoder.cfg.ReturnStream(tempStream) 204 encoder.elemEncoder.Encode(ptr, tempStream) 205 stream.WriteString(string(tempStream.Buffer())) 206} 207 208func (encoder *stringModeStringEncoder) IsEmpty(ptr unsafe.Pointer) bool { 209 return encoder.elemEncoder.IsEmpty(ptr) 210} 211