package stt import ( "github.com/modern-go/reflect2" "unsafe" ) func decoderOfOptional(ctx *ctx, typ reflect2.Type) ValDecoder { ptrType := typ.(*reflect2.UnsafePtrType) elemType := ptrType.Elem() decoder := decoderOfType(ctx, elemType) return &OptionalDecoder{elemType, decoder} } func encoderOfOptional(ctx *ctx, typ reflect2.Type) ValEncoder { ptrType := typ.(*reflect2.UnsafePtrType) elemType := ptrType.Elem() elemEncoder := encoderOfType(ctx, elemType) encoder := &OptionalEncoder{elemEncoder} return encoder } type OptionalDecoder struct { ValueType reflect2.Type ValueDecoder ValDecoder } func (decoder *OptionalDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { if iter.ReadNil() { *((*unsafe.Pointer)(ptr)) = nil } else { if *((*unsafe.Pointer)(ptr)) == nil { //pointer to null, we have to allocate memory to hold the value newPtr := decoder.ValueType.UnsafeNew() decoder.ValueDecoder.Decode(newPtr, iter) *((*unsafe.Pointer)(ptr)) = newPtr } else { //reuse existing instance decoder.ValueDecoder.Decode(*((*unsafe.Pointer)(ptr)), iter) } } } type dereferenceDecoder struct { // only to deference a pointer valueType reflect2.Type valueDecoder ValDecoder } func (decoder *dereferenceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { if *((*unsafe.Pointer)(ptr)) == nil { //pointer to null, we have to allocate memory to hold the value newPtr := decoder.valueType.UnsafeNew() decoder.valueDecoder.Decode(newPtr, iter) *((*unsafe.Pointer)(ptr)) = newPtr } else { //reuse existing instance decoder.valueDecoder.Decode(*((*unsafe.Pointer)(ptr)), iter) } } type OptionalEncoder struct { ValueEncoder ValEncoder } func (encoder *OptionalEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { if *((*unsafe.Pointer)(ptr)) == nil { stream.WriteNil() } else { encoder.ValueEncoder.Encode(*((*unsafe.Pointer)(ptr)), stream) } } func (encoder *OptionalEncoder) IsEmpty(ptr unsafe.Pointer) bool { return *((*unsafe.Pointer)(ptr)) == nil } type dereferenceEncoder struct { ValueEncoder ValEncoder } func (encoder *dereferenceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { if *((*unsafe.Pointer)(ptr)) == nil { stream.WriteNil() } else { encoder.ValueEncoder.Encode(*((*unsafe.Pointer)(ptr)), stream) } } func (encoder *dereferenceEncoder) IsEmpty(ptr unsafe.Pointer) bool { dePtr := *((*unsafe.Pointer)(ptr)) if dePtr == nil { return true } return encoder.ValueEncoder.IsEmpty(dePtr) } func (encoder *dereferenceEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool { deReferenced := *((*unsafe.Pointer)(ptr)) if deReferenced == nil { return true } isEmbeddedPtrNil, converted := encoder.ValueEncoder.(IsEmbeddedPtrNil) if !converted { return false } fieldPtr := unsafe.Pointer(deReferenced) return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr) } type referenceEncoder struct { encoder ValEncoder } func (encoder *referenceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { encoder.encoder.Encode(unsafe.Pointer(&ptr), stream) } func (encoder *referenceEncoder) IsEmpty(ptr unsafe.Pointer) bool { return encoder.encoder.IsEmpty(unsafe.Pointer(&ptr)) } type referenceDecoder struct { decoder ValDecoder } func (decoder *referenceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { decoder.decoder.Decode(unsafe.Pointer(&ptr), iter) }