git.gammaspectra.live/P2Pool/go-json@v0.99.0/internal/decoder/array.go (about)

     1  package decoder
     2  
     3  import (
     4  	"fmt"
     5  	"unsafe"
     6  
     7  	"git.gammaspectra.live/P2Pool/go-json/internal/errors"
     8  	"git.gammaspectra.live/P2Pool/go-json/internal/runtime"
     9  )
    10  
    11  type arrayDecoder struct {
    12  	elemType     *runtime.Type
    13  	size         uintptr
    14  	valueDecoder Decoder
    15  	alen         int
    16  	structName   string
    17  	fieldName    string
    18  	zeroValue    unsafe.Pointer
    19  }
    20  
    21  func newArrayDecoder(dec Decoder, elemType *runtime.Type, alen int, structName, fieldName string) *arrayDecoder {
    22  	// workaround to avoid checkptr errors. cannot use `*(*unsafe.Pointer)(unsafe_New(elemType))` directly.
    23  	zeroValuePtr := unsafe_New(elemType)
    24  	zeroValue := **(**unsafe.Pointer)(unsafe.Pointer(&zeroValuePtr))
    25  	return &arrayDecoder{
    26  		valueDecoder: dec,
    27  		elemType:     elemType,
    28  		size:         elemType.Size(),
    29  		alen:         alen,
    30  		structName:   structName,
    31  		fieldName:    fieldName,
    32  		zeroValue:    zeroValue,
    33  	}
    34  }
    35  
    36  func (d *arrayDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
    37  	depth++
    38  	if depth > maxDecodeNestingDepth {
    39  		return errors.ErrExceededMaxDepth(s.char(), s.cursor)
    40  	}
    41  
    42  	for {
    43  		switch s.char() {
    44  		case ' ', '\n', '\t', '\r':
    45  		case 'n':
    46  			if err := nullBytes(s); err != nil {
    47  				return err
    48  			}
    49  			return nil
    50  		case '[':
    51  			idx := 0
    52  			s.cursor++
    53  			if s.skipWhiteSpace() == ']' {
    54  				for idx < d.alen {
    55  					*(*unsafe.Pointer)(unsafe.Pointer(uintptr(p) + uintptr(idx)*d.size)) = d.zeroValue
    56  					idx++
    57  				}
    58  				s.cursor++
    59  				return nil
    60  			}
    61  			for {
    62  				if idx < d.alen {
    63  					if err := d.valueDecoder.DecodeStream(s, depth, unsafe.Pointer(uintptr(p)+uintptr(idx)*d.size)); err != nil {
    64  						return err
    65  					}
    66  				} else {
    67  					if err := s.skipValue(depth); err != nil {
    68  						return err
    69  					}
    70  				}
    71  				idx++
    72  				switch s.skipWhiteSpace() {
    73  				case ']':
    74  					for idx < d.alen {
    75  						*(*unsafe.Pointer)(unsafe.Pointer(uintptr(p) + uintptr(idx)*d.size)) = d.zeroValue
    76  						idx++
    77  					}
    78  					s.cursor++
    79  					return nil
    80  				case ',':
    81  					s.cursor++
    82  					continue
    83  				case nul:
    84  					if s.read() {
    85  						s.cursor++
    86  						continue
    87  					}
    88  					goto ERROR
    89  				default:
    90  					goto ERROR
    91  				}
    92  			}
    93  		case nul:
    94  			if s.read() {
    95  				continue
    96  			}
    97  			goto ERROR
    98  		default:
    99  			goto ERROR
   100  		}
   101  		s.cursor++
   102  	}
   103  ERROR:
   104  	return errors.ErrUnexpectedEndOfJSON("array", s.totalOffset())
   105  }
   106  
   107  func (d *arrayDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
   108  	buf := ctx.Buf
   109  	depth++
   110  	if depth > maxDecodeNestingDepth {
   111  		return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
   112  	}
   113  
   114  	for {
   115  		switch buf[cursor] {
   116  		case ' ', '\n', '\t', '\r':
   117  			cursor++
   118  			continue
   119  		case 'n':
   120  			if err := validateNull(buf, cursor); err != nil {
   121  				return 0, err
   122  			}
   123  			cursor += 4
   124  			return cursor, nil
   125  		case '[':
   126  			idx := 0
   127  			cursor++
   128  			cursor = skipWhiteSpace(buf, cursor)
   129  			if buf[cursor] == ']' {
   130  				for idx < d.alen {
   131  					*(*unsafe.Pointer)(unsafe.Pointer(uintptr(p) + uintptr(idx)*d.size)) = d.zeroValue
   132  					idx++
   133  				}
   134  				cursor++
   135  				return cursor, nil
   136  			}
   137  			for {
   138  				if idx < d.alen {
   139  					c, err := d.valueDecoder.Decode(ctx, cursor, depth, unsafe.Pointer(uintptr(p)+uintptr(idx)*d.size))
   140  					if err != nil {
   141  						return 0, err
   142  					}
   143  					cursor = c
   144  				} else {
   145  					c, err := skipValue(buf, cursor, depth)
   146  					if err != nil {
   147  						return 0, err
   148  					}
   149  					cursor = c
   150  				}
   151  				idx++
   152  				cursor = skipWhiteSpace(buf, cursor)
   153  				switch buf[cursor] {
   154  				case ']':
   155  					for idx < d.alen {
   156  						*(*unsafe.Pointer)(unsafe.Pointer(uintptr(p) + uintptr(idx)*d.size)) = d.zeroValue
   157  						idx++
   158  					}
   159  					cursor++
   160  					return cursor, nil
   161  				case ',':
   162  					cursor++
   163  					continue
   164  				default:
   165  					return 0, errors.ErrInvalidCharacter(buf[cursor], "array", cursor)
   166  				}
   167  			}
   168  		default:
   169  			return 0, errors.ErrUnexpectedEndOfJSON("array", cursor)
   170  		}
   171  	}
   172  }
   173  
   174  func (d *arrayDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) {
   175  	return nil, 0, fmt.Errorf("json: array decoder does not support decode path")
   176  }