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