1package toml 2 3import ( 4 "fmt" 5 "io" 6 "io/ioutil" 7 "math" 8 "reflect" 9 "strings" 10 "time" 11) 12 13func 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. 19type Unmarshaler interface { 20 UnmarshalTOML(interface{}) error 21} 22 23// Unmarshal decodes the contents of `p` in TOML format into a pointer `v`. 24func 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. 41type Primitive struct { 42 undecoded interface{} 43 context Key 44} 45 46// DEPRECATED! 47// 48// Use MetaData.PrimitiveDecode instead. 49func 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.) 65func (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. 107func 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. 128func 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. 138func 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. 151func (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 234func (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 279func (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 307func (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 323func (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 339func (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 351func (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 359func (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 367func (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 382func (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 429func (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 437func (md *MetaData) unifyAnything(data interface{}, rv reflect.Value) error { 438 rv.Set(reflect.ValueOf(data)) 439 return nil 440} 441 442func (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. 471func 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). 481func 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 497func 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 507func badtype(expected string, data interface{}) error { 508 return e("cannot load TOML value of type %T into a Go %s", data, expected) 509} 510