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