marshaler.go 23 KB

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