marshaler.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973
  1. package toml
  2. import (
  3. "bytes"
  4. "encoding"
  5. "fmt"
  6. "io"
  7. "math"
  8. "reflect"
  9. "sort"
  10. "strconv"
  11. "strings"
  12. "time"
  13. "unicode"
  14. )
  15. // Marshal serializes a Go value as a TOML document.
  16. //
  17. // It is a shortcut for Encoder.Encode() with the default options.
  18. func Marshal(v interface{}) ([]byte, error) {
  19. var buf bytes.Buffer
  20. enc := NewEncoder(&buf)
  21. err := enc.Encode(v)
  22. if err != nil {
  23. return nil, err
  24. }
  25. return buf.Bytes(), nil
  26. }
  27. // Encoder writes a TOML document to an output stream.
  28. type Encoder struct {
  29. // output
  30. w io.Writer
  31. // global settings
  32. tablesInline bool
  33. arraysMultiline bool
  34. indentSymbol string
  35. indentTables bool
  36. }
  37. // NewEncoder returns a new Encoder that writes to w.
  38. func NewEncoder(w io.Writer) *Encoder {
  39. return &Encoder{
  40. w: w,
  41. indentSymbol: " ",
  42. }
  43. }
  44. // SetTablesInline forces the encoder to emit all tables inline.
  45. //
  46. // This behavior can be controlled on an individual struct field basis with the
  47. // inline tag:
  48. //
  49. // MyField `inline:"true"`
  50. func (enc *Encoder) SetTablesInline(inline bool) *Encoder {
  51. enc.tablesInline = inline
  52. return enc
  53. }
  54. // SetArraysMultiline forces the encoder to emit all arrays with one element per
  55. // line.
  56. //
  57. // This behavior can be controlled on an individual struct field basis with the multiline tag:
  58. //
  59. // MyField `multiline:"true"`
  60. func (enc *Encoder) SetArraysMultiline(multiline bool) *Encoder {
  61. enc.arraysMultiline = multiline
  62. return enc
  63. }
  64. // SetIndentSymbol defines the string that should be used for indentation. The
  65. // provided string is repeated for each indentation level. Defaults to two
  66. // spaces.
  67. func (enc *Encoder) SetIndentSymbol(s string) *Encoder {
  68. enc.indentSymbol = s
  69. return enc
  70. }
  71. // SetIndentTables forces the encoder to intent tables and array tables.
  72. func (enc *Encoder) SetIndentTables(indent bool) *Encoder {
  73. enc.indentTables = indent
  74. return enc
  75. }
  76. // Encode writes a TOML representation of v to the stream.
  77. //
  78. // If v cannot be represented to TOML it returns an error.
  79. //
  80. // Encoding rules
  81. //
  82. // A top level slice containing only maps or structs is encoded as [[table
  83. // array]].
  84. //
  85. // All slices not matching rule 1 are encoded as [array]. As a result, any map
  86. // or struct they contain is encoded as an {inline table}.
  87. //
  88. // Nil interfaces and nil pointers are not supported.
  89. //
  90. // Keys in key-values always have one part.
  91. //
  92. // Intermediate tables are always printed.
  93. //
  94. // By default, strings are encoded as literal string, unless they contain either
  95. // a newline character or a single quote. In that case they are emitted as
  96. // quoted strings.
  97. //
  98. // Unsigned integers larger than math.MaxInt64 cannot be encoded. Doing so
  99. // results in an error. This rule exists because the TOML specification only
  100. // requires parsers to support at least the 64 bits integer range. Allowing
  101. // larger numbers would create non-standard TOML documents, which may not be
  102. // readable (at best) by other implementations. To encode such numbers, a
  103. // solution is a custom type that implements encoding.TextMarshaler.
  104. //
  105. // When encoding structs, fields are encoded in order of definition, with their
  106. // exact name.
  107. //
  108. // Struct tags
  109. //
  110. // The encoding of each public struct field can be customized by the format
  111. // string in the "toml" key of the struct field's tag. This follows
  112. // encoding/json's convention. The format string starts with the name of the
  113. // field, optionally followed by a comma-separated list of options. The name may
  114. // be empty in order to provide options without overriding the default name.
  115. //
  116. // The "multiline" option emits strings as quoted multi-line TOML strings. It
  117. // has no effect on fields that would not be encoded as strings.
  118. //
  119. // The "inline" option turns fields that would be emitted as tables into inline
  120. // tables instead. It has no effect on other fields.
  121. //
  122. // The "omitempty" option prevents empty values or groups from being emitted.
  123. //
  124. // In addition to the "toml" tag struct tag, a "comment" tag can be used to emit
  125. // a TOML comment before the value being annotated. Comments are ignored inside
  126. // inline tables. For array tables, the comment is only present before the first
  127. // element of the array.
  128. func (enc *Encoder) Encode(v interface{}) error {
  129. var (
  130. b []byte
  131. ctx encoderCtx
  132. )
  133. ctx.inline = enc.tablesInline
  134. if v == nil {
  135. return fmt.Errorf("toml: cannot encode a nil interface")
  136. }
  137. b, err := enc.encode(b, ctx, reflect.ValueOf(v))
  138. if err != nil {
  139. return err
  140. }
  141. _, err = enc.w.Write(b)
  142. if err != nil {
  143. return fmt.Errorf("toml: cannot write: %w", err)
  144. }
  145. return nil
  146. }
  147. type valueOptions struct {
  148. multiline bool
  149. omitempty bool
  150. comment string
  151. }
  152. type encoderCtx struct {
  153. // Current top-level key.
  154. parentKey []string
  155. // Key that should be used for a KV.
  156. key string
  157. // Extra flag to account for the empty string
  158. hasKey bool
  159. // Set to true to indicate that the encoder is inside a KV, so that all
  160. // tables need to be inlined.
  161. insideKv bool
  162. // Set to true to skip the first table header in an array table.
  163. skipTableHeader bool
  164. // Should the next table be encoded as inline
  165. inline bool
  166. // Indentation level
  167. indent int
  168. // Options coming from struct tags
  169. options valueOptions
  170. }
  171. func (ctx *encoderCtx) shiftKey() {
  172. if ctx.hasKey {
  173. ctx.parentKey = append(ctx.parentKey, ctx.key)
  174. ctx.clearKey()
  175. }
  176. }
  177. func (ctx *encoderCtx) setKey(k string) {
  178. ctx.key = k
  179. ctx.hasKey = true
  180. }
  181. func (ctx *encoderCtx) clearKey() {
  182. ctx.key = ""
  183. ctx.hasKey = false
  184. }
  185. func (ctx *encoderCtx) isRoot() bool {
  186. return len(ctx.parentKey) == 0 && !ctx.hasKey
  187. }
  188. func (enc *Encoder) encode(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
  189. i := v.Interface()
  190. switch x := i.(type) {
  191. case time.Time:
  192. if x.Nanosecond() > 0 {
  193. return x.AppendFormat(b, time.RFC3339Nano), nil
  194. }
  195. return x.AppendFormat(b, time.RFC3339), nil
  196. case LocalTime:
  197. return append(b, x.String()...), nil
  198. case LocalDate:
  199. return append(b, x.String()...), nil
  200. case LocalDateTime:
  201. return append(b, x.String()...), nil
  202. }
  203. hasTextMarshaler := v.Type().Implements(textMarshalerType)
  204. if hasTextMarshaler || (v.CanAddr() && reflect.PtrTo(v.Type()).Implements(textMarshalerType)) {
  205. if !hasTextMarshaler {
  206. v = v.Addr()
  207. }
  208. if ctx.isRoot() {
  209. return nil, fmt.Errorf("toml: type %s implementing the TextMarshaler interface cannot be a root element", v.Type())
  210. }
  211. text, err := v.Interface().(encoding.TextMarshaler).MarshalText()
  212. if err != nil {
  213. return nil, err
  214. }
  215. b = enc.encodeString(b, string(text), ctx.options)
  216. return b, nil
  217. }
  218. switch v.Kind() {
  219. // containers
  220. case reflect.Map:
  221. return enc.encodeMap(b, ctx, v)
  222. case reflect.Struct:
  223. return enc.encodeStruct(b, ctx, v)
  224. case reflect.Slice:
  225. return enc.encodeSlice(b, ctx, v)
  226. case reflect.Interface:
  227. if v.IsNil() {
  228. return nil, fmt.Errorf("toml: encoding a nil interface is not supported")
  229. }
  230. return enc.encode(b, ctx, v.Elem())
  231. case reflect.Ptr:
  232. if v.IsNil() {
  233. return enc.encode(b, ctx, reflect.Zero(v.Type().Elem()))
  234. }
  235. return enc.encode(b, ctx, v.Elem())
  236. // values
  237. case reflect.String:
  238. b = enc.encodeString(b, v.String(), ctx.options)
  239. case reflect.Float32:
  240. f := v.Float()
  241. if math.IsNaN(f) {
  242. b = append(b, "nan"...)
  243. } else if f > math.MaxFloat32 {
  244. b = append(b, "inf"...)
  245. } else if f < -math.MaxFloat32 {
  246. b = append(b, "-inf"...)
  247. } else if math.Trunc(f) == f {
  248. b = strconv.AppendFloat(b, f, 'f', 1, 32)
  249. } else {
  250. b = strconv.AppendFloat(b, f, 'f', -1, 32)
  251. }
  252. case reflect.Float64:
  253. f := v.Float()
  254. if math.IsNaN(f) {
  255. b = append(b, "nan"...)
  256. } else if f > math.MaxFloat64 {
  257. b = append(b, "inf"...)
  258. } else if f < -math.MaxFloat64 {
  259. b = append(b, "-inf"...)
  260. } else if math.Trunc(f) == f {
  261. b = strconv.AppendFloat(b, f, 'f', 1, 64)
  262. } else {
  263. b = strconv.AppendFloat(b, f, 'f', -1, 64)
  264. }
  265. case reflect.Bool:
  266. if v.Bool() {
  267. b = append(b, "true"...)
  268. } else {
  269. b = append(b, "false"...)
  270. }
  271. case reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8, reflect.Uint:
  272. x := v.Uint()
  273. if x > uint64(math.MaxInt64) {
  274. return nil, fmt.Errorf("toml: not encoding uint (%d) greater than max int64 (%d)", x, int64(math.MaxInt64))
  275. }
  276. b = strconv.AppendUint(b, x, 10)
  277. case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int:
  278. b = strconv.AppendInt(b, v.Int(), 10)
  279. default:
  280. return nil, fmt.Errorf("toml: cannot encode value of type %s", v.Kind())
  281. }
  282. return b, nil
  283. }
  284. func isNil(v reflect.Value) bool {
  285. switch v.Kind() {
  286. case reflect.Ptr, reflect.Interface, reflect.Map:
  287. return v.IsNil()
  288. default:
  289. return false
  290. }
  291. }
  292. func (enc *Encoder) encodeKv(b []byte, ctx encoderCtx, options valueOptions, v reflect.Value) ([]byte, error) {
  293. var err error
  294. if (ctx.options.omitempty || options.omitempty) && isEmptyValue(v) {
  295. return b, nil
  296. }
  297. if !ctx.inline {
  298. b = enc.encodeComment(ctx.indent, options.comment, b)
  299. }
  300. b = enc.indent(ctx.indent, b)
  301. b = enc.encodeKey(b, ctx.key)
  302. b = append(b, " = "...)
  303. // create a copy of the context because the value of a KV shouldn't
  304. // modify the global context.
  305. subctx := ctx
  306. subctx.insideKv = true
  307. subctx.shiftKey()
  308. subctx.options = options
  309. b, err = enc.encode(b, subctx, v)
  310. if err != nil {
  311. return nil, err
  312. }
  313. return b, nil
  314. }
  315. func isEmptyValue(v reflect.Value) bool {
  316. switch v.Kind() {
  317. case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
  318. return v.Len() == 0
  319. case reflect.Bool:
  320. return !v.Bool()
  321. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  322. return v.Int() == 0
  323. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  324. return v.Uint() == 0
  325. case reflect.Float32, reflect.Float64:
  326. return v.Float() == 0
  327. case reflect.Interface, reflect.Ptr:
  328. return v.IsNil()
  329. }
  330. return false
  331. }
  332. const literalQuote = '\''
  333. func (enc *Encoder) encodeString(b []byte, v string, options valueOptions) []byte {
  334. if needsQuoting(v) {
  335. return enc.encodeQuotedString(options.multiline, b, v)
  336. }
  337. return enc.encodeLiteralString(b, v)
  338. }
  339. func needsQuoting(v string) bool {
  340. // TODO: vectorize
  341. for _, b := range []byte(v) {
  342. if b == '\'' || b == '\r' || b == '\n' || invalidAscii(b) {
  343. return true
  344. }
  345. }
  346. return false
  347. }
  348. // caller should have checked that the string does not contain new lines or ' .
  349. func (enc *Encoder) encodeLiteralString(b []byte, v string) []byte {
  350. b = append(b, literalQuote)
  351. b = append(b, v...)
  352. b = append(b, literalQuote)
  353. return b
  354. }
  355. //nolint:cyclop
  356. func (enc *Encoder) encodeQuotedString(multiline bool, b []byte, v string) []byte {
  357. stringQuote := `"`
  358. if multiline {
  359. stringQuote = `"""`
  360. }
  361. b = append(b, stringQuote...)
  362. if multiline {
  363. b = append(b, '\n')
  364. }
  365. const (
  366. hextable = "0123456789ABCDEF"
  367. // U+0000 to U+0008, U+000A to U+001F, U+007F
  368. nul = 0x0
  369. bs = 0x8
  370. lf = 0xa
  371. us = 0x1f
  372. del = 0x7f
  373. )
  374. for _, r := range []byte(v) {
  375. switch r {
  376. case '\\':
  377. b = append(b, `\\`...)
  378. case '"':
  379. b = append(b, `\"`...)
  380. case '\b':
  381. b = append(b, `\b`...)
  382. case '\f':
  383. b = append(b, `\f`...)
  384. case '\n':
  385. if multiline {
  386. b = append(b, r)
  387. } else {
  388. b = append(b, `\n`...)
  389. }
  390. case '\r':
  391. b = append(b, `\r`...)
  392. case '\t':
  393. b = append(b, `\t`...)
  394. default:
  395. switch {
  396. case r >= nul && r <= bs, r >= lf && r <= us, r == del:
  397. b = append(b, `\u00`...)
  398. b = append(b, hextable[r>>4])
  399. b = append(b, hextable[r&0x0f])
  400. default:
  401. b = append(b, r)
  402. }
  403. }
  404. }
  405. b = append(b, stringQuote...)
  406. return b
  407. }
  408. // caller should have checked that the string is in A-Z / a-z / 0-9 / - / _ .
  409. func (enc *Encoder) encodeUnquotedKey(b []byte, v string) []byte {
  410. return append(b, v...)
  411. }
  412. func (enc *Encoder) encodeTableHeader(ctx encoderCtx, b []byte) ([]byte, error) {
  413. if len(ctx.parentKey) == 0 {
  414. return b, nil
  415. }
  416. b = enc.encodeComment(ctx.indent, ctx.options.comment, b)
  417. b = enc.indent(ctx.indent, b)
  418. b = append(b, '[')
  419. b = enc.encodeKey(b, ctx.parentKey[0])
  420. for _, k := range ctx.parentKey[1:] {
  421. b = append(b, '.')
  422. b = enc.encodeKey(b, k)
  423. }
  424. b = append(b, "]\n"...)
  425. return b, nil
  426. }
  427. //nolint:cyclop
  428. func (enc *Encoder) encodeKey(b []byte, k string) []byte {
  429. needsQuotation := false
  430. cannotUseLiteral := false
  431. if len(k) == 0 {
  432. return append(b, "''"...)
  433. }
  434. for _, c := range k {
  435. if (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c == '_' {
  436. continue
  437. }
  438. if c == literalQuote {
  439. cannotUseLiteral = true
  440. }
  441. needsQuotation = true
  442. }
  443. if needsQuotation && needsQuoting(k) {
  444. cannotUseLiteral = true
  445. }
  446. switch {
  447. case cannotUseLiteral:
  448. return enc.encodeQuotedString(false, b, k)
  449. case needsQuotation:
  450. return enc.encodeLiteralString(b, k)
  451. default:
  452. return enc.encodeUnquotedKey(b, k)
  453. }
  454. }
  455. func (enc *Encoder) encodeMap(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
  456. if v.Type().Key().Kind() != reflect.String {
  457. return nil, fmt.Errorf("toml: type %s is not supported as a map key", v.Type().Key().Kind())
  458. }
  459. var (
  460. t table
  461. emptyValueOptions valueOptions
  462. )
  463. iter := v.MapRange()
  464. for iter.Next() {
  465. k := iter.Key().String()
  466. v := iter.Value()
  467. if isNil(v) {
  468. continue
  469. }
  470. if willConvertToTableOrArrayTable(ctx, v) {
  471. t.pushTable(k, v, emptyValueOptions)
  472. } else {
  473. t.pushKV(k, v, emptyValueOptions)
  474. }
  475. }
  476. sortEntriesByKey(t.kvs)
  477. sortEntriesByKey(t.tables)
  478. return enc.encodeTable(b, ctx, t)
  479. }
  480. func sortEntriesByKey(e []entry) {
  481. sort.Slice(e, func(i, j int) bool {
  482. return e[i].Key < e[j].Key
  483. })
  484. }
  485. type entry struct {
  486. Key string
  487. Value reflect.Value
  488. Options valueOptions
  489. }
  490. type table struct {
  491. kvs []entry
  492. tables []entry
  493. }
  494. func (t *table) pushKV(k string, v reflect.Value, options valueOptions) {
  495. for _, e := range t.kvs {
  496. if e.Key == k {
  497. return
  498. }
  499. }
  500. t.kvs = append(t.kvs, entry{Key: k, Value: v, Options: options})
  501. }
  502. func (t *table) pushTable(k string, v reflect.Value, options valueOptions) {
  503. for _, e := range t.tables {
  504. if e.Key == k {
  505. return
  506. }
  507. }
  508. t.tables = append(t.tables, entry{Key: k, Value: v, Options: options})
  509. }
  510. func walkStruct(ctx encoderCtx, t *table, v reflect.Value) {
  511. // TODO: cache this
  512. typ := v.Type()
  513. for i := 0; i < typ.NumField(); i++ {
  514. fieldType := typ.Field(i)
  515. // only consider exported fields
  516. if fieldType.PkgPath != "" {
  517. continue
  518. }
  519. tag := fieldType.Tag.Get("toml")
  520. // special field name to skip field
  521. if tag == "-" {
  522. continue
  523. }
  524. k, opts := parseTag(tag)
  525. if !isValidName(k) {
  526. k = ""
  527. }
  528. f := v.Field(i)
  529. if k == "" {
  530. if fieldType.Anonymous {
  531. if fieldType.Type.Kind() == reflect.Struct {
  532. walkStruct(ctx, t, f)
  533. }
  534. continue
  535. } else {
  536. k = fieldType.Name
  537. }
  538. }
  539. if isNil(f) {
  540. continue
  541. }
  542. options := valueOptions{
  543. multiline: opts.multiline,
  544. omitempty: opts.omitempty,
  545. comment: fieldType.Tag.Get("comment"),
  546. }
  547. if opts.inline || !willConvertToTableOrArrayTable(ctx, f) {
  548. t.pushKV(k, f, options)
  549. } else {
  550. t.pushTable(k, f, options)
  551. }
  552. }
  553. }
  554. func (enc *Encoder) encodeStruct(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
  555. var t table
  556. walkStruct(ctx, &t, v)
  557. return enc.encodeTable(b, ctx, t)
  558. }
  559. func (enc *Encoder) encodeComment(indent int, comment string, b []byte) []byte {
  560. for len(comment) > 0 {
  561. var line string
  562. idx := strings.IndexByte(comment, '\n')
  563. if idx >= 0 {
  564. line = comment[:idx]
  565. comment = comment[idx+1:]
  566. } else {
  567. line = comment
  568. comment = ""
  569. }
  570. b = enc.indent(indent, b)
  571. b = append(b, "# "...)
  572. b = append(b, line...)
  573. b = append(b, '\n')
  574. }
  575. return b
  576. }
  577. func isValidName(s string) bool {
  578. if s == "" {
  579. return false
  580. }
  581. for _, c := range s {
  582. switch {
  583. case strings.ContainsRune("!#$%&()*+-./:;<=>?@[]^_{|}~ ", c):
  584. // Backslash and quote chars are reserved, but
  585. // otherwise any punctuation chars are allowed
  586. // in a tag name.
  587. case !unicode.IsLetter(c) && !unicode.IsDigit(c):
  588. return false
  589. }
  590. }
  591. return true
  592. }
  593. type tagOptions struct {
  594. multiline bool
  595. inline bool
  596. omitempty bool
  597. }
  598. func parseTag(tag string) (string, tagOptions) {
  599. opts := tagOptions{}
  600. idx := strings.Index(tag, ",")
  601. if idx == -1 {
  602. return tag, opts
  603. }
  604. raw := tag[idx+1:]
  605. tag = string(tag[:idx])
  606. for raw != "" {
  607. var o string
  608. i := strings.Index(raw, ",")
  609. if i >= 0 {
  610. o, raw = raw[:i], raw[i+1:]
  611. } else {
  612. o, raw = raw, ""
  613. }
  614. switch o {
  615. case "multiline":
  616. opts.multiline = true
  617. case "inline":
  618. opts.inline = true
  619. case "omitempty":
  620. opts.omitempty = true
  621. }
  622. }
  623. return tag, opts
  624. }
  625. func (enc *Encoder) encodeTable(b []byte, ctx encoderCtx, t table) ([]byte, error) {
  626. var err error
  627. ctx.shiftKey()
  628. if ctx.insideKv || (ctx.inline && !ctx.isRoot()) {
  629. return enc.encodeTableInline(b, ctx, t)
  630. }
  631. if !ctx.skipTableHeader {
  632. b, err = enc.encodeTableHeader(ctx, b)
  633. if err != nil {
  634. return nil, err
  635. }
  636. if enc.indentTables && len(ctx.parentKey) > 0 {
  637. ctx.indent++
  638. }
  639. }
  640. ctx.skipTableHeader = false
  641. for _, kv := range t.kvs {
  642. ctx.setKey(kv.Key)
  643. b, err = enc.encodeKv(b, ctx, kv.Options, kv.Value)
  644. if err != nil {
  645. return nil, err
  646. }
  647. b = append(b, '\n')
  648. }
  649. for _, table := range t.tables {
  650. ctx.setKey(table.Key)
  651. ctx.options = table.Options
  652. b, err = enc.encode(b, ctx, table.Value)
  653. if err != nil {
  654. return nil, err
  655. }
  656. b = append(b, '\n')
  657. }
  658. return b, nil
  659. }
  660. func (enc *Encoder) encodeTableInline(b []byte, ctx encoderCtx, t table) ([]byte, error) {
  661. var err error
  662. b = append(b, '{')
  663. first := true
  664. for _, kv := range t.kvs {
  665. if first {
  666. first = false
  667. } else {
  668. b = append(b, `, `...)
  669. }
  670. ctx.setKey(kv.Key)
  671. b, err = enc.encodeKv(b, ctx, kv.Options, kv.Value)
  672. if err != nil {
  673. return nil, err
  674. }
  675. }
  676. if len(t.tables) > 0 {
  677. panic("inline table cannot contain nested tables, online key-values")
  678. }
  679. b = append(b, "}"...)
  680. return b, nil
  681. }
  682. func willConvertToTable(ctx encoderCtx, v reflect.Value) bool {
  683. if !v.IsValid() {
  684. return false
  685. }
  686. if v.Type() == timeType || v.Type().Implements(textMarshalerType) || (v.Kind() != reflect.Ptr && v.CanAddr() && reflect.PtrTo(v.Type()).Implements(textMarshalerType)) {
  687. return false
  688. }
  689. t := v.Type()
  690. switch t.Kind() {
  691. case reflect.Map, reflect.Struct:
  692. return !ctx.inline
  693. case reflect.Interface:
  694. return willConvertToTable(ctx, v.Elem())
  695. case reflect.Ptr:
  696. if v.IsNil() {
  697. return false
  698. }
  699. return willConvertToTable(ctx, v.Elem())
  700. default:
  701. return false
  702. }
  703. }
  704. func willConvertToTableOrArrayTable(ctx encoderCtx, v reflect.Value) bool {
  705. if ctx.insideKv {
  706. return false
  707. }
  708. t := v.Type()
  709. if t.Kind() == reflect.Interface {
  710. return willConvertToTableOrArrayTable(ctx, v.Elem())
  711. }
  712. if t.Kind() == reflect.Slice {
  713. if v.Len() == 0 {
  714. // An empty slice should be a kv = [].
  715. return false
  716. }
  717. for i := 0; i < v.Len(); i++ {
  718. t := willConvertToTable(ctx, v.Index(i))
  719. if !t {
  720. return false
  721. }
  722. }
  723. return true
  724. }
  725. return willConvertToTable(ctx, v)
  726. }
  727. func (enc *Encoder) encodeSlice(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
  728. if v.Len() == 0 {
  729. b = append(b, "[]"...)
  730. return b, nil
  731. }
  732. if willConvertToTableOrArrayTable(ctx, v) {
  733. return enc.encodeSliceAsArrayTable(b, ctx, v)
  734. }
  735. return enc.encodeSliceAsArray(b, ctx, v)
  736. }
  737. // caller should have checked that v is a slice that only contains values that
  738. // encode into tables.
  739. func (enc *Encoder) encodeSliceAsArrayTable(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
  740. ctx.shiftKey()
  741. scratch := make([]byte, 0, 64)
  742. scratch = append(scratch, "[["...)
  743. for i, k := range ctx.parentKey {
  744. if i > 0 {
  745. scratch = append(scratch, '.')
  746. }
  747. scratch = enc.encodeKey(scratch, k)
  748. }
  749. scratch = append(scratch, "]]\n"...)
  750. ctx.skipTableHeader = true
  751. b = enc.encodeComment(ctx.indent, ctx.options.comment, b)
  752. for i := 0; i < v.Len(); i++ {
  753. b = append(b, scratch...)
  754. var err error
  755. b, err = enc.encode(b, ctx, v.Index(i))
  756. if err != nil {
  757. return nil, err
  758. }
  759. }
  760. return b, nil
  761. }
  762. func (enc *Encoder) encodeSliceAsArray(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
  763. multiline := ctx.options.multiline || enc.arraysMultiline
  764. separator := ", "
  765. b = append(b, '[')
  766. subCtx := ctx
  767. subCtx.options = valueOptions{}
  768. if multiline {
  769. separator = ",\n"
  770. b = append(b, '\n')
  771. subCtx.indent++
  772. }
  773. var err error
  774. first := true
  775. for i := 0; i < v.Len(); i++ {
  776. if first {
  777. first = false
  778. } else {
  779. b = append(b, separator...)
  780. }
  781. if multiline {
  782. b = enc.indent(subCtx.indent, b)
  783. }
  784. b, err = enc.encode(b, subCtx, v.Index(i))
  785. if err != nil {
  786. return nil, err
  787. }
  788. }
  789. if multiline {
  790. b = append(b, '\n')
  791. b = enc.indent(ctx.indent, b)
  792. }
  793. b = append(b, ']')
  794. return b, nil
  795. }
  796. func (enc *Encoder) indent(level int, b []byte) []byte {
  797. for i := 0; i < level; i++ {
  798. b = append(b, enc.indentSymbol...)
  799. }
  800. return b
  801. }