You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

695 lines
17 KiB

  1. package toml
  2. import (
  3. "bufio"
  4. "encoding"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "math"
  9. "reflect"
  10. "sort"
  11. "strconv"
  12. "strings"
  13. "time"
  14. "github.com/BurntSushi/toml/internal"
  15. )
  16. type tomlEncodeError struct{ error }
  17. var (
  18. errArrayNilElement = errors.New("toml: cannot encode array with nil element")
  19. errNonString = errors.New("toml: cannot encode a map with non-string key type")
  20. errNoKey = errors.New("toml: top-level values must be Go maps or structs")
  21. errAnything = errors.New("") // used in testing
  22. )
  23. var dblQuotedReplacer = strings.NewReplacer(
  24. "\"", "\\\"",
  25. "\\", "\\\\",
  26. "\x00", `\u0000`,
  27. "\x01", `\u0001`,
  28. "\x02", `\u0002`,
  29. "\x03", `\u0003`,
  30. "\x04", `\u0004`,
  31. "\x05", `\u0005`,
  32. "\x06", `\u0006`,
  33. "\x07", `\u0007`,
  34. "\b", `\b`,
  35. "\t", `\t`,
  36. "\n", `\n`,
  37. "\x0b", `\u000b`,
  38. "\f", `\f`,
  39. "\r", `\r`,
  40. "\x0e", `\u000e`,
  41. "\x0f", `\u000f`,
  42. "\x10", `\u0010`,
  43. "\x11", `\u0011`,
  44. "\x12", `\u0012`,
  45. "\x13", `\u0013`,
  46. "\x14", `\u0014`,
  47. "\x15", `\u0015`,
  48. "\x16", `\u0016`,
  49. "\x17", `\u0017`,
  50. "\x18", `\u0018`,
  51. "\x19", `\u0019`,
  52. "\x1a", `\u001a`,
  53. "\x1b", `\u001b`,
  54. "\x1c", `\u001c`,
  55. "\x1d", `\u001d`,
  56. "\x1e", `\u001e`,
  57. "\x1f", `\u001f`,
  58. "\x7f", `\u007f`,
  59. )
  60. // Marshaler is the interface implemented by types that can marshal themselves
  61. // into valid TOML.
  62. type Marshaler interface {
  63. MarshalTOML() ([]byte, error)
  64. }
  65. // Encoder encodes a Go to a TOML document.
  66. //
  67. // The mapping between Go values and TOML values should be precisely the same as
  68. // for the Decode* functions.
  69. //
  70. // The toml.Marshaler and encoder.TextMarshaler interfaces are supported to
  71. // encoding the value as custom TOML.
  72. //
  73. // If you want to write arbitrary binary data then you will need to use
  74. // something like base64 since TOML does not have any binary types.
  75. //
  76. // When encoding TOML hashes (Go maps or structs), keys without any sub-hashes
  77. // are encoded first.
  78. //
  79. // Go maps will be sorted alphabetically by key for deterministic output.
  80. //
  81. // Encoding Go values without a corresponding TOML representation will return an
  82. // error. Examples of this includes maps with non-string keys, slices with nil
  83. // elements, embedded non-struct types, and nested slices containing maps or
  84. // structs. (e.g. [][]map[string]string is not allowed but []map[string]string
  85. // is okay, as is []map[string][]string).
  86. //
  87. // NOTE: only exported keys are encoded due to the use of reflection. Unexported
  88. // keys are silently discarded.
  89. type Encoder struct {
  90. // String to use for a single indentation level; default is two spaces.
  91. Indent string
  92. w *bufio.Writer
  93. hasWritten bool // written any output to w yet?
  94. }
  95. // NewEncoder create a new Encoder.
  96. func NewEncoder(w io.Writer) *Encoder {
  97. return &Encoder{
  98. w: bufio.NewWriter(w),
  99. Indent: " ",
  100. }
  101. }
  102. // Encode writes a TOML representation of the Go value to the Encoder's writer.
  103. //
  104. // An error is returned if the value given cannot be encoded to a valid TOML
  105. // document.
  106. func (enc *Encoder) Encode(v interface{}) error {
  107. rv := eindirect(reflect.ValueOf(v))
  108. if err := enc.safeEncode(Key([]string{}), rv); err != nil {
  109. return err
  110. }
  111. return enc.w.Flush()
  112. }
  113. func (enc *Encoder) safeEncode(key Key, rv reflect.Value) (err error) {
  114. defer func() {
  115. if r := recover(); r != nil {
  116. if terr, ok := r.(tomlEncodeError); ok {
  117. err = terr.error
  118. return
  119. }
  120. panic(r)
  121. }
  122. }()
  123. enc.encode(key, rv)
  124. return nil
  125. }
  126. func (enc *Encoder) encode(key Key, rv reflect.Value) {
  127. // Special case: time needs to be in ISO8601 format.
  128. //
  129. // Special case: if we can marshal the type to text, then we used that. This
  130. // prevents the encoder for handling these types as generic structs (or
  131. // whatever the underlying type of a TextMarshaler is).
  132. switch t := rv.Interface().(type) {
  133. case time.Time, encoding.TextMarshaler, Marshaler:
  134. enc.writeKeyValue(key, rv, false)
  135. return
  136. // TODO: #76 would make this superfluous after implemented.
  137. case Primitive:
  138. enc.encode(key, reflect.ValueOf(t.undecoded))
  139. return
  140. }
  141. k := rv.Kind()
  142. switch k {
  143. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
  144. reflect.Int64,
  145. reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
  146. reflect.Uint64,
  147. reflect.Float32, reflect.Float64, reflect.String, reflect.Bool:
  148. enc.writeKeyValue(key, rv, false)
  149. case reflect.Array, reflect.Slice:
  150. if typeEqual(tomlArrayHash, tomlTypeOfGo(rv)) {
  151. enc.eArrayOfTables(key, rv)
  152. } else {
  153. enc.writeKeyValue(key, rv, false)
  154. }
  155. case reflect.Interface:
  156. if rv.IsNil() {
  157. return
  158. }
  159. enc.encode(key, rv.Elem())
  160. case reflect.Map:
  161. if rv.IsNil() {
  162. return
  163. }
  164. enc.eTable(key, rv)
  165. case reflect.Ptr:
  166. if rv.IsNil() {
  167. return
  168. }
  169. enc.encode(key, rv.Elem())
  170. case reflect.Struct:
  171. enc.eTable(key, rv)
  172. default:
  173. encPanic(fmt.Errorf("unsupported type for key '%s': %s", key, k))
  174. }
  175. }
  176. // eElement encodes any value that can be an array element.
  177. func (enc *Encoder) eElement(rv reflect.Value) {
  178. switch v := rv.Interface().(type) {
  179. case time.Time: // Using TextMarshaler adds extra quotes, which we don't want.
  180. format := time.RFC3339Nano
  181. switch v.Location() {
  182. case internal.LocalDatetime:
  183. format = "2006-01-02T15:04:05.999999999"
  184. case internal.LocalDate:
  185. format = "2006-01-02"
  186. case internal.LocalTime:
  187. format = "15:04:05.999999999"
  188. }
  189. switch v.Location() {
  190. default:
  191. enc.wf(v.Format(format))
  192. case internal.LocalDatetime, internal.LocalDate, internal.LocalTime:
  193. enc.wf(v.In(time.UTC).Format(format))
  194. }
  195. return
  196. case Marshaler:
  197. s, err := v.MarshalTOML()
  198. if err != nil {
  199. encPanic(err)
  200. }
  201. enc.writeQuoted(string(s))
  202. return
  203. case encoding.TextMarshaler:
  204. s, err := v.MarshalText()
  205. if err != nil {
  206. encPanic(err)
  207. }
  208. enc.writeQuoted(string(s))
  209. return
  210. }
  211. switch rv.Kind() {
  212. case reflect.String:
  213. enc.writeQuoted(rv.String())
  214. case reflect.Bool:
  215. enc.wf(strconv.FormatBool(rv.Bool()))
  216. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  217. enc.wf(strconv.FormatInt(rv.Int(), 10))
  218. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  219. enc.wf(strconv.FormatUint(rv.Uint(), 10))
  220. case reflect.Float32:
  221. f := rv.Float()
  222. if math.IsNaN(f) {
  223. enc.wf("nan")
  224. } else if math.IsInf(f, 0) {
  225. enc.wf("%cinf", map[bool]byte{true: '-', false: '+'}[math.Signbit(f)])
  226. } else {
  227. enc.wf(floatAddDecimal(strconv.FormatFloat(f, 'f', -1, 32)))
  228. }
  229. case reflect.Float64:
  230. f := rv.Float()
  231. if math.IsNaN(f) {
  232. enc.wf("nan")
  233. } else if math.IsInf(f, 0) {
  234. enc.wf("%cinf", map[bool]byte{true: '-', false: '+'}[math.Signbit(f)])
  235. } else {
  236. enc.wf(floatAddDecimal(strconv.FormatFloat(f, 'f', -1, 64)))
  237. }
  238. case reflect.Array, reflect.Slice:
  239. enc.eArrayOrSliceElement(rv)
  240. case reflect.Struct:
  241. enc.eStruct(nil, rv, true)
  242. case reflect.Map:
  243. enc.eMap(nil, rv, true)
  244. case reflect.Interface:
  245. enc.eElement(rv.Elem())
  246. default:
  247. encPanic(fmt.Errorf("unexpected primitive type: %T", rv.Interface()))
  248. }
  249. }
  250. // By the TOML spec, all floats must have a decimal with at least one number on
  251. // either side.
  252. func floatAddDecimal(fstr string) string {
  253. if !strings.Contains(fstr, ".") {
  254. return fstr + ".0"
  255. }
  256. return fstr
  257. }
  258. func (enc *Encoder) writeQuoted(s string) {
  259. enc.wf("\"%s\"", dblQuotedReplacer.Replace(s))
  260. }
  261. func (enc *Encoder) eArrayOrSliceElement(rv reflect.Value) {
  262. length := rv.Len()
  263. enc.wf("[")
  264. for i := 0; i < length; i++ {
  265. elem := rv.Index(i)
  266. enc.eElement(elem)
  267. if i != length-1 {
  268. enc.wf(", ")
  269. }
  270. }
  271. enc.wf("]")
  272. }
  273. func (enc *Encoder) eArrayOfTables(key Key, rv reflect.Value) {
  274. if len(key) == 0 {
  275. encPanic(errNoKey)
  276. }
  277. for i := 0; i < rv.Len(); i++ {
  278. trv := rv.Index(i)
  279. if isNil(trv) {
  280. continue
  281. }
  282. enc.newline()
  283. enc.wf("%s[[%s]]", enc.indentStr(key), key)
  284. enc.newline()
  285. enc.eMapOrStruct(key, trv, false)
  286. }
  287. }
  288. func (enc *Encoder) eTable(key Key, rv reflect.Value) {
  289. if len(key) == 1 {
  290. // Output an extra newline between top-level tables.
  291. // (The newline isn't written if nothing else has been written though.)
  292. enc.newline()
  293. }
  294. if len(key) > 0 {
  295. enc.wf("%s[%s]", enc.indentStr(key), key)
  296. enc.newline()
  297. }
  298. enc.eMapOrStruct(key, rv, false)
  299. }
  300. func (enc *Encoder) eMapOrStruct(key Key, rv reflect.Value, inline bool) {
  301. switch rv := eindirect(rv); rv.Kind() {
  302. case reflect.Map:
  303. enc.eMap(key, rv, inline)
  304. case reflect.Struct:
  305. enc.eStruct(key, rv, inline)
  306. default:
  307. // Should never happen?
  308. panic("eTable: unhandled reflect.Value Kind: " + rv.Kind().String())
  309. }
  310. }
  311. func (enc *Encoder) eMap(key Key, rv reflect.Value, inline bool) {
  312. rt := rv.Type()
  313. if rt.Key().Kind() != reflect.String {
  314. encPanic(errNonString)
  315. }
  316. // Sort keys so that we have deterministic output. And write keys directly
  317. // underneath this key first, before writing sub-structs or sub-maps.
  318. var mapKeysDirect, mapKeysSub []string
  319. for _, mapKey := range rv.MapKeys() {
  320. k := mapKey.String()
  321. if typeIsTable(tomlTypeOfGo(rv.MapIndex(mapKey))) {
  322. mapKeysSub = append(mapKeysSub, k)
  323. } else {
  324. mapKeysDirect = append(mapKeysDirect, k)
  325. }
  326. }
  327. var writeMapKeys = func(mapKeys []string, trailC bool) {
  328. sort.Strings(mapKeys)
  329. for i, mapKey := range mapKeys {
  330. val := rv.MapIndex(reflect.ValueOf(mapKey))
  331. if isNil(val) {
  332. continue
  333. }
  334. if inline {
  335. enc.writeKeyValue(Key{mapKey}, val, true)
  336. if trailC || i != len(mapKeys)-1 {
  337. enc.wf(", ")
  338. }
  339. } else {
  340. enc.encode(key.add(mapKey), val)
  341. }
  342. }
  343. }
  344. if inline {
  345. enc.wf("{")
  346. }
  347. writeMapKeys(mapKeysDirect, len(mapKeysSub) > 0)
  348. writeMapKeys(mapKeysSub, false)
  349. if inline {
  350. enc.wf("}")
  351. }
  352. }
  353. const is32Bit = (32 << (^uint(0) >> 63)) == 32
  354. func (enc *Encoder) eStruct(key Key, rv reflect.Value, inline bool) {
  355. // Write keys for fields directly under this key first, because if we write
  356. // a field that creates a new table then all keys under it will be in that
  357. // table (not the one we're writing here).
  358. //
  359. // Fields is a [][]int: for fieldsDirect this always has one entry (the
  360. // struct index). For fieldsSub it contains two entries: the parent field
  361. // index from tv, and the field indexes for the fields of the sub.
  362. var (
  363. rt = rv.Type()
  364. fieldsDirect, fieldsSub [][]int
  365. addFields func(rt reflect.Type, rv reflect.Value, start []int)
  366. )
  367. addFields = func(rt reflect.Type, rv reflect.Value, start []int) {
  368. for i := 0; i < rt.NumField(); i++ {
  369. f := rt.Field(i)
  370. if f.PkgPath != "" && !f.Anonymous { /// Skip unexported fields.
  371. continue
  372. }
  373. frv := rv.Field(i)
  374. // Treat anonymous struct fields with tag names as though they are
  375. // not anonymous, like encoding/json does.
  376. //
  377. // Non-struct anonymous fields use the normal encoding logic.
  378. if f.Anonymous {
  379. t := f.Type
  380. switch t.Kind() {
  381. case reflect.Struct:
  382. if getOptions(f.Tag).name == "" {
  383. addFields(t, frv, append(start, f.Index...))
  384. continue
  385. }
  386. case reflect.Ptr:
  387. if t.Elem().Kind() == reflect.Struct && getOptions(f.Tag).name == "" {
  388. if !frv.IsNil() {
  389. addFields(t.Elem(), frv.Elem(), append(start, f.Index...))
  390. }
  391. continue
  392. }
  393. }
  394. }
  395. if typeIsTable(tomlTypeOfGo(frv)) {
  396. fieldsSub = append(fieldsSub, append(start, f.Index...))
  397. } else {
  398. // Copy so it works correct on 32bit archs; not clear why this
  399. // is needed. See #314, and https://www.reddit.com/r/golang/comments/pnx8v4
  400. // This also works fine on 64bit, but 32bit archs are somewhat
  401. // rare and this is a wee bit faster.
  402. if is32Bit {
  403. copyStart := make([]int, len(start))
  404. copy(copyStart, start)
  405. fieldsDirect = append(fieldsDirect, append(copyStart, f.Index...))
  406. } else {
  407. fieldsDirect = append(fieldsDirect, append(start, f.Index...))
  408. }
  409. }
  410. }
  411. }
  412. addFields(rt, rv, nil)
  413. writeFields := func(fields [][]int) {
  414. for _, fieldIndex := range fields {
  415. fieldType := rt.FieldByIndex(fieldIndex)
  416. fieldVal := rv.FieldByIndex(fieldIndex)
  417. if isNil(fieldVal) { /// Don't write anything for nil fields.
  418. continue
  419. }
  420. opts := getOptions(fieldType.Tag)
  421. if opts.skip {
  422. continue
  423. }
  424. keyName := fieldType.Name
  425. if opts.name != "" {
  426. keyName = opts.name
  427. }
  428. if opts.omitempty && isEmpty(fieldVal) {
  429. continue
  430. }
  431. if opts.omitzero && isZero(fieldVal) {
  432. continue
  433. }
  434. if inline {
  435. enc.writeKeyValue(Key{keyName}, fieldVal, true)
  436. if fieldIndex[0] != len(fields)-1 {
  437. enc.wf(", ")
  438. }
  439. } else {
  440. enc.encode(key.add(keyName), fieldVal)
  441. }
  442. }
  443. }
  444. if inline {
  445. enc.wf("{")
  446. }
  447. writeFields(fieldsDirect)
  448. writeFields(fieldsSub)
  449. if inline {
  450. enc.wf("}")
  451. }
  452. }
  453. // tomlTypeOfGo returns the TOML type name of the Go value's type.
  454. //
  455. // It is used to determine whether the types of array elements are mixed (which
  456. // is forbidden). If the Go value is nil, then it is illegal for it to be an
  457. // array element, and valueIsNil is returned as true.
  458. //
  459. // The type may be `nil`, which means no concrete TOML type could be found.
  460. func tomlTypeOfGo(rv reflect.Value) tomlType {
  461. if isNil(rv) || !rv.IsValid() {
  462. return nil
  463. }
  464. switch rv.Kind() {
  465. case reflect.Bool:
  466. return tomlBool
  467. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
  468. reflect.Int64,
  469. reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
  470. reflect.Uint64:
  471. return tomlInteger
  472. case reflect.Float32, reflect.Float64:
  473. return tomlFloat
  474. case reflect.Array, reflect.Slice:
  475. if typeEqual(tomlHash, tomlArrayType(rv)) {
  476. return tomlArrayHash
  477. }
  478. return tomlArray
  479. case reflect.Ptr, reflect.Interface:
  480. return tomlTypeOfGo(rv.Elem())
  481. case reflect.String:
  482. return tomlString
  483. case reflect.Map:
  484. return tomlHash
  485. case reflect.Struct:
  486. if _, ok := rv.Interface().(time.Time); ok {
  487. return tomlDatetime
  488. }
  489. if isMarshaler(rv) {
  490. return tomlString
  491. }
  492. return tomlHash
  493. default:
  494. if isMarshaler(rv) {
  495. return tomlString
  496. }
  497. encPanic(errors.New("unsupported type: " + rv.Kind().String()))
  498. panic("unreachable")
  499. }
  500. }
  501. func isMarshaler(rv reflect.Value) bool {
  502. switch rv.Interface().(type) {
  503. case encoding.TextMarshaler:
  504. return true
  505. case Marshaler:
  506. return true
  507. }
  508. // Someone used a pointer receiver: we can make it work for pointer values.
  509. if rv.CanAddr() {
  510. if _, ok := rv.Addr().Interface().(encoding.TextMarshaler); ok {
  511. return true
  512. }
  513. if _, ok := rv.Addr().Interface().(Marshaler); ok {
  514. return true
  515. }
  516. }
  517. return false
  518. }
  519. // tomlArrayType returns the element type of a TOML array. The type returned
  520. // may be nil if it cannot be determined (e.g., a nil slice or a zero length
  521. // slize). This function may also panic if it finds a type that cannot be
  522. // expressed in TOML (such as nil elements, heterogeneous arrays or directly
  523. // nested arrays of tables).
  524. func tomlArrayType(rv reflect.Value) tomlType {
  525. if isNil(rv) || !rv.IsValid() || rv.Len() == 0 {
  526. return nil
  527. }
  528. /// Don't allow nil.
  529. rvlen := rv.Len()
  530. for i := 1; i < rvlen; i++ {
  531. if tomlTypeOfGo(rv.Index(i)) == nil {
  532. encPanic(errArrayNilElement)
  533. }
  534. }
  535. firstType := tomlTypeOfGo(rv.Index(0))
  536. if firstType == nil {
  537. encPanic(errArrayNilElement)
  538. }
  539. return firstType
  540. }
  541. type tagOptions struct {
  542. skip bool // "-"
  543. name string
  544. omitempty bool
  545. omitzero bool
  546. }
  547. func getOptions(tag reflect.StructTag) tagOptions {
  548. t := tag.Get("toml")
  549. if t == "-" {
  550. return tagOptions{skip: true}
  551. }
  552. var opts tagOptions
  553. parts := strings.Split(t, ",")
  554. opts.name = parts[0]
  555. for _, s := range parts[1:] {
  556. switch s {
  557. case "omitempty":
  558. opts.omitempty = true
  559. case "omitzero":
  560. opts.omitzero = true
  561. }
  562. }
  563. return opts
  564. }
  565. func isZero(rv reflect.Value) bool {
  566. switch rv.Kind() {
  567. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  568. return rv.Int() == 0
  569. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  570. return rv.Uint() == 0
  571. case reflect.Float32, reflect.Float64:
  572. return rv.Float() == 0.0
  573. }
  574. return false
  575. }
  576. func isEmpty(rv reflect.Value) bool {
  577. switch rv.Kind() {
  578. case reflect.Array, reflect.Slice, reflect.Map, reflect.String:
  579. return rv.Len() == 0
  580. case reflect.Bool:
  581. return !rv.Bool()
  582. }
  583. return false
  584. }
  585. func (enc *Encoder) newline() {
  586. if enc.hasWritten {
  587. enc.wf("\n")
  588. }
  589. }
  590. // Write a key/value pair:
  591. //
  592. // key = <any value>
  593. //
  594. // This is also used for "k = v" in inline tables; so something like this will
  595. // be written in three calls:
  596. //
  597. // ┌────────────────────┐
  598. // │ ┌───┐ ┌─────┐│
  599. // v v v v vv
  600. // key = {k = v, k2 = v2}
  601. //
  602. func (enc *Encoder) writeKeyValue(key Key, val reflect.Value, inline bool) {
  603. if len(key) == 0 {
  604. encPanic(errNoKey)
  605. }
  606. enc.wf("%s%s = ", enc.indentStr(key), key.maybeQuoted(len(key)-1))
  607. enc.eElement(val)
  608. if !inline {
  609. enc.newline()
  610. }
  611. }
  612. func (enc *Encoder) wf(format string, v ...interface{}) {
  613. _, err := fmt.Fprintf(enc.w, format, v...)
  614. if err != nil {
  615. encPanic(err)
  616. }
  617. enc.hasWritten = true
  618. }
  619. func (enc *Encoder) indentStr(key Key) string {
  620. return strings.Repeat(enc.Indent, len(key)-1)
  621. }
  622. func encPanic(err error) {
  623. panic(tomlEncodeError{err})
  624. }
  625. func eindirect(v reflect.Value) reflect.Value {
  626. switch v.Kind() {
  627. case reflect.Ptr, reflect.Interface:
  628. return eindirect(v.Elem())
  629. default:
  630. return v
  631. }
  632. }
  633. func isNil(rv reflect.Value) bool {
  634. switch rv.Kind() {
  635. case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
  636. return rv.IsNil()
  637. default:
  638. return false
  639. }
  640. }