You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1031 lines
27 KiB
1031 lines
27 KiB
//
|
|
// DISCLAIMER
|
|
//
|
|
// Copyright 2017 ArangoDB GmbH, Cologne, Germany
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
|
//
|
|
// Author Ewout Prangsma
|
|
//
|
|
|
|
// This code is heavily inspired by the Go sources.
|
|
// See https://golang.org/src/encoding/json/
|
|
|
|
package velocypack
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"reflect"
|
|
"runtime"
|
|
"strconv"
|
|
)
|
|
|
|
// A Decoder decodes velocypack values into Go structures.
|
|
type Decoder struct {
|
|
r io.Reader
|
|
}
|
|
|
|
// Unmarshaler is implemented by types that can convert themselves from Velocypack.
|
|
type Unmarshaler interface {
|
|
UnmarshalVPack(Slice) error
|
|
}
|
|
|
|
// NewDecoder creates a new Decoder that reads data from the given reader.
|
|
func NewDecoder(r io.Reader) *Decoder {
|
|
return &Decoder{
|
|
r: r,
|
|
}
|
|
}
|
|
|
|
// Unmarshal reads v from the given Velocypack encoded data slice.
|
|
//
|
|
// Unmarshal uses the inverse of the encodings that
|
|
// Marshal uses, allocating maps, slices, and pointers as necessary,
|
|
// with the following additional rules:
|
|
//
|
|
// To unmarshal VelocyPack into a pointer, Unmarshal first handles the case of
|
|
// the VelocyPack being the VelocyPack literal Null. In that case, Unmarshal sets
|
|
// the pointer to nil. Otherwise, Unmarshal unmarshals the VelocyPack into
|
|
// the value pointed at by the pointer. If the pointer is nil, Unmarshal
|
|
// allocates a new value for it to point to.
|
|
//
|
|
// To unmarshal VelocyPack into a value implementing the Unmarshaler interface,
|
|
// Unmarshal calls that value's UnmarshalVPack method, including
|
|
// when the input is a VelocyPack Null.
|
|
// Otherwise, if the value implements encoding.TextUnmarshaler
|
|
// and the input is a VelocyPack quoted string, Unmarshal calls that value's
|
|
// UnmarshalText method with the unquoted form of the string.
|
|
//
|
|
// To unmarshal VelocyPack into a struct, Unmarshal matches incoming object
|
|
// keys to the keys used by Marshal (either the struct field name or its tag),
|
|
// preferring an exact match but also accepting a case-insensitive match.
|
|
// Unmarshal will only set exported fields of the struct.
|
|
//
|
|
// To unmarshal VelocyPack into an interface value,
|
|
// Unmarshal stores one of these in the interface value:
|
|
//
|
|
// bool, for VelocyPack Bool's
|
|
// float64 for VelocyPack Double's
|
|
// uint64 for VelocyPack UInt's
|
|
// int64 for VelocyPack Int's
|
|
// string, for VelocyPack String's
|
|
// []interface{}, for VelocyPack Array's
|
|
// map[string]interface{}, for VelocyPack Object's
|
|
// nil for VelocyPack Null.
|
|
// []byte for VelocyPack Binary.
|
|
//
|
|
// To unmarshal a VelocyPack array into a slice, Unmarshal resets the slice length
|
|
// to zero and then appends each element to the slice.
|
|
// As a special case, to unmarshal an empty VelocyPack array into a slice,
|
|
// Unmarshal replaces the slice with a new empty slice.
|
|
//
|
|
// To unmarshal a VelocyPack array into a Go array, Unmarshal decodes
|
|
// VelocyPack array elements into corresponding Go array elements.
|
|
// If the Go array is smaller than the VelocyPack array,
|
|
// the additional VelocyPack array elements are discarded.
|
|
// If the VelocyPack array is smaller than the Go array,
|
|
// the additional Go array elements are set to zero values.
|
|
//
|
|
// To unmarshal a VelocyPack object into a map, Unmarshal first establishes a map to
|
|
// use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal
|
|
// reuses the existing map, keeping existing entries. Unmarshal then stores
|
|
// key-value pairs from the VelocyPack object into the map. The map's key type must
|
|
// either be a string, an integer, or implement encoding.TextUnmarshaler.
|
|
//
|
|
// If a VelocyPack value is not appropriate for a given target type,
|
|
// or if a VelocyPack number overflows the target type, Unmarshal
|
|
// skips that field and completes the unmarshaling as best it can.
|
|
// If no more serious errors are encountered, Unmarshal returns
|
|
// an UnmarshalTypeError describing the earliest such error.
|
|
//
|
|
// The VelocyPack Null value unmarshals into an interface, map, pointer, or slice
|
|
// by setting that Go value to nil. Because null is often used in VelocyPack to mean
|
|
// ``not present,'' unmarshaling a VelocyPack Null into any other Go type has no effect
|
|
// on the value and produces no error.
|
|
//
|
|
func Unmarshal(data Slice, v interface{}) error {
|
|
if err := unmarshalSlice(data, v); err != nil {
|
|
return WithStack(err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Decode reads v from the decoder stream.
|
|
func (e *Decoder) Decode(v interface{}) error {
|
|
s, err := SliceFromReader(e.r)
|
|
if err != nil {
|
|
return WithStack(err)
|
|
}
|
|
if err := unmarshalSlice(s, v); err != nil {
|
|
return WithStack(err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// unmarshalSlice reads v from the given slice.
|
|
func unmarshalSlice(data Slice, v interface{}) (err error) {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
if _, ok := r.(runtime.Error); ok {
|
|
panic(r)
|
|
}
|
|
err = r.(error)
|
|
}
|
|
}()
|
|
|
|
rv := reflect.ValueOf(v)
|
|
if rv.Kind() != reflect.Ptr || rv.IsNil() {
|
|
return &InvalidUnmarshalError{reflect.TypeOf(v)}
|
|
}
|
|
|
|
d := &decodeState{}
|
|
// We decode rv not rv.Elem because the Unmarshaler interface
|
|
// test must be applied at the top level of the value.
|
|
d.unmarshalValue(data, rv)
|
|
return d.savedError
|
|
}
|
|
|
|
var (
|
|
textUnmarshalerType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem()
|
|
numberType = reflect.TypeOf(json.Number(""))
|
|
)
|
|
|
|
type decodeState struct {
|
|
useNumber bool
|
|
errorContext struct { // provides context for type errors
|
|
Struct string
|
|
Field string
|
|
}
|
|
savedError error
|
|
}
|
|
|
|
// error aborts the decoding by panicking with err.
|
|
func (d *decodeState) error(err error) {
|
|
panic(d.addErrorContext(err))
|
|
}
|
|
|
|
// saveError saves the first err it is called with,
|
|
// for reporting at the end of the unmarshal.
|
|
func (d *decodeState) saveError(err error) {
|
|
if d.savedError == nil {
|
|
d.savedError = d.addErrorContext(err)
|
|
}
|
|
}
|
|
|
|
// addErrorContext returns a new error enhanced with information from d.errorContext
|
|
func (d *decodeState) addErrorContext(err error) error {
|
|
if d.errorContext.Struct != "" || d.errorContext.Field != "" {
|
|
switch err := err.(type) {
|
|
case *UnmarshalTypeError:
|
|
err.Struct = d.errorContext.Struct
|
|
err.Field = d.errorContext.Field
|
|
return err
|
|
}
|
|
}
|
|
return err
|
|
}
|
|
|
|
// unmarshalValue unmarshals any slice into given v.
|
|
func (d *decodeState) unmarshalValue(data Slice, v reflect.Value) {
|
|
if !v.IsValid() {
|
|
return
|
|
}
|
|
|
|
switch data.Type() {
|
|
case Array:
|
|
d.unmarshalArray(data, v)
|
|
case Object:
|
|
d.unmarshalObject(data, v)
|
|
case Bool, Int, SmallInt, UInt, Double, Binary, BCD, String:
|
|
d.unmarshalLiteral(data, v)
|
|
}
|
|
}
|
|
|
|
// indirect walks down v allocating pointers as needed,
|
|
// until it gets to a non-pointer.
|
|
// if it encounters an Unmarshaler, indirect stops and returns that.
|
|
// if decodingNull is true, indirect stops at the last pointer so it can be set to nil.
|
|
func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler, json.Unmarshaler, encoding.TextUnmarshaler, reflect.Value) {
|
|
// If v is a named type and is addressable,
|
|
// start with its address, so that if the type has pointer methods,
|
|
// we find them.
|
|
if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() {
|
|
v = v.Addr()
|
|
}
|
|
for {
|
|
// Load value from interface, but only if the result will be
|
|
// usefully addressable.
|
|
if v.Kind() == reflect.Interface && !v.IsNil() {
|
|
e := v.Elem()
|
|
if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) {
|
|
v = e
|
|
continue
|
|
}
|
|
}
|
|
|
|
if v.Kind() != reflect.Ptr {
|
|
break
|
|
}
|
|
|
|
if v.Elem().Kind() != reflect.Ptr && decodingNull && v.CanSet() {
|
|
break
|
|
}
|
|
if v.IsNil() {
|
|
v.Set(reflect.New(v.Type().Elem()))
|
|
}
|
|
if v.Type().NumMethod() > 0 {
|
|
if u, ok := v.Interface().(Unmarshaler); ok {
|
|
return u, nil, nil, reflect.Value{}
|
|
}
|
|
if u, ok := v.Interface().(json.Unmarshaler); ok {
|
|
return nil, u, nil, reflect.Value{}
|
|
}
|
|
if !decodingNull {
|
|
if u, ok := v.Interface().(encoding.TextUnmarshaler); ok {
|
|
return nil, nil, u, reflect.Value{}
|
|
}
|
|
}
|
|
}
|
|
v = v.Elem()
|
|
}
|
|
return nil, nil, nil, v
|
|
}
|
|
|
|
// unmarshalArray unmarshals an array slice into given v.
|
|
func (d *decodeState) unmarshalArray(data Slice, v reflect.Value) {
|
|
// Check for unmarshaler.
|
|
u, ju, ut, pv := d.indirect(v, false)
|
|
if u != nil {
|
|
if err := u.UnmarshalVPack(data); err != nil {
|
|
d.error(err)
|
|
}
|
|
return
|
|
}
|
|
if ju != nil {
|
|
json, err := data.JSONString()
|
|
if err != nil {
|
|
d.error(err)
|
|
} else {
|
|
if err := ju.UnmarshalJSON([]byte(json)); err != nil {
|
|
d.error(err)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
if ut != nil {
|
|
d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type()})
|
|
return
|
|
}
|
|
|
|
v = pv
|
|
|
|
// Check type of target.
|
|
switch v.Kind() {
|
|
case reflect.Interface:
|
|
if v.NumMethod() == 0 {
|
|
// Decoding into nil interface? Switch to non-reflect code.
|
|
v.Set(reflect.ValueOf(d.arrayInterface(data)))
|
|
return
|
|
}
|
|
// Otherwise it's invalid.
|
|
fallthrough
|
|
default:
|
|
d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type()})
|
|
return
|
|
case reflect.Array:
|
|
case reflect.Slice:
|
|
break
|
|
}
|
|
|
|
i := 0
|
|
it, err := NewArrayIterator(data)
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
for it.IsValid() {
|
|
value, err := it.Value()
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
|
|
// Get element of array, growing if necessary.
|
|
if v.Kind() == reflect.Slice {
|
|
// Grow slice if necessary
|
|
if i >= v.Cap() {
|
|
newcap := v.Cap() + v.Cap()/2
|
|
if newcap < 4 {
|
|
newcap = 4
|
|
}
|
|
newv := reflect.MakeSlice(v.Type(), v.Len(), newcap)
|
|
reflect.Copy(newv, v)
|
|
v.Set(newv)
|
|
}
|
|
if i >= v.Len() {
|
|
v.SetLen(i + 1)
|
|
}
|
|
}
|
|
|
|
if i < v.Len() {
|
|
// Decode into element.
|
|
d.unmarshalValue(value, v.Index(i))
|
|
}
|
|
i++
|
|
if err := it.Next(); err != nil {
|
|
d.error(err)
|
|
}
|
|
}
|
|
|
|
if i < v.Len() {
|
|
if v.Kind() == reflect.Array {
|
|
// Array. Zero the rest.
|
|
z := reflect.Zero(v.Type().Elem())
|
|
for ; i < v.Len(); i++ {
|
|
v.Index(i).Set(z)
|
|
}
|
|
} else {
|
|
v.SetLen(i)
|
|
}
|
|
}
|
|
if i == 0 && v.Kind() == reflect.Slice {
|
|
v.Set(reflect.MakeSlice(v.Type(), 0, 0))
|
|
}
|
|
}
|
|
|
|
// unmarshalObject unmarshals an object slice into given v.
|
|
func (d *decodeState) unmarshalObject(data Slice, v reflect.Value) {
|
|
// Check for unmarshaler.
|
|
u, ju, ut, pv := d.indirect(v, false)
|
|
if u != nil {
|
|
if err := u.UnmarshalVPack(data); err != nil {
|
|
d.error(err)
|
|
}
|
|
return
|
|
}
|
|
if ju != nil {
|
|
json, err := data.JSONString()
|
|
if err != nil {
|
|
d.error(err)
|
|
} else {
|
|
if err := ju.UnmarshalJSON([]byte(json)); err != nil {
|
|
d.error(err)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
if ut != nil {
|
|
d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type()})
|
|
return
|
|
}
|
|
v = pv
|
|
|
|
// Decoding into nil interface? Switch to non-reflect code.
|
|
if v.Kind() == reflect.Interface && v.NumMethod() == 0 {
|
|
v.Set(reflect.ValueOf(d.objectInterface(data)))
|
|
return
|
|
}
|
|
|
|
// Check type of target:
|
|
// struct or
|
|
// map[T1]T2 where T1 is string, an integer type,
|
|
// or an encoding.TextUnmarshaler
|
|
switch v.Kind() {
|
|
case reflect.Map:
|
|
// Map key must either have string kind, have an integer kind,
|
|
// or be an encoding.TextUnmarshaler.
|
|
t := v.Type()
|
|
switch t.Key().Kind() {
|
|
case reflect.String,
|
|
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
|
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
default:
|
|
if !reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) {
|
|
d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type()})
|
|
return
|
|
}
|
|
}
|
|
if v.IsNil() {
|
|
v.Set(reflect.MakeMap(t))
|
|
}
|
|
case reflect.Struct:
|
|
// ok
|
|
default:
|
|
d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type()})
|
|
return
|
|
}
|
|
|
|
var mapElem reflect.Value
|
|
|
|
it, err := NewObjectIterator(data)
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
for it.IsValid() {
|
|
key, err := it.Key(true)
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
keyUTF8, err := key.GetStringUTF8()
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
value, err := it.Value()
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
|
|
// Figure out field corresponding to key.
|
|
var subv reflect.Value
|
|
destring := false // whether the value is wrapped in a string to be decoded first
|
|
|
|
if v.Kind() == reflect.Map {
|
|
elemType := v.Type().Elem()
|
|
if !mapElem.IsValid() {
|
|
mapElem = reflect.New(elemType).Elem()
|
|
} else {
|
|
mapElem.Set(reflect.Zero(elemType))
|
|
}
|
|
subv = mapElem
|
|
} else {
|
|
var f *field
|
|
fields := cachedTypeFields(v.Type())
|
|
for i := range fields {
|
|
ff := &fields[i]
|
|
if bytes.Equal(ff.nameBytes, key) {
|
|
f = ff
|
|
break
|
|
}
|
|
if f == nil && ff.equalFold(ff.nameBytes, keyUTF8) {
|
|
f = ff
|
|
}
|
|
}
|
|
if f != nil {
|
|
subv = v
|
|
destring = f.quoted
|
|
for _, i := range f.index {
|
|
if subv.Kind() == reflect.Ptr {
|
|
if subv.IsNil() {
|
|
subv.Set(reflect.New(subv.Type().Elem()))
|
|
}
|
|
subv = subv.Elem()
|
|
}
|
|
subv = subv.Field(i)
|
|
}
|
|
d.errorContext.Field = f.name
|
|
d.errorContext.Struct = v.Type().Name()
|
|
}
|
|
}
|
|
|
|
if destring {
|
|
// Value should be a string that we'll decode as JSON
|
|
valueUTF8, err := value.GetStringUTF8()
|
|
if err != nil {
|
|
d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, expected string, got %s in %v (%v)", value.Type(), subv.Type(), err))
|
|
}
|
|
v, err := ParseJSONFromUTF8(valueUTF8)
|
|
if err != nil {
|
|
d.saveError(err)
|
|
} else {
|
|
d.unmarshalValue(v, subv)
|
|
}
|
|
} else {
|
|
d.unmarshalValue(value, subv)
|
|
}
|
|
|
|
// Write value back to map;
|
|
// if using struct, subv points into struct already.
|
|
if v.Kind() == reflect.Map {
|
|
kt := v.Type().Key()
|
|
var kv reflect.Value
|
|
switch {
|
|
case kt.Kind() == reflect.String:
|
|
kv = reflect.ValueOf(keyUTF8).Convert(kt)
|
|
case reflect.PtrTo(kt).Implements(textUnmarshalerType):
|
|
kv = reflect.New(v.Type().Key())
|
|
d.literalStore(key, kv, true)
|
|
kv = kv.Elem()
|
|
default:
|
|
keyStr := string(keyUTF8)
|
|
switch kt.Kind() {
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
n, err := strconv.ParseInt(keyStr, 10, 64)
|
|
if err != nil || reflect.Zero(kt).OverflowInt(n) {
|
|
d.saveError(&UnmarshalTypeError{Value: "number " + keyStr, Type: kt})
|
|
return
|
|
}
|
|
kv = reflect.ValueOf(n).Convert(kt)
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
n, err := strconv.ParseUint(keyStr, 10, 64)
|
|
if err != nil || reflect.Zero(kt).OverflowUint(n) {
|
|
d.saveError(&UnmarshalTypeError{Value: "number " + keyStr, Type: kt})
|
|
return
|
|
}
|
|
kv = reflect.ValueOf(n).Convert(kt)
|
|
default:
|
|
panic("json: Unexpected key type") // should never occur
|
|
}
|
|
}
|
|
v.SetMapIndex(kv, subv)
|
|
}
|
|
|
|
d.errorContext.Struct = ""
|
|
d.errorContext.Field = ""
|
|
|
|
if err := it.Next(); err != nil {
|
|
d.error(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// unmarshalLiteral unmarshals a literal slice into given v.
|
|
func (d *decodeState) unmarshalLiteral(data Slice, v reflect.Value) {
|
|
d.literalStore(data, v, false)
|
|
}
|
|
|
|
// The xxxInterface routines build up a value to be stored
|
|
// in an empty interface. They are not strictly necessary,
|
|
// but they avoid the weight of reflection in this common case.
|
|
|
|
// valueInterface is like value but returns interface{}
|
|
func (d *decodeState) valueInterface(data Slice) interface{} {
|
|
switch data.Type() {
|
|
case Array:
|
|
return d.arrayInterface(data)
|
|
case Object:
|
|
return d.objectInterface(data)
|
|
default:
|
|
return d.literalInterface(data)
|
|
}
|
|
}
|
|
|
|
// arrayInterface is like array but returns []interface{}.
|
|
func (d *decodeState) arrayInterface(data Slice) []interface{} {
|
|
l, err := data.Length()
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
v := make([]interface{}, 0, l)
|
|
it, err := NewArrayIterator(data)
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
for it.IsValid() {
|
|
value, err := it.Value()
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
|
|
v = append(v, d.valueInterface(value))
|
|
|
|
// Move to next field
|
|
if err := it.Next(); err != nil {
|
|
d.error(err)
|
|
}
|
|
}
|
|
return v
|
|
}
|
|
|
|
// objectInterface is like object but returns map[string]interface{}.
|
|
func (d *decodeState) objectInterface(data Slice) map[string]interface{} {
|
|
m := make(map[string]interface{})
|
|
it, err := NewObjectIterator(data)
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
for it.IsValid() {
|
|
key, err := it.Key(true)
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
keyStr, err := key.GetString()
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
value, err := it.Value()
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
|
|
// Read value.
|
|
m[keyStr] = d.valueInterface(value)
|
|
|
|
// Move to next field
|
|
if err := it.Next(); err != nil {
|
|
d.error(err)
|
|
}
|
|
}
|
|
return m
|
|
}
|
|
|
|
// literalInterface is like literal but returns an interface value.
|
|
func (d *decodeState) literalInterface(data Slice) interface{} {
|
|
switch data.Type() {
|
|
case Null:
|
|
return nil
|
|
|
|
case Bool:
|
|
v, err := data.GetBool()
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
return v
|
|
|
|
case String:
|
|
v, err := data.GetString()
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
return v
|
|
|
|
case Double:
|
|
v, err := data.GetDouble()
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
return v
|
|
|
|
case Int, SmallInt:
|
|
v, err := data.GetInt()
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
intV := int(v)
|
|
if int64(intV) == v {
|
|
// Value fits in int
|
|
return intV
|
|
}
|
|
return v
|
|
|
|
case UInt:
|
|
v, err := data.GetUInt()
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
return v
|
|
|
|
case Binary:
|
|
v, err := data.GetBinary()
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
return v
|
|
|
|
default: // ??
|
|
d.error(fmt.Errorf("unknown literal type: %s", data.Type()))
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// literalStore decodes a literal stored in item into v.
|
|
//
|
|
// fromQuoted indicates whether this literal came from unwrapping a
|
|
// string from the ",string" struct tag option. this is used only to
|
|
// produce more helpful error messages.
|
|
func (d *decodeState) literalStore(item Slice, v reflect.Value, fromQuoted bool) {
|
|
// Check for unmarshaler.
|
|
if len(item) == 0 {
|
|
//Empty string given
|
|
d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal empty slice into %v", v.Type()))
|
|
return
|
|
}
|
|
isNull := item.IsNull() // null
|
|
u, ju, ut, pv := d.indirect(v, isNull)
|
|
if u != nil {
|
|
if err := u.UnmarshalVPack(item); err != nil {
|
|
d.error(err)
|
|
}
|
|
return
|
|
}
|
|
if ju != nil {
|
|
json, err := item.JSONString()
|
|
if err != nil {
|
|
d.error(err)
|
|
} else {
|
|
if err := ju.UnmarshalJSON([]byte(json)); err != nil {
|
|
d.error(err)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
if ut != nil {
|
|
if !item.IsString() {
|
|
//if item[0] != '"' {
|
|
if fromQuoted {
|
|
d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal Slice of type %s into %v", item.Type(), v.Type()))
|
|
} else {
|
|
val := item.Type().String()
|
|
d.saveError(&UnmarshalTypeError{Value: val, Type: v.Type()})
|
|
}
|
|
return
|
|
}
|
|
s, err := item.GetStringUTF8()
|
|
if err != nil {
|
|
if fromQuoted {
|
|
d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal slice of type %s into %v", item.Type(), v.Type()))
|
|
} else {
|
|
d.error(InternalError) // Out of sync
|
|
}
|
|
}
|
|
if err := ut.UnmarshalText(s); err != nil {
|
|
d.error(err)
|
|
}
|
|
return
|
|
}
|
|
|
|
v = pv
|
|
|
|
switch item.Type() {
|
|
case Null: // null
|
|
// The main parser checks that only true and false can reach here,
|
|
// but if this was a quoted string input, it could be anything.
|
|
if fromQuoted /*&& string(item) != "null"*/ {
|
|
d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
|
|
break
|
|
}
|
|
switch v.Kind() {
|
|
case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
|
|
v.Set(reflect.Zero(v.Type()))
|
|
// otherwise, ignore null for primitives/string
|
|
}
|
|
case Bool: // true, false
|
|
value, err := item.GetBool()
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
// The main parser checks that only true and false can reach here,
|
|
// but if this was a quoted string input, it could be anything.
|
|
if fromQuoted /*&& string(item) != "true" && string(item) != "false"*/ {
|
|
d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
|
|
break
|
|
}
|
|
switch v.Kind() {
|
|
default:
|
|
if fromQuoted {
|
|
d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
|
|
} else {
|
|
d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type()})
|
|
}
|
|
case reflect.Bool:
|
|
v.SetBool(value)
|
|
case reflect.Interface:
|
|
if v.NumMethod() == 0 {
|
|
v.Set(reflect.ValueOf(value))
|
|
} else {
|
|
d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type()})
|
|
}
|
|
}
|
|
|
|
case String: // string
|
|
s, err := item.GetString()
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
switch v.Kind() {
|
|
default:
|
|
d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type()})
|
|
case reflect.Slice:
|
|
if v.Type().Elem().Kind() != reflect.Uint8 {
|
|
d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type()})
|
|
break
|
|
}
|
|
b, err := base64.StdEncoding.DecodeString(s)
|
|
if err != nil {
|
|
d.saveError(err)
|
|
break
|
|
}
|
|
v.SetBytes(b)
|
|
case reflect.String:
|
|
v.SetString(string(s))
|
|
case reflect.Interface:
|
|
if v.NumMethod() == 0 {
|
|
v.Set(reflect.ValueOf(string(s)))
|
|
} else {
|
|
d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type()})
|
|
}
|
|
}
|
|
|
|
case Double:
|
|
value, err := item.GetDouble()
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
switch v.Kind() {
|
|
default:
|
|
if v.Kind() == reflect.String && v.Type() == numberType {
|
|
s, err := item.JSONString()
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
v.SetString(s)
|
|
break
|
|
}
|
|
if fromQuoted {
|
|
d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
|
|
} else {
|
|
d.error(&UnmarshalTypeError{Value: "number", Type: v.Type()})
|
|
}
|
|
case reflect.Interface:
|
|
n, err := d.convertNumber(value)
|
|
if err != nil {
|
|
d.saveError(err)
|
|
break
|
|
}
|
|
if v.NumMethod() != 0 {
|
|
d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type()})
|
|
break
|
|
}
|
|
v.Set(reflect.ValueOf(n))
|
|
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
n := int64(value)
|
|
if err != nil || v.OverflowInt(n) {
|
|
d.saveError(&UnmarshalTypeError{Value: fmt.Sprintf("number %v", value), Type: v.Type()})
|
|
break
|
|
}
|
|
v.SetInt(n)
|
|
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
n := uint64(value)
|
|
if err != nil || v.OverflowUint(n) {
|
|
d.saveError(&UnmarshalTypeError{Value: fmt.Sprintf("number %v", value), Type: v.Type()})
|
|
break
|
|
}
|
|
v.SetUint(n)
|
|
|
|
case reflect.Float32, reflect.Float64:
|
|
n := value
|
|
v.SetFloat(n)
|
|
}
|
|
|
|
case Int, SmallInt:
|
|
value, err := item.GetInt()
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
switch v.Kind() {
|
|
default:
|
|
if v.Kind() == reflect.String && v.Type() == numberType {
|
|
s, err := item.JSONString()
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
v.SetString(s)
|
|
break
|
|
}
|
|
if fromQuoted {
|
|
d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
|
|
} else {
|
|
d.error(&UnmarshalTypeError{Value: "number", Type: v.Type()})
|
|
}
|
|
case reflect.Interface:
|
|
var n interface{}
|
|
intValue := int(value)
|
|
if int64(intValue) == value {
|
|
// When the value fits in an int, use int type.
|
|
n, err = d.convertNumber(intValue)
|
|
} else {
|
|
n, err = d.convertNumber(value)
|
|
}
|
|
if err != nil {
|
|
d.saveError(err)
|
|
break
|
|
}
|
|
if v.NumMethod() != 0 {
|
|
d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type()})
|
|
break
|
|
}
|
|
v.Set(reflect.ValueOf(n))
|
|
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
n := value
|
|
if err != nil || v.OverflowInt(n) {
|
|
d.saveError(&UnmarshalTypeError{Value: fmt.Sprintf("number %v", value), Type: v.Type()})
|
|
break
|
|
}
|
|
v.SetInt(n)
|
|
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
n := uint64(value)
|
|
if err != nil || v.OverflowUint(n) {
|
|
d.saveError(&UnmarshalTypeError{Value: fmt.Sprintf("number %v", value), Type: v.Type()})
|
|
break
|
|
}
|
|
v.SetUint(n)
|
|
|
|
case reflect.Float32, reflect.Float64:
|
|
n := float64(value)
|
|
if err != nil || v.OverflowFloat(n) {
|
|
d.saveError(&UnmarshalTypeError{Value: fmt.Sprintf("number %v", value), Type: v.Type()})
|
|
break
|
|
}
|
|
v.SetFloat(n)
|
|
}
|
|
|
|
case UInt:
|
|
value, err := item.GetUInt()
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
switch v.Kind() {
|
|
default:
|
|
if v.Kind() == reflect.String && v.Type() == numberType {
|
|
s, err := item.JSONString()
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
v.SetString(s)
|
|
break
|
|
}
|
|
if fromQuoted {
|
|
d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
|
|
} else {
|
|
d.error(&UnmarshalTypeError{Value: "number", Type: v.Type()})
|
|
}
|
|
case reflect.Interface:
|
|
n, err := d.convertNumber(value)
|
|
if err != nil {
|
|
d.saveError(err)
|
|
break
|
|
}
|
|
if v.NumMethod() != 0 {
|
|
d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type()})
|
|
break
|
|
}
|
|
v.Set(reflect.ValueOf(n))
|
|
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
n := int64(value)
|
|
if err != nil || v.OverflowInt(n) {
|
|
d.saveError(&UnmarshalTypeError{Value: fmt.Sprintf("number %v", value), Type: v.Type()})
|
|
break
|
|
}
|
|
v.SetInt(n)
|
|
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
n := value
|
|
if err != nil || v.OverflowUint(n) {
|
|
d.saveError(&UnmarshalTypeError{Value: fmt.Sprintf("number %v", value), Type: v.Type()})
|
|
break
|
|
}
|
|
v.SetUint(n)
|
|
|
|
case reflect.Float32, reflect.Float64:
|
|
n := float64(value)
|
|
if err != nil || v.OverflowFloat(n) {
|
|
d.saveError(&UnmarshalTypeError{Value: fmt.Sprintf("number %v", value), Type: v.Type()})
|
|
break
|
|
}
|
|
v.SetFloat(n)
|
|
}
|
|
|
|
case Binary:
|
|
value, err := item.GetBinary()
|
|
if err != nil {
|
|
d.error(err)
|
|
}
|
|
switch v.Kind() {
|
|
default:
|
|
d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type()})
|
|
case reflect.Slice:
|
|
if v.Type().Elem().Kind() != reflect.Uint8 {
|
|
d.saveError(&UnmarshalTypeError{Value: "binary", Type: v.Type()})
|
|
break
|
|
}
|
|
v.SetBytes(value)
|
|
case reflect.Interface:
|
|
if v.NumMethod() == 0 {
|
|
v.Set(reflect.ValueOf(value))
|
|
} else {
|
|
d.saveError(&UnmarshalTypeError{Value: "binary", Type: v.Type()})
|
|
}
|
|
}
|
|
|
|
default: // number
|
|
d.error(fmt.Errorf("Unknown type %s", item.Type()))
|
|
}
|
|
}
|
|
|
|
// convertNumber converts the number literal s to a float64 or a Number
|
|
// depending on the setting of d.useNumber.
|
|
func (d *decodeState) convertNumber(s interface{}) (interface{}, error) {
|
|
if d.useNumber {
|
|
return json.Number(fmt.Sprintf("%v", s)), nil
|
|
}
|
|
return s, nil
|
|
}
|
|
|