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