예제 #1
0
// overwriteFields replaces configuration values with alternate values specified
// through the environment. Precondition: an empty path slice must never be
// passed in.
func (p *Parser) overwriteFields(v reflect.Value, fullpath string, path []string, payload string) error {
	for v.Kind() == reflect.Ptr {
		if v.IsNil() {
			panic("encountered nil pointer while handling environment variable " + fullpath)
		}
		v = reflect.Indirect(v)
	}
	switch v.Kind() {
	case reflect.Struct:
		return p.overwriteStruct(v, fullpath, path, payload)
	case reflect.Map:
		return p.overwriteMap(v, fullpath, path, payload)
	case reflect.Interface:
		if v.NumMethod() == 0 {
			if !v.IsNil() {
				return p.overwriteFields(v.Elem(), fullpath, path, payload)
			}
			// Interface was empty; create an implicit map
			var template map[string]interface{}
			wrappedV := reflect.MakeMap(reflect.TypeOf(template))
			v.Set(wrappedV)
			return p.overwriteMap(wrappedV, fullpath, path, payload)
		}
	}
	return nil
}
예제 #2
0
func (d *decoder) unmarshalUint(size uint, offset uint, result reflect.Value, uintType uint) (uint, error) {
	if size > uintType/8 {
		return 0, newInvalidDatabaseError("the MaxMind DB file's data section contains bad data (uint%v size of %v)", uintType, size)
	}

	value, newOffset, err := d.decodeUint(size, offset)
	if err != nil {
		return 0, err
	}

	switch result.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		n := int64(value)
		if !result.OverflowInt(n) {
			result.SetInt(n)
			return newOffset, nil
		}
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		if !result.OverflowUint(value) {
			result.SetUint(value)
			return newOffset, nil
		}
	case reflect.Interface:
		if result.NumMethod() == 0 {
			result.Set(reflect.ValueOf(value))
			return newOffset, nil
		}
	}
	return newOffset, newUnmarshalTypeError(value, result.Type())
}
예제 #3
0
func (c *Config) configureInterface(v, config reflect.Value, path string) error {
	// nil interface
	if v.NumMethod() == 0 {
		v.Set(config)
		return nil
	}

	tk := mapIndex(config, typeKey)
	if !tk.IsValid() {
		return &ConfigValueError{path, "missing the type element"}
	}
	if tk.Kind() != reflect.String {
		return &ConfigValueError{path, "type must be a string"}
	}

	builder, ok := c.types[tk.String()]
	if !ok {
		return &ConfigValueError{path, fmt.Sprintf("type %q is unknown", tk.String())}
	}

	object := builder.Call([]reflect.Value{})[0]

	s := indirect(object)
	if !s.Addr().Type().Implements(v.Type()) {
		return &ConfigValueError{path, fmt.Sprintf("%v does not implement %v", s.Type(), v.Type())}
	}
	v.Set(object)

	return c.configureStruct(s, config, path)
}
예제 #4
0
func Indirect(rv reflect.Value) (encoding.TextUnmarshaler, reflect.Value) {
	if rv.Kind() != reflect.Ptr && rv.Type().Name() != "" && rv.CanAddr() {
		rv = rv.Addr()
	}
	for {
		// rv is an non-nil interface
		if rv.Kind() == reflect.Interface && !rv.IsNil() {
			if e := rv.Elem(); e.Kind() == reflect.Ptr && !e.IsNil() {
				rv = e
			}
		}

		// rv is not a pointer
		if rv.Kind() != reflect.Ptr {
			break
		}

		// rv is a pointer
		if rv.IsNil() {
			rv.Set(reflect.New(rv.Type()))
		}
		if rv.NumMethod() > 0 {
			if um, ok := rv.Interface().(encoding.TextUnmarshaler); ok {
				return um, reflect.Value{}
			}
		}
		rv = rv.Elem()
	}
	return nil, reflect.Value{}
}
예제 #5
0
파일: dump.go 프로젝트: yinyuefengyi/spirv
// dumpStringer checks if rv implements the Stringer interface.
// If so, String() is called and its output logged.
// Returns false if this fails.
func dumpStringer(rv reflect.Value, prefix, indent string) bool {
	if rv.NumMethod() == 0 {
		return false
	}

	method, ok := rv.Type().MethodByName("String")
	if !ok {
		return false
	}

	mt := method.Type
	if mt.NumOut() != 1 {
		return false
	}

	if mt.Out(0).Kind() != reflect.String {
		return false
	}

	ret := method.Func.Call([]reflect.Value{rv})
	if len(ret) == 0 {
		return false
	}

	fmt.Printf("%s%s%v\n", indent, prefix, ret[0])
	return true
}
예제 #6
0
파일: decode.go 프로젝트: kezhuw/toml
func unmarshalInteger(i int64, v reflect.Value) {
	switch v.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		if v.OverflowInt(i) {
			panic(&UnmarshalOverflowError{"integer " + strconv.FormatInt(i, 10), v.Type()})
		}
		v.SetInt(i)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		if i < 0 {
			panic(&UnmarshalOverflowError{"integer " + strconv.FormatInt(i, 10), v.Type()})
		}
		u := uint64(i)
		if v.OverflowUint(u) {
			panic(&UnmarshalOverflowError{"integer " + strconv.FormatUint(u, 10), v.Type()})
		}
		v.SetUint(u)
	case reflect.Interface:
		if v.NumMethod() == 0 {
			v.Set(reflect.ValueOf(i))
			return
		}
		fallthrough
	default:
		panic(&UnmarshalTypeError{"integer " + strconv.FormatInt(i, 10), v.Type()})
	}
}
예제 #7
0
파일: decode.go 프로젝트: kezhuw/toml
func indirectValue(v reflect.Value) (encoding.TextUnmarshaler, reflect.Value) {
	if v.Kind() != reflect.Ptr && v.CanAddr() {
		v = v.Addr()
	}
	var u encoding.TextUnmarshaler
	for {
		if v.Kind() == reflect.Interface && !v.IsNil() {
			e := v.Elem()
			if e.Kind() == reflect.Ptr && !e.IsNil() {
				v = e
				continue
			}
		}
		if v.Kind() != reflect.Ptr {
			break
		}
		if v.IsNil() {
			v.Set(reflect.New(v.Type().Elem()))
		}
		if v.NumMethod() > 0 {
			// TOML has native Datetime support, while time.Time implements
			// encoding.TextUnmarshaler. For native Datetime, we need settable
			// time.Time struct, so continue here.
			if i, ok := v.Interface().(encoding.TextUnmarshaler); ok {
				u = i
			}
		}
		v = v.Elem()
	}
	return u, v
}
예제 #8
0
파일: decode.go 프로젝트: hail100/cli
func (d *Decoder) mapping(v reflect.Value) {
	u, pv := d.indirect(v)
	if u != nil {
		defer func() {
			if err := u.UnmarshalYAML("!!map", pv.Interface()); err != nil {
				d.error(err)
			}
		}()
		_, pv = d.indirect(pv)
	}
	v = pv

	// Decoding into nil interface?  Switch to non-reflect code.
	if v.Kind() == reflect.Interface && v.NumMethod() == 0 {
		v.Set(reflect.ValueOf(d.mappingInterface()))
		return
	}

	// Check type of target: struct or map[X]Y
	switch v.Kind() {
	case reflect.Struct:
		d.mappingStruct(v)
		return
	case reflect.Map:
	default:
		d.error(errors.New("mapping: invalid type: " + v.Type().String()))
	}

	mapt := v.Type()
	if v.IsNil() {
		v.Set(reflect.MakeMap(mapt))
	}

	d.nextEvent()

	keyt := mapt.Key()
	mapElemt := mapt.Elem()

	var mapElem reflect.Value
	for {
		if d.event.event_type == yaml_MAPPING_END_EVENT {
			break
		}
		key := reflect.New(keyt)
		d.parse(key.Elem())

		if !mapElem.IsValid() {
			mapElem = reflect.New(mapElemt).Elem()
		} else {
			mapElem.Set(reflect.Zero(mapElemt))
		}

		d.parse(mapElem)

		v.SetMapIndex(key.Elem(), mapElem)
	}

	d.nextEvent()
}
예제 #9
0
// unify performs a sort of type unification based on the structure of `rv`,
// which is the client representation.
//
// Any type mismatch produces an error. Finding a type that we don't know
// how to handle produces an unsupported type error.
func unify(data interface{}, rv reflect.Value) error {
	// Special case. Look for a `Primitive` value.
	if rv.Type() == reflect.TypeOf((*Primitive)(nil)).Elem() {
		return unifyAnything(data, rv)
	}

	// Special case. Look for a value satisfying the TextUnmarshaler interface.
	if v, ok := rv.Interface().(TextUnmarshaler); ok {
		return unifyText(data, v)
	}
	// BUG(burntsushi)
	// The behavior here is incorrect whenever a Go type satisfies the
	// encoding.TextUnmarshaler interface but also corresponds to a TOML
	// hash or array. In particular, the unmarshaler should only be applied
	// to primitive TOML values. But at this point, it will be applied to
	// all kinds of values and produce an incorrect error whenever those values
	// are hashes or arrays (including arrays of tables).

	k := rv.Kind()

	// laziness
	if k >= reflect.Int && k <= reflect.Uint64 {
		return unifyInt(data, rv)
	}
	switch k {
	case reflect.Ptr:
		elem := reflect.New(rv.Type().Elem())
		err := unify(data, reflect.Indirect(elem))
		if err != nil {
			return err
		}
		rv.Set(elem)
		return nil
	case reflect.Struct:
		return unifyStruct(data, rv)
	case reflect.Map:
		return unifyMap(data, rv)
	case reflect.Array:
		return unifyArray(data, rv)
	case reflect.Slice:
		return unifySlice(data, rv)
	case reflect.String:
		return unifyString(data, rv)
	case reflect.Bool:
		return unifyBool(data, rv)
	case reflect.Interface:
		// we only support empty interfaces.
		if rv.NumMethod() > 0 {
			return e("Unsupported type '%s'.", rv.Kind())
		}
		return unifyAnything(data, rv)
	case reflect.Float32:
		fallthrough
	case reflect.Float64:
		return unifyFloat64(data, rv)
	}
	return e("Unsupported type '%s'.", rv.Kind())
}
예제 #10
0
파일: scrub.go 프로젝트: GregWilson/kite
func (s *Scrubber) collectMethods(v reflect.Value, path Path, callbackMap map[string]Path) {
	for i := 0; i < v.NumMethod(); i++ {
		if v.Type().Method(i).PkgPath == "" { // exported
			name := v.Type().Method(i).Name
			name = strings.ToLower(name[0:1]) + name[1:]
			s.registerCallback(v.Method(i), append(path, name), callbackMap)
		}
	}
}
예제 #11
0
파일: decode.go 프로젝트: kezhuw/toml
func unmarshalString(s string, v reflect.Value, options tagOptions) {
	u, v := indirectValue(v)
	if u != nil {
		err := u.UnmarshalText([]byte(s))
		if err != nil {
			panic(err)
		}
		if v.Type().ConvertibleTo(datetimeType) {
			t := v.Addr().Convert(reflect.PtrTo(datetimeType)).Interface().(*time.Time)
			if t.IsZero() {
				*t = time.Time{}
			}
		}
		return
	}
	switch v.Kind() {
	case reflect.String:
		if options.Has("string") {
			t, err := strconv.Unquote(s)
			if err != nil {
				panic(err)
			}
			v.SetString(t)
			break
		}
		v.SetString(s)
	case reflect.Slice:
		if v.Type().Elem().Kind() != reflect.Uint8 {
			goto typeError
		}
		b := make([]byte, base64.StdEncoding.DecodedLen(len(s)))
		n, err := base64.StdEncoding.Decode(b, []byte(s))
		if err != nil {
			panic(err)
		}
		v.SetBytes(b[:n])
	case reflect.Bool,
		reflect.Float32, reflect.Float64,
		reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		if !options.Has("string") {
			goto typeError
		}
		unmarshalQuoted(s, v)
	case reflect.Interface:
		if v.NumMethod() != 0 {
			goto typeError
		}
		v.Set(reflect.ValueOf(s))
	default:
		goto typeError
	}
	return
typeError:
	panic(&UnmarshalTypeError{fmt.Sprintf("string: %q", s), v.Type()})
}
예제 #12
0
파일: decode.go 프로젝트: nsf/libtorgo
// returns true if there was a value and it's now stored in 'v', otherwise there
// was an end symbol ("e") and no value was stored
func (d *decoder) parse_value(v reflect.Value) bool {
	// we support one level of indirection at the moment
	if v.Kind() == reflect.Ptr {
		// if the pointer is nil, allocate a new element of the type it
		// points to
		if v.IsNil() {
			v.Set(reflect.New(v.Type().Elem()))
		}
		v = v.Elem()
	}

	if d.parse_unmarshaler(v) {
		return true
	}

	// common case: interface{}
	if v.Kind() == reflect.Interface && v.NumMethod() == 0 {
		iface, _ := d.parse_value_interface()
		v.Set(reflect.ValueOf(iface))
		return true
	}

	b, err := d.ReadByte()
	if err != nil {
		panic(err)
	}
	d.offset++

	switch b {
	case 'e':
		return false
	case 'd':
		d.parse_dict(v)
	case 'l':
		d.parse_list(v)
	case 'i':
		d.parse_int(v)
	default:
		if b >= '0' && b <= '9' {
			// string
			// append first digit of the length to the buffer
			d.buf.WriteByte(b)
			d.parse_string(v)
			break
		}

		// unknown value
		panic(&SyntaxError{
			Offset: d.offset - 1,
			what:   "unknown value type (invalid bencode?)",
		})
	}

	return true
}
예제 #13
0
// indirect is taken from 'text/template/exec.go'
func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
	for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
		if v.IsNil() {
			return v, true
		}
		if v.Kind() == reflect.Interface && v.NumMethod() > 0 {
			break
		}
	}
	return v, false
}
예제 #14
0
파일: decode.go 프로젝트: kplimack/gh-keys
// unify performs a sort of type unification based on the structure of `rv`,
// which is the client representation.
//
// Any type mismatch produces an error. Finding a type that we don't know
// how to handle produces an unsupported type error.
func unify(data interface{}, rv reflect.Value) error {
	// Special case. Look for a `Primitive` value.
	if rv.Type() == reflect.TypeOf((*Primitive)(nil)).Elem() {
		return unifyAnything(data, rv)
	}

	// Special case. Go's `time.Time` is a struct, which we don't want
	// to confuse with a user struct.
	if rv.Type().AssignableTo(rvalue(time.Time{}).Type()) {
		return unifyDatetime(data, rv)
	}

	k := rv.Kind()

	// laziness
	if k >= reflect.Int && k <= reflect.Uint64 {
		return unifyInt(data, rv)
	}
	switch k {
	case reflect.Ptr:
		elem := reflect.New(rv.Type().Elem())
		err := unify(data, reflect.Indirect(elem))
		if err != nil {
			return err
		}
		rv.Set(elem)
		return nil
	case reflect.Struct:
		return unifyStruct(data, rv)
	case reflect.Map:
		return unifyMap(data, rv)
	case reflect.Slice:
		return unifySlice(data, rv)
	case reflect.String:
		return unifyString(data, rv)
	case reflect.Bool:
		return unifyBool(data, rv)
	case reflect.Interface:
		// we only support empty interfaces.
		if rv.NumMethod() > 0 {
			return e("Unsupported type '%s'.", rv.Kind())
		}
		return unifyAnything(data, rv)
	case reflect.Float32:
		fallthrough
	case reflect.Float64:
		return unifyFloat64(data, rv)
	}
	return e("Unsupported type '%s'.", rv.Kind())
}
예제 #15
0
파일: scrub.go 프로젝트: yonglehou/kite
// methods walks over a structure and scrubs its exported methods.
func (s *Scrubber) methods(rv reflect.Value, path Path, callbacks map[string]Path) {
	for i := 0; i < rv.NumMethod(); i++ {
		if rv.Type().Method(i).PkgPath == "" { // exported
			cb, ok := rv.Method(i).Interface().(func(*Partial))
			if !ok {
				continue
			}

			name := rv.Type().Method(i).Name
			name = strings.ToLower(name[0:1]) + name[1:]
			s.register(cb, append(path, name), callbacks)
		}
	}
}
예제 #16
0
파일: decode.go 프로젝트: kezhuw/toml
func unmarshalBoolean(b bool, v reflect.Value) {
	switch v.Kind() {
	case reflect.Bool:
		v.SetBool(b)
	case reflect.Interface:
		if v.NumMethod() == 0 {
			v.Set(reflect.ValueOf(b))
			return
		}
		fallthrough
	default:
		panic(&UnmarshalTypeError{"boolean " + strconv.FormatBool(b), v.Type()})
	}
}
예제 #17
0
func (d *decoder) unmarshalSlice(size uint, offset uint, result reflect.Value) (uint, error) {
	switch result.Kind() {
	case reflect.Slice:
		return d.decodeSlice(size, offset, result)
	case reflect.Interface:
		if result.NumMethod() == 0 {
			a := []interface{}{}
			rv := reflect.ValueOf(&a).Elem()
			newOffset, err := d.decodeSlice(size, offset, rv)
			result.Set(rv)
			return newOffset, err
		}
	}
	return 0, newUnmarshalTypeError("array", result.Type())
}
예제 #18
0
func getAllowed(vResourcePtr *reflect.Value) (allowed []string) {
	for i := 0; i < vResourcePtr.NumMethod(); i++ {
		method := vResourcePtr.Type().Method(i)
		if method.PkgPath == "" && method.Type.NumIn() == 1 && method.Type.NumOut() == 1 &&
			method.Type.Out(0).Name() == "" && method.Name != "Pre" {
			if method.Name == "Get" {
				allowed = append(allowed, "HEAD")
				allowed = append(allowed, "GET")
			} else {
				allowed = append(allowed, strings.ToUpper(method.Name))
			}
		}
	}
	return
}
예제 #19
0
파일: decode.go 프로젝트: kezhuw/toml
func unmarshalArray(a *types.Array, v reflect.Value) {
	switch v.Kind() {
	case reflect.Array:
		unmarshalGoArray(a, v)
	case reflect.Slice:
		unmarshalSlice(a, v)
	case reflect.Interface:
		if v.NumMethod() == 0 {
			v.Set(reflect.ValueOf(a.Interface()))
			return
		}
		fallthrough
	default:
		panic(&UnmarshalTypeError{"array", v.Type()})
	}
}
예제 #20
0
파일: decode.go 프로젝트: kezhuw/toml
func unmarshalTable(t *types.Table, v reflect.Value) {
	switch v.Kind() {
	case reflect.Map:
		unmarshalMap(t, v)
	case reflect.Struct:
		unmarshalStruct(t, v)
	case reflect.Interface:
		if v.NumMethod() == 0 {
			v.Set(reflect.ValueOf(t.Interface()))
			return
		}
		fallthrough
	default:
		panic(&UnmarshalTypeError{"table", v.Type()})
	}
}
예제 #21
0
파일: decode.go 프로젝트: kezhuw/toml
func unmarshalFloat(f float64, v reflect.Value) {
	switch v.Kind() {
	case reflect.Float32, reflect.Float64:
		if v.OverflowFloat(f) {
			panic(&UnmarshalOverflowError{"float " + strconv.FormatFloat(f, 'g', -1, 64), v.Type()})
		}
		v.SetFloat(f)
	case reflect.Interface:
		if v.NumMethod() == 0 {
			v.Set(reflect.ValueOf(f))
			return
		}
		fallthrough
	default:
		panic(&UnmarshalTypeError{"float " + strconv.FormatFloat(f, 'g', -1, 64), v.Type()})
	}
}
예제 #22
0
func (d *decoder) unmarshalBytes(size uint, offset uint, result reflect.Value) (uint, error) {
	value, newOffset, err := d.decodeBytes(size, offset)
	if err != nil {
		return 0, err
	}
	switch result.Kind() {
	case reflect.Slice:
		result.SetBytes(value)
		return newOffset, nil
	case reflect.Interface:
		if result.NumMethod() == 0 {
			result.Set(reflect.ValueOf(value))
			return newOffset, nil
		}
	}
	return newOffset, newUnmarshalTypeError(value, result.Type())
}
예제 #23
0
func (c *Config) configureArray(v, config reflect.Value, path string) error {
	vkind := v.Kind()

	// nil interface
	if vkind == reflect.Interface && v.NumMethod() == 0 {
		v.Set(config)
		return nil
	}

	if vkind != reflect.Array && vkind != reflect.Slice {
		return &ConfigValueError{path, fmt.Sprintf("%v cannot be used to configure %v", config.Type(), v.Type())}
	}

	n := config.Len()

	// grow slice if it's smaller than the config array
	if vkind == reflect.Slice && v.Cap() < n {
		t := reflect.MakeSlice(v.Type(), n, n)
		reflect.Copy(t, v)
		v.Set(t)
	}

	if n > v.Cap() {
		n = v.Cap()
	}
	for i := 0; i < n; i++ {
		if err := c.configure(v.Index(i), config.Index(i), path+"."+strconv.Itoa(i)); err != nil {
			return err
		}
	}

	if n < v.Len() {
		if vkind == reflect.Array {
			// Array.  Zero the rest.
			z := reflect.Zero(v.Type().Elem())
			for i := n; i < v.Len(); i++ {
				v.Index(i).Set(z)
			}
		} else {
			v.SetLen(n)
		}
	}

	return nil
}
예제 #24
0
func (d *decoder) unmarshalMap(size uint, offset uint, result reflect.Value) (uint, error) {
	result = d.indirect(result)
	switch result.Kind() {
	default:
		return 0, newUnmarshalTypeError("map", result.Type())
	case reflect.Struct:
		return d.decodeStruct(size, offset, result)
	case reflect.Map:
		return d.decodeMap(size, offset, result)
	case reflect.Interface:
		if result.NumMethod() == 0 {
			rv := reflect.ValueOf(make(map[string]interface{}, size))
			newOffset, err := d.decodeMap(size, offset, rv)
			result.Set(rv)
			return newOffset, err
		}
		return 0, newUnmarshalTypeError("map", result.Type())
	}
}
예제 #25
0
func (d *decoder) unmarshalBool(size uint, offset uint, result reflect.Value) (uint, error) {
	if size > 1 {
		return 0, newInvalidDatabaseError("the MaxMind DB file's data section contains bad data (bool size of %v)", size)
	}
	value, newOffset, err := d.decodeBool(size, offset)
	if err != nil {
		return 0, err
	}
	switch result.Kind() {
	case reflect.Bool:
		result.SetBool(value)
		return newOffset, nil
	case reflect.Interface:
		if result.NumMethod() == 0 {
			result.Set(reflect.ValueOf(value))
			return newOffset, nil
		}
	}
	return newOffset, newUnmarshalTypeError(value, result.Type())
}
예제 #26
0
func (c *Config) configureScalar(v, config reflect.Value, path string) error {
	if !config.IsValid() {
		switch v.Kind() {
		case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
			v.Set(reflect.Zero(v.Type()))
			// otherwise, ignore null for primitives/string
		}
		return nil
	}

	// nil interface
	if v.Kind() == reflect.Interface && v.NumMethod() == 0 {
		v.Set(config)
		return nil
	}

	if config.Type().ConvertibleTo(v.Type()) {
		v.Set(config.Convert(v.Type()))
		return nil
	}

	return &ConfigValueError{path, fmt.Sprintf("%v cannot be used to configure %v", config.Type(), v.Type())}
}
예제 #27
0
func (d *decoder) unmarshalFloat64(size uint, offset uint, result reflect.Value) (uint, error) {

	if size != 8 {
		return 0, newInvalidDatabaseError("the MaxMind DB file's data section contains bad data (float 64 size of %v)", size)
	}
	value, newOffset, err := d.decodeFloat64(size, offset)
	if err != nil {
		return 0, err
	}
	switch result.Kind() {
	case reflect.Float32, reflect.Float64:
		if result.OverflowFloat(value) {
			return 0, newUnmarshalTypeError(value, result.Type())
		}
		result.SetFloat(value)
		return newOffset, nil
	case reflect.Interface:
		if result.NumMethod() == 0 {
			result.Set(reflect.ValueOf(value))
			return newOffset, nil
		}
	}
	return newOffset, newUnmarshalTypeError(value, result.Type())
}
예제 #28
0
func isEmptyInterface(v reflect.Value) bool {
	return v.Kind() == reflect.Interface && v.NumMethod() == 0
}
예제 #29
0
// 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 []byte, 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 %q into %v", item, v.Type()))
		return
	}
	wantptr := item[0] == 'n' // null
	u, ut, pv := d.indirect(v, wantptr)
	if u != nil {
		err := u.UnmarshalJSON(item)
		if err != nil {
			d.error(err)
		}
		return
	}
	if ut != nil {
		if item[0] != '"' {
			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{"string", v.Type()})
			}
		}
		s, ok := unquoteBytes(item)
		if !ok {
			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(errPhase)
			}
		}
		err := ut.UnmarshalText(s)
		if err != nil {
			d.error(err)
		}
		return
	}

	v = pv

	switch c := item[0]; c {
	case 'n': // null
		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 't', 'f': // true, false
		value := c == 't'
		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{"bool", v.Type()})
			}
		case reflect.Bool:
			v.SetBool(value)
		case reflect.Interface:
			if v.NumMethod() == 0 {
				v.Set(reflect.ValueOf(value))
			} else {
				d.saveError(&UnmarshalTypeError{"bool", v.Type()})
			}
		}

	case '"': // string
		s, ok := unquoteBytes(item)
		if !ok {
			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(errPhase)
			}
		}
		switch v.Kind() {
		default:
			d.saveError(&UnmarshalTypeError{"string", v.Type()})
		case reflect.Slice:
			if v.Type() != byteSliceType {
				d.saveError(&UnmarshalTypeError{"string", v.Type()})
				break
			}
			b := make([]byte, base64.StdEncoding.DecodedLen(len(s)))
			n, err := base64.StdEncoding.Decode(b, s)
			if err != nil {
				d.saveError(err)
				break
			}
			v.Set(reflect.ValueOf(b[0:n]))
		case reflect.String:
			v.SetString(string(s))
		case reflect.Interface:
			if v.NumMethod() == 0 {
				v.Set(reflect.ValueOf(string(s)))
			} else {
				d.saveError(&UnmarshalTypeError{"string", v.Type()})
			}
		}

	default: // number
		if c != '-' && (c < '0' || c > '9') {
			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(errPhase)
			}
		}
		s := string(item)
		switch v.Kind() {
		default:
			if v.Kind() == reflect.String && v.Type() == numberType {
				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{"number", v.Type()})
			}
		case reflect.Interface:
			n, err := d.convertNumber(s)
			if err != nil {
				d.saveError(err)
				break
			}
			if v.NumMethod() != 0 {
				d.saveError(&UnmarshalTypeError{"number", v.Type()})
				break
			}
			v.Set(reflect.ValueOf(n))

		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			n, err := strconv.ParseInt(s, 10, 64)
			if err != nil || v.OverflowInt(n) {
				d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
				break
			}
			v.SetInt(n)

		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
			n, err := strconv.ParseUint(s, 10, 64)
			if err != nil || v.OverflowUint(n) {
				d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
				break
			}
			v.SetUint(n)

		case reflect.Float32, reflect.Float64:
			n, err := strconv.ParseFloat(s, v.Type().Bits())
			if err != nil || v.OverflowFloat(n) {
				d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
				break
			}
			v.SetFloat(n)
		}
	}
}
예제 #30
0
// object consumes an object from d.data[d.off-1:], decoding into the value v.
// the first byte of the object ('{') has been read already.
func (d *decodeState) object(v reflect.Value) {
	// Check for unmarshaler.
	u, ut, pv := d.indirect(v, false)
	if u != nil {
		d.off--
		err := u.UnmarshalJSON(d.next())
		if err != nil {
			d.error(err)
		}
		return
	}
	if ut != nil {
		d.saveError(&UnmarshalTypeError{"object", v.Type()})
		d.off--
		d.next() // skip over { } in input
		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()))
		return
	}

	// Check type of target: struct or map[string]T
	switch v.Kind() {
	case reflect.Map:
		// map must have string kind
		t := v.Type()
		if t.Key().Kind() != reflect.String {
			d.saveError(&UnmarshalTypeError{"object", v.Type()})
			break
		}
		if v.IsNil() {
			v.Set(reflect.MakeMap(t))
		}
	case reflect.Struct:

	default:
		d.saveError(&UnmarshalTypeError{"object", v.Type()})
		d.off--
		d.next() // skip over { } in input
		return
	}

	var mapElem reflect.Value

	for {
		// Read opening " of string key or closing }.
		op := d.scanWhile(scanSkipSpace)
		if op == scanEndObject {
			// closing } - can only happen on first iteration.
			break
		}
		if op != scanBeginLiteral {
			d.error(errPhase)
		}

		// Read key.
		start := d.off - 1
		op = d.scanWhile(scanContinue)
		item := d.data[start : d.off-1]
		key := item
		if item[0] == '"' {
			k, ok := unquoteBytes(item)
			if !ok {
				d.error(errPhase)
			}
			key = k
		}
		if item[0] != '"' {
			key = []byte(strings.Trim(string(key), " "))
		}

		// 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, key) {
					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)
				}
			}
		}

		// Read : before value.
		if op == scanSkipSpace {
			op = d.scanWhile(scanSkipSpace)
		}
		if op != scanObjectKey {
			d.error(errPhase)
		}

		// Read value.
		if destring {
			d.value(reflect.ValueOf(&d.tempstr))
			d.literalStore([]byte(d.tempstr), subv, true)
			d.tempstr = "" // Zero scratch space for successive values.
		} else {
			d.value(subv)
		}

		// Write value back to map;
		// if using struct, subv points into struct already.
		if v.Kind() == reflect.Map {
			kv := reflect.ValueOf(key).Convert(v.Type().Key())
			v.SetMapIndex(kv, subv)
		}

		// Next token must be , or }.
		op = d.scanWhile(scanSkipSpace)
		if op == scanEndObject {
			break
		}
		if op != scanObjectValue {
			d.error(errPhase)
		}
	}
}