github.com/night-codes/go-json@v0.9.15/internal/decoder/array.go (about)

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