// 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 }
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()) }
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) }
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{} }
// 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 }
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()}) } }
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 }
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() }
// 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()) }
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) } } }
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()}) }
// 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 }
// 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 }
// 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()) }
// 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) } } }
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()}) } }
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()) }
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 }
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()}) } }
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()}) } }
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()}) } }
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()) }
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 }
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()) } }
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()) }
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())} }
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()) }
func isEmptyInterface(v reflect.Value) bool { return v.Kind() == reflect.Interface && v.NumMethod() == 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) } } }
// 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) } } }