1package jsoniter 2 3import ( 4 "github.com/modern-go/reflect2" 5 "reflect" 6 "unsafe" 7) 8 9func decoderOfOptional(ctx *ctx, typ reflect2.Type) ValDecoder { 10 ptrType := typ.(*reflect2.UnsafePtrType) 11 elemType := ptrType.Elem() 12 decoder := decoderOfType(ctx, elemType) 13 if ctx.prefix == "" && elemType.Kind() == reflect.Ptr { 14 return &dereferenceDecoder{elemType, decoder} 15 } 16 return &OptionalDecoder{elemType, decoder} 17} 18 19func encoderOfOptional(ctx *ctx, typ reflect2.Type) ValEncoder { 20 ptrType := typ.(*reflect2.UnsafePtrType) 21 elemType := ptrType.Elem() 22 elemEncoder := encoderOfType(ctx, elemType) 23 encoder := &OptionalEncoder{elemEncoder} 24 return encoder 25} 26 27type OptionalDecoder struct { 28 ValueType reflect2.Type 29 ValueDecoder ValDecoder 30} 31 32func (decoder *OptionalDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { 33 if iter.ReadNil() { 34 *((*unsafe.Pointer)(ptr)) = nil 35 } else { 36 if *((*unsafe.Pointer)(ptr)) == nil { 37 //pointer to null, we have to allocate memory to hold the value 38 newPtr := decoder.ValueType.UnsafeNew() 39 decoder.ValueDecoder.Decode(newPtr, iter) 40 *((*unsafe.Pointer)(ptr)) = newPtr 41 } else { 42 //reuse existing instance 43 decoder.ValueDecoder.Decode(*((*unsafe.Pointer)(ptr)), iter) 44 } 45 } 46} 47 48type dereferenceDecoder struct { 49 // only to deference a pointer 50 valueType reflect2.Type 51 valueDecoder ValDecoder 52} 53 54func (decoder *dereferenceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { 55 if *((*unsafe.Pointer)(ptr)) == nil { 56 //pointer to null, we have to allocate memory to hold the value 57 newPtr := decoder.valueType.UnsafeNew() 58 decoder.valueDecoder.Decode(newPtr, iter) 59 *((*unsafe.Pointer)(ptr)) = newPtr 60 } else { 61 //reuse existing instance 62 decoder.valueDecoder.Decode(*((*unsafe.Pointer)(ptr)), iter) 63 } 64} 65 66type OptionalEncoder struct { 67 ValueEncoder ValEncoder 68} 69 70func (encoder *OptionalEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { 71 if *((*unsafe.Pointer)(ptr)) == nil { 72 stream.WriteNil() 73 } else { 74 encoder.ValueEncoder.Encode(*((*unsafe.Pointer)(ptr)), stream) 75 } 76} 77 78func (encoder *OptionalEncoder) IsEmpty(ptr unsafe.Pointer) bool { 79 return *((*unsafe.Pointer)(ptr)) == nil 80} 81 82type dereferenceEncoder struct { 83 ValueEncoder ValEncoder 84} 85 86func (encoder *dereferenceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { 87 if *((*unsafe.Pointer)(ptr)) == nil { 88 stream.WriteNil() 89 } else { 90 encoder.ValueEncoder.Encode(*((*unsafe.Pointer)(ptr)), stream) 91 } 92} 93 94func (encoder *dereferenceEncoder) IsEmpty(ptr unsafe.Pointer) bool { 95 dePtr := *((*unsafe.Pointer)(ptr)) 96 if dePtr == nil { 97 return true 98 } 99 return encoder.ValueEncoder.IsEmpty(dePtr) 100} 101 102func (encoder *dereferenceEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool { 103 deReferenced := *((*unsafe.Pointer)(ptr)) 104 if deReferenced == nil { 105 return true 106 } 107 isEmbeddedPtrNil, converted := encoder.ValueEncoder.(IsEmbeddedPtrNil) 108 if !converted { 109 return false 110 } 111 fieldPtr := unsafe.Pointer(deReferenced) 112 return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr) 113} 114 115type referenceEncoder struct { 116 encoder ValEncoder 117} 118 119func (encoder *referenceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { 120 encoder.encoder.Encode(unsafe.Pointer(&ptr), stream) 121} 122 123func (encoder *referenceEncoder) IsEmpty(ptr unsafe.Pointer) bool { 124 return encoder.encoder.IsEmpty(unsafe.Pointer(&ptr)) 125} 126 127type referenceDecoder struct { 128 decoder ValDecoder 129} 130 131func (decoder *referenceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { 132 decoder.decoder.Decode(unsafe.Pointer(&ptr), iter) 133} 134