github.com/zerosnake0/jzon@v0.0.9-0.20230801092939-1b135cb83f7f/val_decoder_native_array.go (about)

     1  package jzon
     2  
     3  import (
     4  	"reflect"
     5  	"unsafe"
     6  )
     7  
     8  type arrayDecoderBuilder struct {
     9  	decoder      *arrayDecoder
    10  	elemPtrRType rtype
    11  }
    12  
    13  func newArrayDecoder(arrType reflect.Type) *arrayDecoderBuilder {
    14  	elem := arrType.Elem()
    15  	return &arrayDecoderBuilder{
    16  		decoder: &arrayDecoder{
    17  			rtype:    rtypeOfType(arrType),
    18  			size:     arrType.Size(),
    19  			elemSize: elem.Size(),
    20  			length:   arrType.Len(),
    21  			// elemRType: rtypeOfType(elem),
    22  		},
    23  		elemPtrRType: rtypeOfType(reflect.PtrTo(elem)),
    24  	}
    25  }
    26  
    27  func (builder *arrayDecoderBuilder) build(cache decoderCache) {
    28  	builder.decoder.elemDec = cache[builder.elemPtrRType]
    29  }
    30  
    31  type arrayDecoder struct {
    32  	rtype    rtype
    33  	size     uintptr
    34  	elemSize uintptr
    35  	length   int
    36  	// elemRType rtype
    37  
    38  	elemDec ValDecoder
    39  }
    40  
    41  func (dec *arrayDecoder) Decode(ptr unsafe.Pointer, it *Iterator, _ *DecOpts) error {
    42  	c, err := it.nextToken()
    43  	if err != nil {
    44  		return err
    45  	}
    46  	if c == 'n' {
    47  		it.head++
    48  		return it.expectBytes("ull")
    49  	}
    50  	if c != '[' {
    51  		return UnexpectedByteError{got: c, exp: '[', exp2: 'n'}
    52  	}
    53  	it.head++
    54  	c, err = it.nextToken()
    55  	if err != nil {
    56  		return err
    57  	}
    58  	count := 0
    59  	var offset uintptr = 0
    60  	if c == ']' {
    61  		it.head++
    62  	} else {
    63  		for {
    64  			if count < dec.length {
    65  				// newer golang version seems to disallow direct
    66  				// uintptr to unsafe.Pointer convert
    67  				elemPtr := add(ptr, offset, "count < dec.length")
    68  				if err := dec.elemDec.Decode(elemPtr, it, nil); err != nil {
    69  					return err
    70  				}
    71  				count++
    72  				offset += dec.elemSize
    73  			} else {
    74  				if err := it.Skip(); err != nil {
    75  					return err
    76  				}
    77  			}
    78  			c, err = it.nextToken()
    79  			if err != nil {
    80  				return err
    81  			}
    82  			it.head++
    83  			if c == ']' {
    84  				break
    85  			}
    86  			if c != ',' {
    87  				return UnexpectedByteError{got: c, exp: ']', exp2: ','}
    88  			}
    89  		}
    90  	}
    91  	if count < dec.length {
    92  		// should be safe (?)
    93  		typedmemclrpartial(dec.rtype, add(ptr, offset, "count < dec.length"),
    94  			offset, dec.size-offset)
    95  	}
    96  	return nil
    97  }