github.com/zerosnake0/jzon@v0.0.9-0.20230801092939-1b135cb83f7f/val_decoder_native_slice.go (about) 1 package jzon 2 3 import ( 4 "encoding/base64" 5 "reflect" 6 "unsafe" 7 ) 8 9 type sliceDecoderBuilder struct { 10 decoder *sliceDecoder 11 elemPtrRType rtype 12 } 13 14 func newSliceDecoder(sliceType reflect.Type) *sliceDecoderBuilder { 15 elem := sliceType.Elem() 16 return &sliceDecoderBuilder{ 17 decoder: &sliceDecoder{ 18 elemKind: elem.Kind(), 19 elemRType: rtypeOfType(elem), 20 elemSize: elem.Size(), 21 }, 22 elemPtrRType: rtypeOfType(reflect.PtrTo(elem)), 23 } 24 } 25 26 func (builder *sliceDecoderBuilder) build(cache decoderCache) { 27 builder.decoder.elemDec = cache[builder.elemPtrRType] 28 } 29 30 type sliceDecoder struct { 31 elemKind reflect.Kind 32 elemRType rtype 33 elemSize uintptr 34 elemDec ValDecoder 35 } 36 37 func (dec *sliceDecoder) Decode(ptr unsafe.Pointer, it *Iterator, _ *DecOpts) error { 38 c, err := it.nextToken() 39 if err != nil { 40 return err 41 } 42 if c == 'n' { 43 it.head++ 44 if err = it.expectBytes("ull"); err != nil { 45 return err 46 } 47 sh := (*sliceHeader)(ptr) 48 sh.Len = 0 49 sh.Cap = 0 50 sh.Data = 0 51 return nil 52 } 53 if c == '"' { 54 if dec.elemKind != reflect.Uint8 { 55 return UnexpectedByteError{got: c, exp: '[', exp2: 'n'} 56 } 57 it.head++ 58 // TODO: improve by checking only base64 characters 59 begin := it.head 60 oldCapture := it.capture 61 it.capture = true 62 if err := skipString(it, c); err != nil { 63 return err 64 } 65 it.capture = oldCapture 66 buf := it.buffer[begin : it.head-1] 67 data, err := base64.StdEncoding.DecodeString(localByteToString(buf)) 68 if err != nil { 69 return err 70 } 71 *((*[]byte)(ptr)) = data 72 return nil 73 } 74 if c != '[' { 75 return UnexpectedByteError{got: c, exp: '[', exp2: 'n'} 76 } 77 it.head++ 78 c, err = it.nextToken() 79 if err != nil { 80 return err 81 } 82 newPtr := unsafeMakeSlice(dec.elemRType, 0, 0) 83 if c == ']' { 84 it.head++ 85 } else { 86 for length := 1; ; length++ { 87 newPtr = unsafeGrowSlice(dec.elemRType, newPtr, length) 88 // must get the address every time 89 childPtr := unsafeSliceChildPtr(newPtr, dec.elemSize, length-1) 90 if err = dec.elemDec.Decode(childPtr, it, nil); err != nil { 91 return err 92 } 93 c, err = it.nextToken() 94 if err != nil { 95 return err 96 } 97 it.head++ 98 if c == ']' { 99 break 100 } 101 if c != ',' { 102 return UnexpectedByteError{got: c, exp: ']', exp2: ','} 103 } 104 } 105 } 106 *(*sliceHeader)(ptr) = *(*sliceHeader)(newPtr) 107 return nil 108 }