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

     1  package decoder
     2  
     3  import (
     4  	"reflect"
     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 mapDecoder struct {
    12  	mapType                 *runtime.Type
    13  	keyType                 *runtime.Type
    14  	valueType               *runtime.Type
    15  	canUseAssignFaststrType bool
    16  	keyDecoder              Decoder
    17  	valueDecoder            Decoder
    18  	structName              string
    19  	fieldName               string
    20  }
    21  
    22  func newMapDecoder(mapType *runtime.Type, keyType *runtime.Type, keyDec Decoder, valueType *runtime.Type, valueDec Decoder, structName, fieldName string) *mapDecoder {
    23  	return &mapDecoder{
    24  		mapType:                 mapType,
    25  		keyDecoder:              keyDec,
    26  		keyType:                 keyType,
    27  		canUseAssignFaststrType: canUseAssignFaststrType(keyType, valueType),
    28  		valueType:               valueType,
    29  		valueDecoder:            valueDec,
    30  		structName:              structName,
    31  		fieldName:               fieldName,
    32  	}
    33  }
    34  
    35  const (
    36  	mapMaxElemSize = 128
    37  )
    38  
    39  // See detail: https://git.gammaspectra.live/P2Pool/go-json/pull/283
    40  func canUseAssignFaststrType(key *runtime.Type, value *runtime.Type) bool {
    41  	indirectElem := value.Size() > mapMaxElemSize
    42  	if indirectElem {
    43  		return false
    44  	}
    45  	return key.Kind() == reflect.String
    46  }
    47  
    48  //go:linkname makemap reflect.makemap
    49  func makemap(*runtime.Type, int) unsafe.Pointer
    50  
    51  //nolint:golint
    52  //go:linkname mapassign_faststr runtime.mapassign_faststr
    53  //go:noescape
    54  func mapassign_faststr(t *runtime.Type, m unsafe.Pointer, s string) unsafe.Pointer
    55  
    56  //go:linkname mapassign reflect.mapassign
    57  //go:noescape
    58  func mapassign(t *runtime.Type, m unsafe.Pointer, k, v unsafe.Pointer)
    59  
    60  func (d *mapDecoder) mapassign(t *runtime.Type, m, k, v unsafe.Pointer) {
    61  	if d.canUseAssignFaststrType {
    62  		mapV := mapassign_faststr(t, m, *(*string)(k))
    63  		typedmemmove(d.valueType, mapV, v)
    64  	} else {
    65  		mapassign(t, m, k, v)
    66  	}
    67  }
    68  
    69  func (d *mapDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
    70  	depth++
    71  	if depth > maxDecodeNestingDepth {
    72  		return errors.ErrExceededMaxDepth(s.char(), s.cursor)
    73  	}
    74  
    75  	switch s.skipWhiteSpace() {
    76  	case 'n':
    77  		if err := nullBytes(s); err != nil {
    78  			return err
    79  		}
    80  		**(**unsafe.Pointer)(unsafe.Pointer(&p)) = nil
    81  		return nil
    82  	case '{':
    83  	default:
    84  		return errors.ErrExpected("{ character for map value", s.totalOffset())
    85  	}
    86  	mapValue := *(*unsafe.Pointer)(p)
    87  	if mapValue == nil {
    88  		mapValue = makemap(d.mapType, 0)
    89  	}
    90  	s.cursor++
    91  	if s.skipWhiteSpace() == '}' {
    92  		*(*unsafe.Pointer)(p) = mapValue
    93  		s.cursor++
    94  		return nil
    95  	}
    96  	for {
    97  		k := unsafe_New(d.keyType)
    98  		if err := d.keyDecoder.DecodeStream(s, depth, k); err != nil {
    99  			return err
   100  		}
   101  		s.skipWhiteSpace()
   102  		if !s.equalChar(':') {
   103  			return errors.ErrExpected("colon after object key", s.totalOffset())
   104  		}
   105  		s.cursor++
   106  		v := unsafe_New(d.valueType)
   107  		if err := d.valueDecoder.DecodeStream(s, depth, v); err != nil {
   108  			return err
   109  		}
   110  		d.mapassign(d.mapType, mapValue, k, v)
   111  		s.skipWhiteSpace()
   112  		if s.equalChar('}') {
   113  			**(**unsafe.Pointer)(unsafe.Pointer(&p)) = mapValue
   114  			s.cursor++
   115  			return nil
   116  		}
   117  		if !s.equalChar(',') {
   118  			return errors.ErrExpected("comma after object value", s.totalOffset())
   119  		}
   120  		s.cursor++
   121  	}
   122  }
   123  
   124  func (d *mapDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
   125  	buf := ctx.Buf
   126  	depth++
   127  	if depth > maxDecodeNestingDepth {
   128  		return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
   129  	}
   130  
   131  	cursor = skipWhiteSpace(buf, cursor)
   132  	buflen := int64(len(buf))
   133  	if buflen < 2 {
   134  		return 0, errors.ErrExpected("{} for map", cursor)
   135  	}
   136  	switch buf[cursor] {
   137  	case 'n':
   138  		if err := validateNull(buf, cursor); err != nil {
   139  			return 0, err
   140  		}
   141  		cursor += 4
   142  		**(**unsafe.Pointer)(unsafe.Pointer(&p)) = nil
   143  		return cursor, nil
   144  	case '{':
   145  	default:
   146  		return 0, errors.ErrExpected("{ character for map value", cursor)
   147  	}
   148  	cursor++
   149  	cursor = skipWhiteSpace(buf, cursor)
   150  	mapValue := *(*unsafe.Pointer)(p)
   151  	if mapValue == nil {
   152  		mapValue = makemap(d.mapType, 0)
   153  	}
   154  	if buf[cursor] == '}' {
   155  		**(**unsafe.Pointer)(unsafe.Pointer(&p)) = mapValue
   156  		cursor++
   157  		return cursor, nil
   158  	}
   159  	for {
   160  		k := unsafe_New(d.keyType)
   161  		keyCursor, err := d.keyDecoder.Decode(ctx, cursor, depth, k)
   162  		if err != nil {
   163  			return 0, err
   164  		}
   165  		cursor = skipWhiteSpace(buf, keyCursor)
   166  		if buf[cursor] != ':' {
   167  			return 0, errors.ErrExpected("colon after object key", cursor)
   168  		}
   169  		cursor++
   170  		v := unsafe_New(d.valueType)
   171  		valueCursor, err := d.valueDecoder.Decode(ctx, cursor, depth, v)
   172  		if err != nil {
   173  			return 0, err
   174  		}
   175  		d.mapassign(d.mapType, mapValue, k, v)
   176  		cursor = skipWhiteSpace(buf, valueCursor)
   177  		if buf[cursor] == '}' {
   178  			**(**unsafe.Pointer)(unsafe.Pointer(&p)) = mapValue
   179  			cursor++
   180  			return cursor, nil
   181  		}
   182  		if buf[cursor] != ',' {
   183  			return 0, errors.ErrExpected("comma after object value", cursor)
   184  		}
   185  		cursor++
   186  	}
   187  }
   188  
   189  func (d *mapDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) {
   190  	buf := ctx.Buf
   191  	depth++
   192  	if depth > maxDecodeNestingDepth {
   193  		return nil, 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
   194  	}
   195  
   196  	cursor = skipWhiteSpace(buf, cursor)
   197  	buflen := int64(len(buf))
   198  	if buflen < 2 {
   199  		return nil, 0, errors.ErrExpected("{} for map", cursor)
   200  	}
   201  	switch buf[cursor] {
   202  	case 'n':
   203  		if err := validateNull(buf, cursor); err != nil {
   204  			return nil, 0, err
   205  		}
   206  		cursor += 4
   207  		return [][]byte{nullbytes}, cursor, nil
   208  	case '{':
   209  	default:
   210  		return nil, 0, errors.ErrExpected("{ character for map value", cursor)
   211  	}
   212  	cursor++
   213  	cursor = skipWhiteSpace(buf, cursor)
   214  	if buf[cursor] == '}' {
   215  		cursor++
   216  		return nil, cursor, nil
   217  	}
   218  	keyDecoder, ok := d.keyDecoder.(*stringDecoder)
   219  	if !ok {
   220  		return nil, 0, &errors.UnmarshalTypeError{
   221  			Value:  "string",
   222  			Type:   reflect.TypeOf(""),
   223  			Offset: cursor,
   224  			Struct: d.structName,
   225  			Field:  d.fieldName,
   226  		}
   227  	}
   228  	ret := [][]byte{}
   229  	for {
   230  		key, keyCursor, err := keyDecoder.decodeByte(buf, cursor)
   231  		if err != nil {
   232  			return nil, 0, err
   233  		}
   234  		cursor = skipWhiteSpace(buf, keyCursor)
   235  		if buf[cursor] != ':' {
   236  			return nil, 0, errors.ErrExpected("colon after object key", cursor)
   237  		}
   238  		cursor++
   239  		child, found, err := ctx.Option.Path.Field(string(key))
   240  		if err != nil {
   241  			return nil, 0, err
   242  		}
   243  		if found {
   244  			if child != nil {
   245  				oldPath := ctx.Option.Path.node
   246  				ctx.Option.Path.node = child
   247  				paths, c, err := d.valueDecoder.DecodePath(ctx, cursor, depth)
   248  				if err != nil {
   249  					return nil, 0, err
   250  				}
   251  				ctx.Option.Path.node = oldPath
   252  				ret = append(ret, paths...)
   253  				cursor = c
   254  			} else {
   255  				start := cursor
   256  				end, err := skipValue(buf, cursor, depth)
   257  				if err != nil {
   258  					return nil, 0, err
   259  				}
   260  				ret = append(ret, buf[start:end])
   261  				cursor = end
   262  			}
   263  		} else {
   264  			c, err := skipValue(buf, cursor, depth)
   265  			if err != nil {
   266  				return nil, 0, err
   267  			}
   268  			cursor = c
   269  		}
   270  		cursor = skipWhiteSpace(buf, cursor)
   271  		if buf[cursor] == '}' {
   272  			cursor++
   273  			return ret, cursor, nil
   274  		}
   275  		if buf[cursor] != ',' {
   276  			return nil, 0, errors.ErrExpected("comma after object value", cursor)
   277  		}
   278  		cursor++
   279  	}
   280  }