encode.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. package toml
  2. // TODO: Build a decent encoder.
  3. // Interestingly, this isn't as trivial as recursing down the type of the
  4. // value given and outputting the corresponding TOML. In particular, multiple
  5. // TOML types (especially if tuples are added) can map to a single Go type, so
  6. // that the reverse correspondence isn't clear.
  7. //
  8. // One possible avenue is to choose a reasonable default (like structs map
  9. // to hashes), but allow the user to override with struct tags. But this seems
  10. // like a mess.
  11. //
  12. // The other possibility is to scrap an encoder altogether. After all, TOML
  13. // is a configuration file format, and not a data exchange format.
  14. import (
  15. "bufio"
  16. "fmt"
  17. "io"
  18. "reflect"
  19. "strings"
  20. )
  21. type encoder struct {
  22. // A single indentation level. By default it is two spaces.
  23. Indent string
  24. w *bufio.Writer
  25. }
  26. func newEncoder(w io.Writer) *encoder {
  27. return &encoder{
  28. w: bufio.NewWriter(w),
  29. Indent: " ",
  30. }
  31. }
  32. func (enc *encoder) Encode(v interface{}) error {
  33. rv := eindirect(reflect.ValueOf(v))
  34. if err := enc.encode(Key([]string{}), rv); err != nil {
  35. return err
  36. }
  37. return enc.w.Flush()
  38. }
  39. func (enc *encoder) encode(key Key, rv reflect.Value) error {
  40. k := rv.Kind()
  41. switch k {
  42. case reflect.Struct:
  43. return enc.eStruct(key, rv)
  44. case reflect.String:
  45. return enc.eString(key, rv)
  46. }
  47. return e("Unsupported type for key '%s': %s", key, k)
  48. }
  49. func (enc *encoder) eStruct(key Key, rv reflect.Value) error {
  50. rt := rv.Type()
  51. for i := 0; i < rt.NumField(); i++ {
  52. sft := rt.Field(i)
  53. sf := rv.Field(i)
  54. if err := enc.encode(key.add(sft.Name), sf); err != nil {
  55. return err
  56. }
  57. }
  58. return nil
  59. }
  60. func (enc *encoder) eString(key Key, rv reflect.Value) error {
  61. s := rv.String()
  62. s = strings.NewReplacer(
  63. "\t", "\\t",
  64. "\n", "\\n",
  65. "\r", "\\r",
  66. "\"", "\\\"",
  67. "\\", "\\\\",
  68. ).Replace(s)
  69. s = "\"" + s + "\""
  70. if err := enc.eKeyVal(key, s); err != nil {
  71. return err
  72. }
  73. return nil
  74. }
  75. func (enc *encoder) eKeyVal(key Key, value string) error {
  76. out := fmt.Sprintf("%s%s = %s",
  77. strings.Repeat(enc.Indent, len(key)-1), key[len(key)-1], value)
  78. if _, err := fmt.Fprintln(enc.w, out); err != nil {
  79. return err
  80. }
  81. return nil
  82. }
  83. func eindirect(v reflect.Value) reflect.Value {
  84. if v.Kind() != reflect.Ptr {
  85. return v
  86. }
  87. return eindirect(reflect.Indirect(v))
  88. }