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  }