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 }