gopkg.in/alecthomas/gometalinter.v3@v3.0.0/_linters/src/github.com/BurntSushi/toml/decode.go (about) 1 package toml 2 3 import ( 4 "fmt" 5 "io" 6 "io/ioutil" 7 "math" 8 "reflect" 9 "strings" 10 "time" 11 ) 12 13 func e(format string, args ...interface{}) error { 14 return fmt.Errorf("toml: "+format, args...) 15 } 16 17 // Unmarshaler is the interface implemented by objects that can unmarshal a 18 // TOML description of themselves. 19 type Unmarshaler interface { 20 UnmarshalTOML(interface{}) error 21 } 22 23 // Unmarshal decodes the contents of `p` in TOML format into a pointer `v`. 24 func Unmarshal(p []byte, v interface{}) error { 25 _, err := Decode(string(p), v) 26 return err 27 } 28 29 // Primitive is a TOML value that hasn't been decoded into a Go value. 30 // When using the various `Decode*` functions, the type `Primitive` may 31 // be given to any value, and its decoding will be delayed. 32 // 33 // A `Primitive` value can be decoded using the `PrimitiveDecode` function. 34 // 35 // The underlying representation of a `Primitive` value is subject to change. 36 // Do not rely on it. 37 // 38 // N.B. Primitive values are still parsed, so using them will only avoid 39 // the overhead of reflection. They can be useful when you don't know the 40 // exact type of TOML data until run time. 41 type Primitive struct { 42 undecoded interface{} 43 context Key 44 } 45 46 // DEPRECATED! 47 // 48 // Use MetaData.PrimitiveDecode instead. 49 func PrimitiveDecode(primValue Primitive, v interface{}) error { 50 md := MetaData{decoded: make(map[string]bool)} 51 return md.unify(primValue.undecoded, rvalue(v)) 52 } 53 54 // PrimitiveDecode is just like the other `Decode*` functions, except it 55 // decodes a TOML value that has already been parsed. Valid primitive values 56 // can *only* be obtained from values filled by the decoder functions, 57 // including this method. (i.e., `v` may contain more `Primitive` 58 // values.) 59 // 60 // Meta data for primitive values is included in the meta data returned by 61 // the `Decode*` functions with one exception: keys returned by the Undecoded 62 // method will only reflect keys that were decoded. Namely, any keys hidden 63 // behind a Primitive will be considered undecoded. Executing this method will 64 // update the undecoded keys in the meta data. (See the example.) 65 func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error { 66 md.context = primValue.context 67 defer func() { md.context = nil }() 68 return md.unify(primValue.undecoded, rvalue(v)) 69 } 70 71 // Decode will decode the contents of `data` in TOML format into a pointer 72 // `v`. 73 // 74 // TOML hashes correspond to Go structs or maps. (Dealer's choice. They can be 75 // used interchangeably.) 76 // 77 // TOML arrays of tables correspond to either a slice of structs or a slice 78 // of maps. 79 // 80 // TOML datetimes correspond to Go `time.Time` values. 81 // 82 // All other TOML types (float, string, int, bool and array) correspond 83 // to the obvious Go types. 84 // 85 // An exception to the above rules is if a type implements the 86 // encoding.TextUnmarshaler interface. In this case, any primitive TOML value 87 // (floats, strings, integers, booleans and datetimes) will be converted to 88 // a byte string and given to the value's UnmarshalText method. See the 89 // Unmarshaler example for a demonstration with time duration strings. 90 // 91 // Key mapping 92 // 93 // TOML keys can map to either keys in a Go map or field names in a Go 94 // struct. The special `toml` struct tag may be used to map TOML keys to 95 // struct fields that don't match the key name exactly. (See the example.) 96 // A case insensitive match to struct names will be tried if an exact match 97 // can't be found. 98 // 99 // The mapping between TOML values and Go values is loose. That is, there 100 // may exist TOML values that cannot be placed into your representation, and 101 // there may be parts of your representation that do not correspond to 102 // TOML values. This loose mapping can be made stricter by using the IsDefined 103 // and/or Undecoded methods on the MetaData returned. 104 // 105 // This decoder will not handle cyclic types. If a cyclic type is passed, 106 // `Decode` will not terminate. 107 func Decode(data string, v interface{}) (MetaData, error) { 108 rv := reflect.ValueOf(v) 109 if rv.Kind() != reflect.Ptr { 110 return MetaData{}, e("Decode of non-pointer %s", reflect.TypeOf(v)) 111 } 112 if rv.IsNil() { 113 return MetaData{}, e("Decode of nil %s", reflect.TypeOf(v)) 114 } 115 p, err := parse(data) 116 if err != nil { 117 return MetaData{}, err 118 } 119 md := MetaData{ 120 p.mapping, p.types, p.ordered, 121 make(map[string]bool, len(p.ordered)), nil, 122 } 123 return md, md.unify(p.mapping, indirect(rv)) 124 } 125 126 // DecodeFile is just like Decode, except it will automatically read the 127 // contents of the file at `fpath` and decode it for you. 128 func DecodeFile(fpath string, v interface{}) (MetaData, error) { 129 bs, err := ioutil.ReadFile(fpath) 130 if err != nil { 131 return MetaData{}, err 132 } 133 return Decode(string(bs), v) 134 } 135 136 // DecodeReader is just like Decode, except it will consume all bytes 137 // from the reader and decode it for you. 138 func DecodeReader(r io.Reader, v interface{}) (MetaData, error) { 139 bs, err := ioutil.ReadAll(r) 140 if err != nil { 141 return MetaData{}, err 142 } 143 return Decode(string(bs), v) 144 } 145 146 // unify performs a sort of type unification based on the structure of `rv`, 147 // which is the client representation. 148 // 149 // Any type mismatch produces an error. Finding a type that we don't know 150 // how to handle produces an unsupported type error. 151 func (md *MetaData) unify(data interface{}, rv reflect.Value) error { 152 153 // Special case. Look for a `Primitive` value. 154 if rv.Type() == reflect.TypeOf((*Primitive)(nil)).Elem() { 155 // Save the undecoded data and the key context into the primitive 156 // value. 157 context := make(Key, len(md.context)) 158 copy(context, md.context) 159 rv.Set(reflect.ValueOf(Primitive{ 160 undecoded: data, 161 context: context, 162 })) 163 return nil 164 } 165 166 // Special case. Unmarshaler Interface support. 167 if rv.CanAddr() { 168 if v, ok := rv.Addr().Interface().(Unmarshaler); ok { 169 return v.UnmarshalTOML(data) 170 } 171 } 172 173 // Special case. Handle time.Time values specifically. 174 // TODO: Remove this code when we decide to drop support for Go 1.1. 175 // This isn't necessary in Go 1.2 because time.Time satisfies the encoding 176 // interfaces. 177 if rv.Type().AssignableTo(rvalue(time.Time{}).Type()) { 178 return md.unifyDatetime(data, rv) 179 } 180 181 // Special case. Look for a value satisfying the TextUnmarshaler interface. 182 if v, ok := rv.Interface().(TextUnmarshaler); ok { 183 return md.unifyText(data, v) 184 } 185 // BUG(burntsushi) 186 // The behavior here is incorrect whenever a Go type satisfies the 187 // encoding.TextUnmarshaler interface but also corresponds to a TOML 188 // hash or array. In particular, the unmarshaler should only be applied 189 // to primitive TOML values. But at this point, it will be applied to 190 // all kinds of values and produce an incorrect error whenever those values 191 // are hashes or arrays (including arrays of tables). 192 193 k := rv.Kind() 194 195 // laziness 196 if k >= reflect.Int && k <= reflect.Uint64 { 197 return md.unifyInt(data, rv) 198 } 199 switch k { 200 case reflect.Ptr: 201 elem := reflect.New(rv.Type().Elem()) 202 err := md.unify(data, reflect.Indirect(elem)) 203 if err != nil { 204 return err 205 } 206 rv.Set(elem) 207 return nil 208 case reflect.Struct: 209 return md.unifyStruct(data, rv) 210 case reflect.Map: 211 return md.unifyMap(data, rv) 212 case reflect.Array: 213 return md.unifyArray(data, rv) 214 case reflect.Slice: 215 return md.unifySlice(data, rv) 216 case reflect.String: 217 return md.unifyString(data, rv) 218 case reflect.Bool: 219 return md.unifyBool(data, rv) 220 case reflect.Interface: 221 // we only support empty interfaces. 222 if rv.NumMethod() > 0 { 223 return e("unsupported type %s", rv.Type()) 224 } 225 return md.unifyAnything(data, rv) 226 case reflect.Float32: 227 fallthrough 228 case reflect.Float64: 229 return md.unifyFloat64(data, rv) 230 } 231 return e("unsupported type %s", rv.Kind()) 232 } 233 234 func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error { 235 tmap, ok := mapping.(map[string]interface{}) 236 if !ok { 237 if mapping == nil { 238 return nil 239 } 240 return e("type mismatch for %s: expected table but found %T", 241 rv.Type().String(), mapping) 242 } 243 244 for key, datum := range tmap { 245 var f *field 246 fields := cachedTypeFields(rv.Type()) 247 for i := range fields { 248 ff := &fields[i] 249 if ff.name == key { 250 f = ff 251 break 252 } 253 if f == nil && strings.EqualFold(ff.name, key) { 254 f = ff 255 } 256 } 257 if f != nil { 258 subv := rv 259 for _, i := range f.index { 260 subv = indirect(subv.Field(i)) 261 } 262 if isUnifiable(subv) { 263 md.decoded[md.context.add(key).String()] = true 264 md.context = append(md.context, key) 265 if err := md.unify(datum, subv); err != nil { 266 return err 267 } 268 md.context = md.context[0 : len(md.context)-1] 269 } else if f.name != "" { 270 // Bad user! No soup for you! 271 return e("cannot write unexported field %s.%s", 272 rv.Type().String(), f.name) 273 } 274 } 275 } 276 return nil 277 } 278 279 func (md *MetaData) unifyMap(mapping interface{}, rv reflect.Value) error { 280 tmap, ok := mapping.(map[string]interface{}) 281 if !ok { 282 if tmap == nil { 283 return nil 284 } 285 return badtype("map", mapping) 286 } 287 if rv.IsNil() { 288 rv.Set(reflect.MakeMap(rv.Type())) 289 } 290 for k, v := range tmap { 291 md.decoded[md.context.add(k).String()] = true 292 md.context = append(md.context, k) 293 294 rvkey := indirect(reflect.New(rv.Type().Key())) 295 rvval := reflect.Indirect(reflect.New(rv.Type().Elem())) 296 if err := md.unify(v, rvval); err != nil { 297 return err 298 } 299 md.context = md.context[0 : len(md.context)-1] 300 301 rvkey.SetString(k) 302 rv.SetMapIndex(rvkey, rvval) 303 } 304 return nil 305 } 306 307 func (md *MetaData) unifyArray(data interface{}, rv reflect.Value) error { 308 datav := reflect.ValueOf(data) 309 if datav.Kind() != reflect.Slice { 310 if !datav.IsValid() { 311 return nil 312 } 313 return badtype("slice", data) 314 } 315 sliceLen := datav.Len() 316 if sliceLen != rv.Len() { 317 return e("expected array length %d; got TOML array of length %d", 318 rv.Len(), sliceLen) 319 } 320 return md.unifySliceArray(datav, rv) 321 } 322 323 func (md *MetaData) unifySlice(data interface{}, rv reflect.Value) error { 324 datav := reflect.ValueOf(data) 325 if datav.Kind() != reflect.Slice { 326 if !datav.IsValid() { 327 return nil 328 } 329 return badtype("slice", data) 330 } 331 n := datav.Len() 332 if rv.IsNil() || rv.Cap() < n { 333 rv.Set(reflect.MakeSlice(rv.Type(), n, n)) 334 } 335 rv.SetLen(n) 336 return md.unifySliceArray(datav, rv) 337 } 338 339 func (md *MetaData) unifySliceArray(data, rv reflect.Value) error { 340 sliceLen := data.Len() 341 for i := 0; i < sliceLen; i++ { 342 v := data.Index(i).Interface() 343 sliceval := indirect(rv.Index(i)) 344 if err := md.unify(v, sliceval); err != nil { 345 return err 346 } 347 } 348 return nil 349 } 350 351 func (md *MetaData) unifyDatetime(data interface{}, rv reflect.Value) error { 352 if _, ok := data.(time.Time); ok { 353 rv.Set(reflect.ValueOf(data)) 354 return nil 355 } 356 return badtype("time.Time", data) 357 } 358 359 func (md *MetaData) unifyString(data interface{}, rv reflect.Value) error { 360 if s, ok := data.(string); ok { 361 rv.SetString(s) 362 return nil 363 } 364 return badtype("string", data) 365 } 366 367 func (md *MetaData) unifyFloat64(data interface{}, rv reflect.Value) error { 368 if num, ok := data.(float64); ok { 369 switch rv.Kind() { 370 case reflect.Float32: 371 fallthrough 372 case reflect.Float64: 373 rv.SetFloat(num) 374 default: 375 panic("bug") 376 } 377 return nil 378 } 379 return badtype("float", data) 380 } 381 382 func (md *MetaData) unifyInt(data interface{}, rv reflect.Value) error { 383 if num, ok := data.(int64); ok { 384 if rv.Kind() >= reflect.Int && rv.Kind() <= reflect.Int64 { 385 switch rv.Kind() { 386 case reflect.Int, reflect.Int64: 387 // No bounds checking necessary. 388 case reflect.Int8: 389 if num < math.MinInt8 || num > math.MaxInt8 { 390 return e("value %d is out of range for int8", num) 391 } 392 case reflect.Int16: 393 if num < math.MinInt16 || num > math.MaxInt16 { 394 return e("value %d is out of range for int16", num) 395 } 396 case reflect.Int32: 397 if num < math.MinInt32 || num > math.MaxInt32 { 398 return e("value %d is out of range for int32", num) 399 } 400 } 401 rv.SetInt(num) 402 } else if rv.Kind() >= reflect.Uint && rv.Kind() <= reflect.Uint64 { 403 unum := uint64(num) 404 switch rv.Kind() { 405 case reflect.Uint, reflect.Uint64: 406 // No bounds checking necessary. 407 case reflect.Uint8: 408 if num < 0 || unum > math.MaxUint8 { 409 return e("value %d is out of range for uint8", num) 410 } 411 case reflect.Uint16: 412 if num < 0 || unum > math.MaxUint16 { 413 return e("value %d is out of range for uint16", num) 414 } 415 case reflect.Uint32: 416 if num < 0 || unum > math.MaxUint32 { 417 return e("value %d is out of range for uint32", num) 418 } 419 } 420 rv.SetUint(unum) 421 } else { 422 panic("unreachable") 423 } 424 return nil 425 } 426 return badtype("integer", data) 427 } 428 429 func (md *MetaData) unifyBool(data interface{}, rv reflect.Value) error { 430 if b, ok := data.(bool); ok { 431 rv.SetBool(b) 432 return nil 433 } 434 return badtype("boolean", data) 435 } 436 437 func (md *MetaData) unifyAnything(data interface{}, rv reflect.Value) error { 438 rv.Set(reflect.ValueOf(data)) 439 return nil 440 } 441 442 func (md *MetaData) unifyText(data interface{}, v TextUnmarshaler) error { 443 var s string 444 switch sdata := data.(type) { 445 case TextMarshaler: 446 text, err := sdata.MarshalText() 447 if err != nil { 448 return err 449 } 450 s = string(text) 451 case fmt.Stringer: 452 s = sdata.String() 453 case string: 454 s = sdata 455 case bool: 456 s = fmt.Sprintf("%v", sdata) 457 case int64: 458 s = fmt.Sprintf("%d", sdata) 459 case float64: 460 s = fmt.Sprintf("%f", sdata) 461 default: 462 return badtype("primitive (string-like)", data) 463 } 464 if err := v.UnmarshalText([]byte(s)); err != nil { 465 return err 466 } 467 return nil 468 } 469 470 // rvalue returns a reflect.Value of `v`. All pointers are resolved. 471 func rvalue(v interface{}) reflect.Value { 472 return indirect(reflect.ValueOf(v)) 473 } 474 475 // indirect returns the value pointed to by a pointer. 476 // Pointers are followed until the value is not a pointer. 477 // New values are allocated for each nil pointer. 478 // 479 // An exception to this rule is if the value satisfies an interface of 480 // interest to us (like encoding.TextUnmarshaler). 481 func indirect(v reflect.Value) reflect.Value { 482 if v.Kind() != reflect.Ptr { 483 if v.CanSet() { 484 pv := v.Addr() 485 if _, ok := pv.Interface().(TextUnmarshaler); ok { 486 return pv 487 } 488 } 489 return v 490 } 491 if v.IsNil() { 492 v.Set(reflect.New(v.Type().Elem())) 493 } 494 return indirect(reflect.Indirect(v)) 495 } 496 497 func isUnifiable(rv reflect.Value) bool { 498 if rv.CanSet() { 499 return true 500 } 501 if _, ok := rv.Interface().(TextUnmarshaler); ok { 502 return true 503 } 504 return false 505 } 506 507 func badtype(expected string, data interface{}) error { 508 return e("cannot load TOML value of type %T into a Go %s", data, expected) 509 }