encode.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. package toml
  2. import (
  3. "bytes"
  4. "encoding"
  5. "fmt"
  6. "io"
  7. "reflect"
  8. "sort"
  9. "strconv"
  10. "time"
  11. "github.com/naoina/toml/ast"
  12. )
  13. const (
  14. tagOmitempty = "omitempty"
  15. tagSkip = "-"
  16. )
  17. // Marshal returns the TOML encoding of v.
  18. //
  19. // Struct values encode as TOML. Each exported struct field becomes a field of
  20. // the TOML structure unless
  21. // - the field's tag is "-", or
  22. // - the field is empty and its tag specifies the "omitempty" option.
  23. //
  24. // The "toml" key in the struct field's tag value is the key name, followed by
  25. // an optional comma and options. Examples:
  26. //
  27. // // Field is ignored by this package.
  28. // Field int `toml:"-"`
  29. //
  30. // // Field appears in TOML as key "myName".
  31. // Field int `toml:"myName"`
  32. //
  33. // // Field appears in TOML as key "myName" and the field is omitted from the
  34. // // result of encoding if its value is empty.
  35. // Field int `toml:"myName,omitempty"`
  36. //
  37. // // Field appears in TOML as key "field", but the field is skipped if
  38. // // empty. Note the leading comma.
  39. // Field int `toml:",omitempty"`
  40. func (cfg *Config) Marshal(v interface{}) ([]byte, error) {
  41. buf := new(bytes.Buffer)
  42. err := cfg.NewEncoder(buf).Encode(v)
  43. return buf.Bytes(), err
  44. }
  45. // A Encoder writes TOML to an output stream.
  46. type Encoder struct {
  47. w io.Writer
  48. cfg *Config
  49. }
  50. // NewEncoder returns a new Encoder that writes to w.
  51. func (cfg *Config) NewEncoder(w io.Writer) *Encoder {
  52. return &Encoder{w, cfg}
  53. }
  54. // Encode writes the TOML of v to the stream.
  55. // See the documentation for Marshal for details about the conversion of Go values to TOML.
  56. func (e *Encoder) Encode(v interface{}) error {
  57. var (
  58. buf = &tableBuf{typ: ast.TableTypeNormal}
  59. rv = reflect.ValueOf(v)
  60. err error
  61. )
  62. for rv.Kind() == reflect.Ptr {
  63. if rv.IsNil() {
  64. return &marshalNilError{rv.Type()}
  65. }
  66. rv = rv.Elem()
  67. }
  68. switch rv.Kind() {
  69. case reflect.Struct:
  70. err = buf.structFields(e.cfg, rv)
  71. case reflect.Map:
  72. err = buf.mapFields(e.cfg, rv)
  73. case reflect.Interface:
  74. return e.Encode(rv.Interface())
  75. default:
  76. err = &marshalTableError{rv.Type()}
  77. }
  78. if err != nil {
  79. return err
  80. }
  81. return buf.writeTo(e.w, "")
  82. }
  83. // Marshaler can be implemented to override the encoding of TOML values. The returned text
  84. // must be a simple TOML value (i.e. not a table) and is inserted into marshaler output.
  85. //
  86. // This interface exists for backwards-compatibility reasons. You probably want to
  87. // implement encoding.TextMarshaler or MarshalerRec instead.
  88. type Marshaler interface {
  89. MarshalTOML() ([]byte, error)
  90. }
  91. // MarshalerRec can be implemented to override the TOML encoding of a type.
  92. // The returned value is marshaled in place of the receiver.
  93. type MarshalerRec interface {
  94. MarshalTOML() (interface{}, error)
  95. }
  96. type tableBuf struct {
  97. name string // already escaped / quoted
  98. body []byte
  99. children []*tableBuf
  100. typ ast.TableType
  101. arrayDepth int
  102. }
  103. func (b *tableBuf) writeTo(w io.Writer, prefix string) error {
  104. key := b.name // TODO: escape dots
  105. if prefix != "" {
  106. key = prefix + "." + key
  107. }
  108. if b.name != "" {
  109. head := "[" + key + "]"
  110. if b.typ == ast.TableTypeArray {
  111. head = "[" + head + "]"
  112. }
  113. head += "\n"
  114. if _, err := io.WriteString(w, head); err != nil {
  115. return err
  116. }
  117. }
  118. if _, err := w.Write(b.body); err != nil {
  119. return err
  120. }
  121. for i, child := range b.children {
  122. if len(b.body) > 0 || i > 0 {
  123. if _, err := w.Write([]byte("\n")); err != nil {
  124. return err
  125. }
  126. }
  127. if err := child.writeTo(w, key); err != nil {
  128. return err
  129. }
  130. }
  131. return nil
  132. }
  133. func (b *tableBuf) newChild(name string) *tableBuf {
  134. child := &tableBuf{name: quoteName(name), typ: ast.TableTypeNormal}
  135. if b.arrayDepth > 0 {
  136. child.typ = ast.TableTypeArray
  137. }
  138. return child
  139. }
  140. func (b *tableBuf) addChild(child *tableBuf) {
  141. // Empty table elision: we can avoid writing a table that doesn't have any keys on its
  142. // own. Array tables can't be elided because they define array elements (which would
  143. // be missing if elided).
  144. if len(child.body) == 0 && child.typ == ast.TableTypeNormal {
  145. for _, gchild := range child.children {
  146. gchild.name = child.name + "." + gchild.name
  147. b.addChild(gchild)
  148. }
  149. return
  150. }
  151. b.children = append(b.children, child)
  152. }
  153. func (b *tableBuf) structFields(cfg *Config, rv reflect.Value) error {
  154. rt := rv.Type()
  155. for i := 0; i < rv.NumField(); i++ {
  156. ft := rt.Field(i)
  157. if ft.PkgPath != "" && !ft.Anonymous { // not exported
  158. continue
  159. }
  160. name, rest := extractTag(ft.Tag.Get(fieldTagName))
  161. if name == tagSkip {
  162. continue
  163. }
  164. fv := rv.Field(i)
  165. if rest == tagOmitempty && isEmptyValue(fv) {
  166. continue
  167. }
  168. if name == "" {
  169. name = cfg.FieldToKey(rt, ft.Name)
  170. }
  171. if err := b.field(cfg, name, fv); err != nil {
  172. return err
  173. }
  174. }
  175. return nil
  176. }
  177. type mapKeyList []struct {
  178. key string
  179. value reflect.Value
  180. }
  181. func (l mapKeyList) Len() int { return len(l) }
  182. func (l mapKeyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
  183. func (l mapKeyList) Less(i, j int) bool { return l[i].key < l[j].key }
  184. func (b *tableBuf) mapFields(cfg *Config, rv reflect.Value) error {
  185. keys := rv.MapKeys()
  186. keylist := make(mapKeyList, len(keys))
  187. for i, key := range keys {
  188. var err error
  189. keylist[i].key, err = encodeMapKey(key)
  190. if err != nil {
  191. return err
  192. }
  193. keylist[i].value = rv.MapIndex(key)
  194. }
  195. sort.Sort(keylist)
  196. for _, kv := range keylist {
  197. if err := b.field(cfg, kv.key, kv.value); err != nil {
  198. return err
  199. }
  200. }
  201. return nil
  202. }
  203. func (b *tableBuf) field(cfg *Config, name string, rv reflect.Value) error {
  204. off := len(b.body)
  205. b.body = append(b.body, quoteName(name)...)
  206. b.body = append(b.body, " = "...)
  207. isTable, err := b.value(cfg, rv, name)
  208. if isTable {
  209. b.body = b.body[:off] // rub out "key ="
  210. } else {
  211. b.body = append(b.body, '\n')
  212. }
  213. return err
  214. }
  215. func (b *tableBuf) value(cfg *Config, rv reflect.Value, name string) (bool, error) {
  216. isMarshaler, isTable, err := b.marshaler(cfg, rv, name)
  217. if isMarshaler {
  218. return isTable, err
  219. }
  220. switch rv.Kind() {
  221. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  222. b.body = strconv.AppendInt(b.body, rv.Int(), 10)
  223. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  224. b.body = strconv.AppendUint(b.body, rv.Uint(), 10)
  225. case reflect.Float32, reflect.Float64:
  226. b.body = strconv.AppendFloat(b.body, rv.Float(), 'e', -1, 64)
  227. case reflect.Bool:
  228. b.body = strconv.AppendBool(b.body, rv.Bool())
  229. case reflect.String:
  230. b.body = strconv.AppendQuote(b.body, rv.String())
  231. case reflect.Ptr, reflect.Interface:
  232. if rv.IsNil() {
  233. return false, &marshalNilError{rv.Type()}
  234. }
  235. return b.value(cfg, rv.Elem(), name)
  236. case reflect.Slice, reflect.Array:
  237. rvlen := rv.Len()
  238. if rvlen == 0 {
  239. b.body = append(b.body, '[', ']')
  240. return false, nil
  241. }
  242. b.arrayDepth++
  243. wroteElem := false
  244. b.body = append(b.body, '[')
  245. for i := 0; i < rvlen; i++ {
  246. isTable, err := b.value(cfg, rv.Index(i), name)
  247. if err != nil {
  248. return isTable, err
  249. }
  250. wroteElem = wroteElem || !isTable
  251. if wroteElem {
  252. if i < rvlen-1 {
  253. b.body = append(b.body, ',', ' ')
  254. } else {
  255. b.body = append(b.body, ']')
  256. }
  257. }
  258. }
  259. if !wroteElem {
  260. b.body = b.body[:len(b.body)-1] // rub out '['
  261. }
  262. b.arrayDepth--
  263. return !wroteElem, nil
  264. case reflect.Struct:
  265. child := b.newChild(name)
  266. err := child.structFields(cfg, rv)
  267. b.addChild(child)
  268. return true, err
  269. case reflect.Map:
  270. child := b.newChild(name)
  271. err := child.mapFields(cfg, rv)
  272. b.addChild(child)
  273. return true, err
  274. default:
  275. return false, fmt.Errorf("toml: marshal: unsupported type %v", rv.Kind())
  276. }
  277. return false, nil
  278. }
  279. func (b *tableBuf) marshaler(cfg *Config, rv reflect.Value, name string) (handled, isTable bool, err error) {
  280. switch t := rv.Interface().(type) {
  281. case encoding.TextMarshaler:
  282. enc, err := t.MarshalText()
  283. if err != nil {
  284. return true, false, err
  285. }
  286. b.body = encodeTextMarshaler(b.body, string(enc))
  287. return true, false, nil
  288. case MarshalerRec:
  289. newval, err := t.MarshalTOML()
  290. if err != nil {
  291. return true, false, err
  292. }
  293. isTable, err = b.value(cfg, reflect.ValueOf(newval), name)
  294. return true, isTable, err
  295. case Marshaler:
  296. enc, err := t.MarshalTOML()
  297. if err != nil {
  298. return true, false, err
  299. }
  300. b.body = append(b.body, enc...)
  301. return true, false, nil
  302. }
  303. return false, false, nil
  304. }
  305. func encodeTextMarshaler(buf []byte, v string) []byte {
  306. // Emit the value without quotes if possible.
  307. if v == "true" || v == "false" {
  308. return append(buf, v...)
  309. } else if _, err := time.Parse(time.RFC3339Nano, v); err == nil {
  310. return append(buf, v...)
  311. } else if _, err := strconv.ParseInt(v, 10, 64); err == nil {
  312. return append(buf, v...)
  313. } else if _, err := strconv.ParseUint(v, 10, 64); err == nil {
  314. return append(buf, v...)
  315. } else if _, err := strconv.ParseFloat(v, 64); err == nil {
  316. return append(buf, v...)
  317. }
  318. return strconv.AppendQuote(buf, v)
  319. }
  320. func encodeMapKey(rv reflect.Value) (string, error) {
  321. if rv.Kind() == reflect.String {
  322. return rv.String(), nil
  323. }
  324. if tm, ok := rv.Interface().(encoding.TextMarshaler); ok {
  325. b, err := tm.MarshalText()
  326. return string(b), err
  327. }
  328. switch rv.Kind() {
  329. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  330. return strconv.FormatInt(rv.Int(), 10), nil
  331. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  332. return strconv.FormatUint(rv.Uint(), 10), nil
  333. }
  334. return "", fmt.Errorf("toml: invalid map key type %v", rv.Type())
  335. }
  336. func isEmptyValue(v reflect.Value) bool {
  337. switch v.Kind() {
  338. case reflect.Array:
  339. // encoding/json treats all arrays with non-zero length as non-empty. We check the
  340. // array content here because zero-length arrays are almost never used.
  341. len := v.Len()
  342. for i := 0; i < len; i++ {
  343. if !isEmptyValue(v.Index(i)) {
  344. return false
  345. }
  346. }
  347. return true
  348. case reflect.Map, reflect.Slice, reflect.String:
  349. return v.Len() == 0
  350. case reflect.Bool:
  351. return !v.Bool()
  352. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  353. return v.Int() == 0
  354. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  355. return v.Uint() == 0
  356. case reflect.Float32, reflect.Float64:
  357. return v.Float() == 0
  358. case reflect.Interface, reflect.Ptr:
  359. return v.IsNil()
  360. }
  361. return false
  362. }
  363. func quoteName(s string) string {
  364. if len(s) == 0 {
  365. return strconv.Quote(s)
  366. }
  367. for _, r := range s {
  368. if r >= '0' && r <= '9' || r >= 'A' && r <= 'Z' || r >= 'a' && r <= 'z' || r == '-' || r == '_' {
  369. continue
  370. }
  371. return strconv.Quote(s)
  372. }
  373. return s
  374. }