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  }