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