github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/jsoni/reflect_slice.go (about)

     1  package jsoni
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  	"unsafe"
     8  
     9  	"github.com/modern-go/reflect2"
    10  )
    11  
    12  func decoderOfSlice(ctx *ctx, typ reflect2.Type) ValDecoder {
    13  	sliceType := typ.(*reflect2.UnsafeSliceType)
    14  	decoder := decoderOfType(ctx.append("[sliceElem]"), sliceType.Elem())
    15  	return &sliceDecoder{sliceType: sliceType, elemDecoder: decoder}
    16  }
    17  
    18  func encoderOfSlice(ctx *ctx, typ reflect2.Type) ValEncoder {
    19  	sliceType := typ.(*reflect2.UnsafeSliceType)
    20  	encoder := encoderOfType(ctx.append("[sliceElem]"), sliceType.Elem())
    21  	return &sliceEncoder{ctx: ctx, sliceType: sliceType, elemEncoder: encoder}
    22  }
    23  
    24  type sliceEncoder struct {
    25  	ctx         *ctx
    26  	sliceType   *reflect2.UnsafeSliceType
    27  	elemEncoder ValEncoder
    28  }
    29  
    30  func (e *sliceEncoder) Encode(ctx context.Context, ptr unsafe.Pointer, stream *Stream) {
    31  	if getContextNilEmpty(ctx) && e.IsEmpty(ctx, ptr, true) {
    32  		stream.WriteEmptyArray()
    33  	} else {
    34  		if e.sliceType.UnsafeIsNil(ptr) {
    35  			stream.WriteNil()
    36  			return
    37  		}
    38  		length := e.sliceType.UnsafeLengthOf(ptr)
    39  		if length == 0 {
    40  			stream.WriteEmptyArray()
    41  			return
    42  		}
    43  		stream.WriteArrayStart()
    44  		e.elemEncoder.Encode(ctx, e.sliceType.UnsafeGetIndex(ptr, 0), stream)
    45  		for i := 1; i < length; i++ {
    46  			stream.WriteMore()
    47  			elemPtr := e.sliceType.UnsafeGetIndex(ptr, i)
    48  			e.elemEncoder.Encode(ctx, elemPtr, stream)
    49  		}
    50  		stream.WriteArrayEnd()
    51  	}
    52  
    53  	if stream.Error != nil && stream.Error != io.EOF {
    54  		stream.Error = fmt.Errorf("%v: %s", e.sliceType, stream.Error.Error())
    55  	}
    56  }
    57  
    58  func (e *sliceEncoder) IsEmpty(_ context.Context, ptr unsafe.Pointer, _ bool) bool {
    59  	return e.sliceType.UnsafeLengthOf(ptr) == 0
    60  }
    61  
    62  type sliceDecoder struct {
    63  	sliceType   *reflect2.UnsafeSliceType
    64  	elemDecoder ValDecoder
    65  }
    66  
    67  func (d *sliceDecoder) Decode(ctx context.Context, ptr unsafe.Pointer, iter *Iterator) {
    68  	d.doDecode(ctx, ptr, iter)
    69  	if iter.Error != nil && iter.Error != io.EOF {
    70  		iter.Error = fmt.Errorf("%v: %s", d.sliceType, iter.Error.Error())
    71  	}
    72  }
    73  
    74  func (d *sliceDecoder) doDecode(ctx context.Context, ptr unsafe.Pointer, iter *Iterator) {
    75  	c := iter.nextToken()
    76  	sliceType := d.sliceType
    77  	if c == 'n' {
    78  		iter.skip3Bytes('u', 'l', 'l')
    79  		sliceType.UnsafeSetNil(ptr)
    80  		return
    81  	}
    82  	if c != '[' {
    83  		iter.ReportError("decode slice", "expect [ or n, but found "+string([]byte{c}))
    84  		return
    85  	}
    86  	c = iter.nextToken()
    87  	if c == ']' {
    88  		sliceType.UnsafeSet(ptr, sliceType.UnsafeMakeSlice(0, 0))
    89  		return
    90  	}
    91  	iter.unreadByte()
    92  	sliceType.UnsafeGrow(ptr, 1)
    93  	elemPtr := sliceType.UnsafeGetIndex(ptr, 0)
    94  	d.elemDecoder.Decode(ctx, elemPtr, iter)
    95  	length := 1
    96  	for c = iter.nextToken(); c == ','; c = iter.nextToken() {
    97  		idx := length
    98  		length += 1
    99  		sliceType.UnsafeGrow(ptr, length)
   100  		elemPtr = sliceType.UnsafeGetIndex(ptr, idx)
   101  		d.elemDecoder.Decode(ctx, elemPtr, iter)
   102  	}
   103  	if c != ']' {
   104  		iter.ReportError("decode slice", "expect ], but found "+string([]byte{c}))
   105  		return
   106  	}
   107  }