encode.go 18 KB

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