marshaler.go 24 KB

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