reflect_marshaler.go (5964B)
1 package jsoniter 2 3 import ( 4 "encoding" 5 "encoding/json" 6 "unsafe" 7 8 "github.com/modern-go/reflect2" 9 ) 10 11 var marshalerType = reflect2.TypeOfPtr((*json.Marshaler)(nil)).Elem() 12 var unmarshalerType = reflect2.TypeOfPtr((*json.Unmarshaler)(nil)).Elem() 13 var textMarshalerType = reflect2.TypeOfPtr((*encoding.TextMarshaler)(nil)).Elem() 14 var textUnmarshalerType = reflect2.TypeOfPtr((*encoding.TextUnmarshaler)(nil)).Elem() 15 16 func createDecoderOfMarshaler(ctx *ctx, typ reflect2.Type) ValDecoder { 17 ptrType := reflect2.PtrTo(typ) 18 if ptrType.Implements(unmarshalerType) { 19 return &referenceDecoder{ 20 &unmarshalerDecoder{ptrType}, 21 } 22 } 23 if ptrType.Implements(textUnmarshalerType) { 24 return &referenceDecoder{ 25 &textUnmarshalerDecoder{ptrType}, 26 } 27 } 28 return nil 29 } 30 31 func createEncoderOfMarshaler(ctx *ctx, typ reflect2.Type) ValEncoder { 32 if typ == marshalerType { 33 checkIsEmpty := createCheckIsEmpty(ctx, typ) 34 var encoder ValEncoder = &directMarshalerEncoder{ 35 checkIsEmpty: checkIsEmpty, 36 } 37 return encoder 38 } 39 if typ.Implements(marshalerType) { 40 checkIsEmpty := createCheckIsEmpty(ctx, typ) 41 var encoder ValEncoder = &marshalerEncoder{ 42 valType: typ, 43 checkIsEmpty: checkIsEmpty, 44 } 45 return encoder 46 } 47 ptrType := reflect2.PtrTo(typ) 48 if ctx.prefix != "" && ptrType.Implements(marshalerType) { 49 checkIsEmpty := createCheckIsEmpty(ctx, ptrType) 50 var encoder ValEncoder = &marshalerEncoder{ 51 valType: ptrType, 52 checkIsEmpty: checkIsEmpty, 53 } 54 return &referenceEncoder{encoder} 55 } 56 if typ == textMarshalerType { 57 checkIsEmpty := createCheckIsEmpty(ctx, typ) 58 var encoder ValEncoder = &directTextMarshalerEncoder{ 59 checkIsEmpty: checkIsEmpty, 60 stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), 61 } 62 return encoder 63 } 64 if typ.Implements(textMarshalerType) { 65 checkIsEmpty := createCheckIsEmpty(ctx, typ) 66 var encoder ValEncoder = &textMarshalerEncoder{ 67 valType: typ, 68 stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), 69 checkIsEmpty: checkIsEmpty, 70 } 71 return encoder 72 } 73 // if prefix is empty, the type is the root type 74 if ctx.prefix != "" && ptrType.Implements(textMarshalerType) { 75 checkIsEmpty := createCheckIsEmpty(ctx, ptrType) 76 var encoder ValEncoder = &textMarshalerEncoder{ 77 valType: ptrType, 78 stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), 79 checkIsEmpty: checkIsEmpty, 80 } 81 return &referenceEncoder{encoder} 82 } 83 return nil 84 } 85 86 type marshalerEncoder struct { 87 checkIsEmpty checkIsEmpty 88 valType reflect2.Type 89 } 90 91 func (encoder *marshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { 92 obj := encoder.valType.UnsafeIndirect(ptr) 93 if encoder.valType.IsNullable() && reflect2.IsNil(obj) { 94 stream.WriteNil() 95 return 96 } 97 marshaler := obj.(json.Marshaler) 98 bytes, err := marshaler.MarshalJSON() 99 if err != nil { 100 stream.Error = err 101 } else { 102 // html escape was already done by jsoniter 103 // but the extra '\n' should be trimed 104 l := len(bytes) 105 if l > 0 && bytes[l-1] == '\n' { 106 bytes = bytes[:l-1] 107 } 108 stream.Write(bytes) 109 } 110 } 111 112 func (encoder *marshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool { 113 return encoder.checkIsEmpty.IsEmpty(ptr) 114 } 115 116 type directMarshalerEncoder struct { 117 checkIsEmpty checkIsEmpty 118 } 119 120 func (encoder *directMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { 121 marshaler := *(*json.Marshaler)(ptr) 122 if marshaler == nil { 123 stream.WriteNil() 124 return 125 } 126 bytes, err := marshaler.MarshalJSON() 127 if err != nil { 128 stream.Error = err 129 } else { 130 stream.Write(bytes) 131 } 132 } 133 134 func (encoder *directMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool { 135 return encoder.checkIsEmpty.IsEmpty(ptr) 136 } 137 138 type textMarshalerEncoder struct { 139 valType reflect2.Type 140 stringEncoder ValEncoder 141 checkIsEmpty checkIsEmpty 142 } 143 144 func (encoder *textMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { 145 obj := encoder.valType.UnsafeIndirect(ptr) 146 if encoder.valType.IsNullable() && reflect2.IsNil(obj) { 147 stream.WriteNil() 148 return 149 } 150 marshaler := (obj).(encoding.TextMarshaler) 151 bytes, err := marshaler.MarshalText() 152 if err != nil { 153 stream.Error = err 154 } else { 155 str := string(bytes) 156 encoder.stringEncoder.Encode(unsafe.Pointer(&str), stream) 157 } 158 } 159 160 func (encoder *textMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool { 161 return encoder.checkIsEmpty.IsEmpty(ptr) 162 } 163 164 type directTextMarshalerEncoder struct { 165 stringEncoder ValEncoder 166 checkIsEmpty checkIsEmpty 167 } 168 169 func (encoder *directTextMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { 170 marshaler := *(*encoding.TextMarshaler)(ptr) 171 if marshaler == nil { 172 stream.WriteNil() 173 return 174 } 175 bytes, err := marshaler.MarshalText() 176 if err != nil { 177 stream.Error = err 178 } else { 179 str := string(bytes) 180 encoder.stringEncoder.Encode(unsafe.Pointer(&str), stream) 181 } 182 } 183 184 func (encoder *directTextMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool { 185 return encoder.checkIsEmpty.IsEmpty(ptr) 186 } 187 188 type unmarshalerDecoder struct { 189 valType reflect2.Type 190 } 191 192 func (decoder *unmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { 193 valType := decoder.valType 194 obj := valType.UnsafeIndirect(ptr) 195 unmarshaler := obj.(json.Unmarshaler) 196 iter.nextToken() 197 iter.unreadByte() // skip spaces 198 bytes := iter.SkipAndReturnBytes() 199 err := unmarshaler.UnmarshalJSON(bytes) 200 if err != nil { 201 iter.ReportError("unmarshalerDecoder", err.Error()) 202 } 203 } 204 205 type textUnmarshalerDecoder struct { 206 valType reflect2.Type 207 } 208 209 func (decoder *textUnmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { 210 valType := decoder.valType 211 obj := valType.UnsafeIndirect(ptr) 212 if reflect2.IsNil(obj) { 213 ptrType := valType.(*reflect2.UnsafePtrType) 214 elemType := ptrType.Elem() 215 elem := elemType.UnsafeNew() 216 ptrType.UnsafeSet(ptr, unsafe.Pointer(&elem)) 217 obj = valType.UnsafeIndirect(ptr) 218 } 219 unmarshaler := (obj).(encoding.TextUnmarshaler) 220 str := iter.ReadString() 221 err := unmarshaler.UnmarshalText([]byte(str)) 222 if err != nil { 223 iter.ReportError("textUnmarshalerDecoder", err.Error()) 224 } 225 }