14 type tomlOpts struct {
26 var encOptsDefaults = encOpts{
30 var timeType = reflect.TypeOf(time.Time{})
31 var marshalerType = reflect.TypeOf(new(Marshaler)).Elem()
33 // Check if the given marshall type maps to a Tree primitive
34 func isPrimitive(mtype reflect.Type) bool {
37 return isPrimitive(mtype.Elem())
40 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
42 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
44 case reflect.Float32, reflect.Float64:
49 return mtype == timeType || isCustomMarshaler(mtype)
55 // Check if the given marshall type maps to a Tree slice
56 func isTreeSlice(mtype reflect.Type) bool {
59 return !isOtherSlice(mtype)
65 // Check if the given marshall type maps to a non-Tree slice
66 func isOtherSlice(mtype reflect.Type) bool {
69 return isOtherSlice(mtype.Elem())
71 return isPrimitive(mtype.Elem()) || isOtherSlice(mtype.Elem())
77 // Check if the given marshall type maps to a Tree
78 func isTree(mtype reflect.Type) bool {
83 return !isPrimitive(mtype)
89 func isCustomMarshaler(mtype reflect.Type) bool {
90 return mtype.Implements(marshalerType)
93 func callCustomMarshaler(mval reflect.Value) ([]byte, error) {
94 return mval.Interface().(Marshaler).MarshalTOML()
97 // Marshaler is the interface implemented by types that
98 // can marshal themselves into valid TOML.
99 type Marshaler interface {
100 MarshalTOML() ([]byte, error)
104 Marshal returns the TOML encoding of v. Behavior is similar to the Go json
105 encoder, except that there is no concept of a Marshaler interface or MarshalTOML
106 function for sub-structs, and currently only definite types can be marshaled
107 (i.e. no `interface{}`).
109 The following struct annotations are supported:
111 toml:"Field" Overrides the field's name to output.
112 omitempty When set, empty values and groups are not emitted.
113 comment:"comment" Emits a # comment on the same line. This supports new lines.
114 commented:"true" Emits the value as commented.
116 Note that pointers are automatically assigned the "omitempty" option, as TOML
117 explicitly does not handle null values (saying instead the label should be
120 Tree structural types and corresponding marshal types:
122 *Tree (*)struct, (*)map[string]interface{}
123 []*Tree (*)[](*)struct, (*)[](*)map[string]interface{}
124 []interface{} (as interface{}) (*)[]primitive, (*)[]([]interface{})
125 interface{} (*)primitive
127 Tree primitive types and corresponding marshal types:
129 uint64 uint, uint8-uint64, pointers to same
130 int64 int, int8-uint64, pointers to same
131 float64 float32, float64, pointers to same
132 string string, pointers to same
133 bool bool, pointers to same
134 time.Time time.Time{}, pointers to same
136 func Marshal(v interface{}) ([]byte, error) {
137 return NewEncoder(nil).marshal(v)
140 // Encoder writes TOML values to an output stream.
141 type Encoder struct {
146 // NewEncoder returns a new encoder that writes to w.
147 func NewEncoder(w io.Writer) *Encoder {
150 encOpts: encOptsDefaults,
154 // Encode writes the TOML encoding of v to the stream.
156 // See the documentation for Marshal for details.
157 func (e *Encoder) Encode(v interface{}) error {
158 b, err := e.marshal(v)
162 if _, err := e.w.Write(b); err != nil {
168 // QuoteMapKeys sets up the encoder to encode
169 // maps with string type keys with quoted TOML keys.
171 // This relieves the character limitations on map keys.
172 func (e *Encoder) QuoteMapKeys(v bool) *Encoder {
177 func (e *Encoder) marshal(v interface{}) ([]byte, error) {
178 mtype := reflect.TypeOf(v)
179 if mtype.Kind() != reflect.Struct {
180 return []byte{}, errors.New("Only a struct can be marshaled to TOML")
182 sval := reflect.ValueOf(v)
183 if isCustomMarshaler(mtype) {
184 return callCustomMarshaler(sval)
186 t, err := e.valueToTree(mtype, sval)
190 s, err := t.ToTomlString()
191 return []byte(s), err
194 // Convert given marshal struct or map value to toml tree
195 func (e *Encoder) valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, error) {
196 if mtype.Kind() == reflect.Ptr {
197 return e.valueToTree(mtype.Elem(), mval.Elem())
200 switch mtype.Kind() {
202 for i := 0; i < mtype.NumField(); i++ {
203 mtypef, mvalf := mtype.Field(i), mval.Field(i)
204 opts := tomlOptions(mtypef)
205 if opts.include && (!opts.omitempty || !isZero(mvalf)) {
206 val, err := e.valueToToml(mtypef.Type, mvalf)
210 tval.Set(opts.name, opts.comment, opts.commented, val)
214 for _, key := range mval.MapKeys() {
215 mvalf := mval.MapIndex(key)
216 val, err := e.valueToToml(mtype.Elem(), mvalf)
221 keyStr, err := tomlValueStringRepresentation(key.String())
225 tval.SetPath([]string{keyStr}, "", false, val)
227 tval.Set(key.String(), "", false, val)
234 // Convert given marshal slice to slice of Toml trees
235 func (e *Encoder) valueToTreeSlice(mtype reflect.Type, mval reflect.Value) ([]*Tree, error) {
236 tval := make([]*Tree, mval.Len(), mval.Len())
237 for i := 0; i < mval.Len(); i++ {
238 val, err := e.valueToTree(mtype.Elem(), mval.Index(i))
247 // Convert given marshal slice to slice of toml values
248 func (e *Encoder) valueToOtherSlice(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
249 tval := make([]interface{}, mval.Len(), mval.Len())
250 for i := 0; i < mval.Len(); i++ {
251 val, err := e.valueToToml(mtype.Elem(), mval.Index(i))
260 // Convert given marshal value to toml value
261 func (e *Encoder) valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
262 if mtype.Kind() == reflect.Ptr {
263 return e.valueToToml(mtype.Elem(), mval.Elem())
266 case isCustomMarshaler(mtype):
267 return callCustomMarshaler(mval)
269 return e.valueToTree(mtype, mval)
270 case isTreeSlice(mtype):
271 return e.valueToTreeSlice(mtype, mval)
272 case isOtherSlice(mtype):
273 return e.valueToOtherSlice(mtype, mval)
275 switch mtype.Kind() {
277 return mval.Bool(), nil
278 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
279 return mval.Int(), nil
280 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
281 return mval.Uint(), nil
282 case reflect.Float32, reflect.Float64:
283 return mval.Float(), nil
285 return mval.String(), nil
287 return mval.Interface().(time.Time), nil
289 return nil, fmt.Errorf("Marshal can't handle %v(%v)", mtype, mtype.Kind())
294 // Unmarshal attempts to unmarshal the Tree into a Go struct pointed by v.
295 // Neither Unmarshaler interfaces nor UnmarshalTOML functions are supported for
296 // sub-structs, and only definite types can be unmarshaled.
297 func (t *Tree) Unmarshal(v interface{}) error {
298 d := Decoder{tval: t}
299 return d.unmarshal(v)
302 // Marshal returns the TOML encoding of Tree.
303 // See Marshal() documentation for types mapping table.
304 func (t *Tree) Marshal() ([]byte, error) {
306 err := NewEncoder(&buf).Encode(t)
307 return buf.Bytes(), err
310 // Unmarshal parses the TOML-encoded data and stores the result in the value
311 // pointed to by v. Behavior is similar to the Go json encoder, except that there
312 // is no concept of an Unmarshaler interface or UnmarshalTOML function for
313 // sub-structs, and currently only definite types can be unmarshaled to (i.e. no
316 // The following struct annotations are supported:
318 // toml:"Field" Overrides the field's name to map to.
320 // See Marshal() documentation for types mapping table.
321 func Unmarshal(data []byte, v interface{}) error {
322 t, err := LoadReader(bytes.NewReader(data))
326 return t.Unmarshal(v)
329 // Decoder reads and decodes TOML values from an input stream.
330 type Decoder struct {
336 // NewDecoder returns a new decoder that reads from r.
337 func NewDecoder(r io.Reader) *Decoder {
340 encOpts: encOptsDefaults,
344 // Decode reads a TOML-encoded value from it's input
345 // and unmarshals it in the value pointed at by v.
347 // See the documentation for Marshal for details.
348 func (d *Decoder) Decode(v interface{}) error {
350 d.tval, err = LoadReader(d.r)
354 return d.unmarshal(v)
357 func (d *Decoder) unmarshal(v interface{}) error {
358 mtype := reflect.TypeOf(v)
359 if mtype.Kind() != reflect.Ptr || mtype.Elem().Kind() != reflect.Struct {
360 return errors.New("Only a pointer to struct can be unmarshaled from TOML")
363 sval, err := d.valueFromTree(mtype.Elem(), d.tval)
367 reflect.ValueOf(v).Elem().Set(sval)
371 // Convert toml tree to marshal struct or map, using marshal type
372 func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value, error) {
373 if mtype.Kind() == reflect.Ptr {
374 return d.unwrapPointer(mtype, tval)
376 var mval reflect.Value
377 switch mtype.Kind() {
379 mval = reflect.New(mtype).Elem()
380 for i := 0; i < mtype.NumField(); i++ {
381 mtypef := mtype.Field(i)
382 opts := tomlOptions(mtypef)
385 keysToTry := []string{baseKey, strings.ToLower(baseKey), strings.ToTitle(baseKey)}
386 for _, key := range keysToTry {
387 exists := tval.Has(key)
392 mvalf, err := d.valueFromToml(mtypef.Type, val)
394 return mval, formatError(err, tval.GetPosition(key))
396 mval.Field(i).Set(mvalf)
402 mval = reflect.MakeMap(mtype)
403 for _, key := range tval.Keys() {
404 // TODO: path splits key
405 val := tval.GetPath([]string{key})
406 mvalf, err := d.valueFromToml(mtype.Elem(), val)
408 return mval, formatError(err, tval.GetPosition(key))
410 mval.SetMapIndex(reflect.ValueOf(key), mvalf)
416 // Convert toml value to marshal struct/map slice, using marshal type
417 func (d *Decoder) valueFromTreeSlice(mtype reflect.Type, tval []*Tree) (reflect.Value, error) {
418 mval := reflect.MakeSlice(mtype, len(tval), len(tval))
419 for i := 0; i < len(tval); i++ {
420 val, err := d.valueFromTree(mtype.Elem(), tval[i])
424 mval.Index(i).Set(val)
429 // Convert toml value to marshal primitive slice, using marshal type
430 func (d *Decoder) valueFromOtherSlice(mtype reflect.Type, tval []interface{}) (reflect.Value, error) {
431 mval := reflect.MakeSlice(mtype, len(tval), len(tval))
432 for i := 0; i < len(tval); i++ {
433 val, err := d.valueFromToml(mtype.Elem(), tval[i])
437 mval.Index(i).Set(val)
442 // Convert toml value to marshal value, using marshal type
443 func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}) (reflect.Value, error) {
444 if mtype.Kind() == reflect.Ptr {
445 return d.unwrapPointer(mtype, tval)
451 return d.valueFromTree(mtype, tval.(*Tree))
453 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a tree", tval, tval)
456 if isTreeSlice(mtype) {
457 return d.valueFromTreeSlice(mtype, tval.([]*Tree))
459 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to trees", tval, tval)
462 if isOtherSlice(mtype) {
463 return d.valueFromOtherSlice(mtype, tval.([]interface{}))
465 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a slice", tval, tval)
468 switch mtype.Kind() {
470 val, ok := tval.(bool)
472 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to bool", tval, tval)
474 return reflect.ValueOf(val), nil
476 val, ok := tval.(int64)
478 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
480 return reflect.ValueOf(int(val)), nil
482 val, ok := tval.(int64)
484 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
486 return reflect.ValueOf(int8(val)), nil
488 val, ok := tval.(int64)
490 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
492 return reflect.ValueOf(int16(val)), nil
494 val, ok := tval.(int64)
496 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
498 return reflect.ValueOf(int32(val)), nil
500 val, ok := tval.(int64)
502 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
504 return reflect.ValueOf(val), nil
506 val, ok := tval.(int64)
508 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
510 return reflect.ValueOf(uint(val)), nil
512 val, ok := tval.(int64)
514 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
516 return reflect.ValueOf(uint8(val)), nil
518 val, ok := tval.(int64)
520 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
522 return reflect.ValueOf(uint16(val)), nil
524 val, ok := tval.(int64)
526 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
528 return reflect.ValueOf(uint32(val)), nil
530 val, ok := tval.(int64)
532 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
534 return reflect.ValueOf(uint64(val)), nil
535 case reflect.Float32:
536 val, ok := tval.(float64)
538 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to float", tval, tval)
540 return reflect.ValueOf(float32(val)), nil
541 case reflect.Float64:
542 val, ok := tval.(float64)
544 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to float", tval, tval)
546 return reflect.ValueOf(val), nil
548 val, ok := tval.(string)
550 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to string", tval, tval)
552 return reflect.ValueOf(val), nil
554 val, ok := tval.(time.Time)
556 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to time", tval, tval)
558 return reflect.ValueOf(val), nil
560 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v(%v)", tval, tval, mtype, mtype.Kind())
565 func (d *Decoder) unwrapPointer(mtype reflect.Type, tval interface{}) (reflect.Value, error) {
566 val, err := d.valueFromToml(mtype.Elem(), tval)
568 return reflect.ValueOf(nil), err
570 mval := reflect.New(mtype.Elem())
575 func tomlOptions(vf reflect.StructField) tomlOpts {
576 tag := vf.Tag.Get("toml")
577 parse := strings.Split(tag, ",")
579 if c := vf.Tag.Get("comment"); c != "" {
582 commented, _ := strconv.ParseBool(vf.Tag.Get("commented"))
583 result := tomlOpts{name: vf.Name, comment: comment, commented: commented, include: true, omitempty: false}
585 if parse[0] == "-" && len(parse) == 1 {
586 result.include = false
588 result.name = strings.Trim(parse[0], " ")
591 if vf.PkgPath != "" {
592 result.include = false
594 if len(parse) > 1 && strings.Trim(parse[1], " ") == "omitempty" {
595 result.omitempty = true
597 if vf.Type.Kind() == reflect.Ptr {
598 result.omitempty = true
603 func isZero(val reflect.Value) bool {
604 switch val.Type().Kind() {
610 return val.Len() == 0
612 return reflect.DeepEqual(val.Interface(), reflect.Zero(val.Type()).Interface())
616 func formatError(err error, pos Position) error {
617 if err.Error()[0] == '(' { // Error already contains position information
620 return fmt.Errorf("%s: %s", pos, err)