github.com/3JoB/go-json@v0.10.4/internal/decoder/map.go (about)

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