| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899 |
- package toml
- // TODO: Build a decent encoder.
- // Interestingly, this isn't as trivial as recursing down the type of the
- // value given and outputting the corresponding TOML. In particular, multiple
- // TOML types (especially if tuples are added) can map to a single Go type, so
- // that the reverse correspondence isn't clear.
- //
- // One possible avenue is to choose a reasonable default (like structs map
- // to hashes), but allow the user to override with struct tags. But this seems
- // like a mess.
- //
- // The other possibility is to scrap an encoder altogether. After all, TOML
- // is a configuration file format, and not a data exchange format.
- import (
- "bufio"
- "fmt"
- "io"
- "reflect"
- "strings"
- )
- type encoder struct {
- // A single indentation level. By default it is two spaces.
- Indent string
- w *bufio.Writer
- }
- func newEncoder(w io.Writer) *encoder {
- return &encoder{
- w: bufio.NewWriter(w),
- Indent: " ",
- }
- }
- func (enc *encoder) Encode(v interface{}) error {
- rv := eindirect(reflect.ValueOf(v))
- if err := enc.encode(Key([]string{}), rv); err != nil {
- return err
- }
- return enc.w.Flush()
- }
- func (enc *encoder) encode(key Key, rv reflect.Value) error {
- k := rv.Kind()
- switch k {
- case reflect.Struct:
- return enc.eStruct(key, rv)
- case reflect.String:
- return enc.eString(key, rv)
- }
- return e("Unsupported type for key '%s': %s", key, k)
- }
- func (enc *encoder) eStruct(key Key, rv reflect.Value) error {
- rt := rv.Type()
- for i := 0; i < rt.NumField(); i++ {
- sft := rt.Field(i)
- sf := rv.Field(i)
- if err := enc.encode(key.add(sft.Name), sf); err != nil {
- return err
- }
- }
- return nil
- }
- func (enc *encoder) eString(key Key, rv reflect.Value) error {
- s := rv.String()
- s = strings.NewReplacer(
- "\t", "\\t",
- "\n", "\\n",
- "\r", "\\r",
- "\"", "\\\"",
- "\\", "\\\\",
- ).Replace(s)
- s = "\"" + s + "\""
- if err := enc.eKeyVal(key, s); err != nil {
- return err
- }
- return nil
- }
- func (enc *encoder) eKeyVal(key Key, value string) error {
- out := fmt.Sprintf("%s%s = %s",
- strings.Repeat(enc.Indent, len(key)-1), key[len(key)-1], value)
- if _, err := fmt.Fprintln(enc.w, out); err != nil {
- return err
- }
- return nil
- }
- func eindirect(v reflect.Value) reflect.Value {
- if v.Kind() != reflect.Ptr {
- return v
- }
- return eindirect(reflect.Indirect(v))
- }
|