marshaler.go 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133
  1. package toml
  2. import (
  3. "bytes"
  4. "encoding"
  5. "encoding/json"
  6. "fmt"
  7. "io"
  8. "math"
  9. "reflect"
  10. "slices"
  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.PointerTo(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. case keyType.Kind() == reflect.Int || keyType.Kind() == reflect.Int8 || keyType.Kind() == reflect.Int16 || keyType.Kind() == reflect.Int32 || keyType.Kind() == reflect.Int64:
  541. return strconv.FormatInt(k.Int(), 10), nil
  542. case keyType.Kind() == reflect.Uint || keyType.Kind() == reflect.Uint8 || keyType.Kind() == reflect.Uint16 || keyType.Kind() == reflect.Uint32 || keyType.Kind() == reflect.Uint64:
  543. return strconv.FormatUint(k.Uint(), 10), nil
  544. case keyType.Kind() == reflect.Float32:
  545. return strconv.FormatFloat(k.Float(), 'f', -1, 32), nil
  546. case keyType.Kind() == reflect.Float64:
  547. return strconv.FormatFloat(k.Float(), 'f', -1, 64), nil
  548. }
  549. return "", fmt.Errorf("toml: type %s is not supported as a map key", keyType.Kind())
  550. }
  551. func (enc *Encoder) encodeMap(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
  552. var (
  553. t table
  554. emptyValueOptions valueOptions
  555. )
  556. iter := v.MapRange()
  557. for iter.Next() {
  558. v := iter.Value()
  559. if isNil(v) {
  560. continue
  561. }
  562. k, err := enc.keyToString(iter.Key())
  563. if err != nil {
  564. return nil, err
  565. }
  566. if willConvertToTableOrArrayTable(ctx, v) {
  567. t.pushTable(k, v, emptyValueOptions)
  568. } else {
  569. t.pushKV(k, v, emptyValueOptions)
  570. }
  571. }
  572. sortEntriesByKey(t.kvs)
  573. sortEntriesByKey(t.tables)
  574. return enc.encodeTable(b, ctx, t)
  575. }
  576. func sortEntriesByKey(e []entry) {
  577. slices.SortFunc(e, func(a, b entry) int {
  578. return strings.Compare(a.Key, b.Key)
  579. })
  580. }
  581. type entry struct {
  582. Key string
  583. Value reflect.Value
  584. Options valueOptions
  585. }
  586. type table struct {
  587. kvs []entry
  588. tables []entry
  589. }
  590. func (t *table) pushKV(k string, v reflect.Value, options valueOptions) {
  591. for _, e := range t.kvs {
  592. if e.Key == k {
  593. return
  594. }
  595. }
  596. t.kvs = append(t.kvs, entry{Key: k, Value: v, Options: options})
  597. }
  598. func (t *table) pushTable(k string, v reflect.Value, options valueOptions) {
  599. for _, e := range t.tables {
  600. if e.Key == k {
  601. return
  602. }
  603. }
  604. t.tables = append(t.tables, entry{Key: k, Value: v, Options: options})
  605. }
  606. func walkStruct(ctx encoderCtx, t *table, v reflect.Value) {
  607. // TODO: cache this
  608. typ := v.Type()
  609. for i := 0; i < typ.NumField(); i++ {
  610. fieldType := typ.Field(i)
  611. // only consider exported fields
  612. if fieldType.PkgPath != "" {
  613. continue
  614. }
  615. tag := fieldType.Tag.Get("toml")
  616. // special field name to skip field
  617. if tag == "-" {
  618. continue
  619. }
  620. k, opts := parseTag(tag)
  621. if !isValidName(k) {
  622. k = ""
  623. }
  624. f := v.Field(i)
  625. if k == "" {
  626. if fieldType.Anonymous {
  627. if fieldType.Type.Kind() == reflect.Struct {
  628. walkStruct(ctx, t, f)
  629. } else if fieldType.Type.Kind() == reflect.Ptr && !f.IsNil() && f.Elem().Kind() == reflect.Struct {
  630. walkStruct(ctx, t, f.Elem())
  631. }
  632. continue
  633. } else {
  634. k = fieldType.Name
  635. }
  636. }
  637. if isNil(f) {
  638. continue
  639. }
  640. options := valueOptions{
  641. multiline: opts.multiline,
  642. omitempty: opts.omitempty,
  643. commented: opts.commented,
  644. comment: fieldType.Tag.Get("comment"),
  645. }
  646. if opts.inline || !willConvertToTableOrArrayTable(ctx, f) {
  647. t.pushKV(k, f, options)
  648. } else {
  649. t.pushTable(k, f, options)
  650. }
  651. }
  652. }
  653. func (enc *Encoder) encodeStruct(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
  654. var t table
  655. walkStruct(ctx, &t, v)
  656. return enc.encodeTable(b, ctx, t)
  657. }
  658. func (enc *Encoder) encodeComment(indent int, comment string, b []byte) []byte {
  659. for len(comment) > 0 {
  660. var line string
  661. idx := strings.IndexByte(comment, '\n')
  662. if idx >= 0 {
  663. line = comment[:idx]
  664. comment = comment[idx+1:]
  665. } else {
  666. line = comment
  667. comment = ""
  668. }
  669. b = enc.indent(indent, b)
  670. b = append(b, "# "...)
  671. b = append(b, line...)
  672. b = append(b, '\n')
  673. }
  674. return b
  675. }
  676. func isValidName(s string) bool {
  677. if s == "" {
  678. return false
  679. }
  680. for _, c := range s {
  681. switch {
  682. case strings.ContainsRune("!#$%&()*+-./:;<=>?@[]^_{|}~ ", c):
  683. // Backslash and quote chars are reserved, but
  684. // otherwise any punctuation chars are allowed
  685. // in a tag name.
  686. case !unicode.IsLetter(c) && !unicode.IsDigit(c):
  687. return false
  688. }
  689. }
  690. return true
  691. }
  692. type tagOptions struct {
  693. multiline bool
  694. inline bool
  695. omitempty bool
  696. commented bool
  697. }
  698. func parseTag(tag string) (string, tagOptions) {
  699. opts := tagOptions{}
  700. idx := strings.Index(tag, ",")
  701. if idx == -1 {
  702. return tag, opts
  703. }
  704. raw := tag[idx+1:]
  705. tag = string(tag[:idx])
  706. for raw != "" {
  707. var o string
  708. i := strings.Index(raw, ",")
  709. if i >= 0 {
  710. o, raw = raw[:i], raw[i+1:]
  711. } else {
  712. o, raw = raw, ""
  713. }
  714. switch o {
  715. case "multiline":
  716. opts.multiline = true
  717. case "inline":
  718. opts.inline = true
  719. case "omitempty":
  720. opts.omitempty = true
  721. case "commented":
  722. opts.commented = true
  723. }
  724. }
  725. return tag, opts
  726. }
  727. func (enc *Encoder) encodeTable(b []byte, ctx encoderCtx, t table) ([]byte, error) {
  728. var err error
  729. ctx.shiftKey()
  730. if ctx.insideKv || (ctx.inline && !ctx.isRoot()) {
  731. return enc.encodeTableInline(b, ctx, t)
  732. }
  733. if !ctx.skipTableHeader {
  734. b, err = enc.encodeTableHeader(ctx, b)
  735. if err != nil {
  736. return nil, err
  737. }
  738. if enc.indentTables && len(ctx.parentKey) > 0 {
  739. ctx.indent++
  740. }
  741. }
  742. ctx.skipTableHeader = false
  743. hasNonEmptyKV := false
  744. for _, kv := range t.kvs {
  745. if shouldOmitEmpty(kv.Options, kv.Value) {
  746. continue
  747. }
  748. hasNonEmptyKV = true
  749. ctx.setKey(kv.Key)
  750. ctx2 := ctx
  751. ctx2.commented = kv.Options.commented || ctx2.commented
  752. b, err = enc.encodeKv(b, ctx2, kv.Options, kv.Value)
  753. if err != nil {
  754. return nil, err
  755. }
  756. b = append(b, '\n')
  757. }
  758. first := true
  759. for _, table := range t.tables {
  760. if shouldOmitEmpty(table.Options, table.Value) {
  761. continue
  762. }
  763. if first {
  764. first = false
  765. if hasNonEmptyKV {
  766. b = append(b, '\n')
  767. }
  768. } else {
  769. b = append(b, "\n"...)
  770. }
  771. ctx.setKey(table.Key)
  772. ctx.options = table.Options
  773. ctx2 := ctx
  774. ctx2.commented = ctx2.commented || ctx.options.commented
  775. b, err = enc.encode(b, ctx2, table.Value)
  776. if err != nil {
  777. return nil, err
  778. }
  779. }
  780. return b, nil
  781. }
  782. func (enc *Encoder) encodeTableInline(b []byte, ctx encoderCtx, t table) ([]byte, error) {
  783. var err error
  784. b = append(b, '{')
  785. first := true
  786. for _, kv := range t.kvs {
  787. if shouldOmitEmpty(kv.Options, kv.Value) {
  788. continue
  789. }
  790. if first {
  791. first = false
  792. } else {
  793. b = append(b, `, `...)
  794. }
  795. ctx.setKey(kv.Key)
  796. b, err = enc.encodeKv(b, ctx, kv.Options, kv.Value)
  797. if err != nil {
  798. return nil, err
  799. }
  800. }
  801. if len(t.tables) > 0 {
  802. panic("inline table cannot contain nested tables, only key-values")
  803. }
  804. b = append(b, "}"...)
  805. return b, nil
  806. }
  807. func willConvertToTable(ctx encoderCtx, v reflect.Value) bool {
  808. if !v.IsValid() {
  809. return false
  810. }
  811. if v.Type() == timeType || v.Type().Implements(textMarshalerType) || (v.Kind() != reflect.Ptr && v.CanAddr() && reflect.PointerTo(v.Type()).Implements(textMarshalerType)) {
  812. return false
  813. }
  814. t := v.Type()
  815. switch t.Kind() {
  816. case reflect.Map, reflect.Struct:
  817. return !ctx.inline
  818. case reflect.Interface:
  819. return willConvertToTable(ctx, v.Elem())
  820. case reflect.Ptr:
  821. if v.IsNil() {
  822. return false
  823. }
  824. return willConvertToTable(ctx, v.Elem())
  825. default:
  826. return false
  827. }
  828. }
  829. func willConvertToTableOrArrayTable(ctx encoderCtx, v reflect.Value) bool {
  830. if ctx.insideKv {
  831. return false
  832. }
  833. t := v.Type()
  834. if t.Kind() == reflect.Interface {
  835. return willConvertToTableOrArrayTable(ctx, v.Elem())
  836. }
  837. if t.Kind() == reflect.Slice || t.Kind() == reflect.Array {
  838. if v.Len() == 0 {
  839. // An empty slice should be a kv = [].
  840. return false
  841. }
  842. for i := 0; i < v.Len(); i++ {
  843. t := willConvertToTable(ctx, v.Index(i))
  844. if !t {
  845. return false
  846. }
  847. }
  848. return true
  849. }
  850. return willConvertToTable(ctx, v)
  851. }
  852. func (enc *Encoder) encodeSlice(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
  853. if v.Len() == 0 {
  854. b = append(b, "[]"...)
  855. return b, nil
  856. }
  857. if willConvertToTableOrArrayTable(ctx, v) {
  858. return enc.encodeSliceAsArrayTable(b, ctx, v)
  859. }
  860. return enc.encodeSliceAsArray(b, ctx, v)
  861. }
  862. // caller should have checked that v is a slice that only contains values that
  863. // encode into tables.
  864. func (enc *Encoder) encodeSliceAsArrayTable(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
  865. ctx.shiftKey()
  866. scratch := make([]byte, 0, 64)
  867. scratch = enc.commented(ctx.commented, scratch)
  868. if enc.indentTables {
  869. scratch = enc.indent(ctx.indent, scratch)
  870. }
  871. scratch = append(scratch, "[["...)
  872. for i, k := range ctx.parentKey {
  873. if i > 0 {
  874. scratch = append(scratch, '.')
  875. }
  876. scratch = enc.encodeKey(scratch, k)
  877. }
  878. scratch = append(scratch, "]]\n"...)
  879. ctx.skipTableHeader = true
  880. b = enc.encodeComment(ctx.indent, ctx.options.comment, b)
  881. if enc.indentTables {
  882. ctx.indent++
  883. }
  884. for i := 0; i < v.Len(); i++ {
  885. if i != 0 {
  886. b = append(b, "\n"...)
  887. }
  888. b = append(b, scratch...)
  889. var err error
  890. b, err = enc.encode(b, ctx, v.Index(i))
  891. if err != nil {
  892. return nil, err
  893. }
  894. }
  895. return b, nil
  896. }
  897. func (enc *Encoder) encodeSliceAsArray(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
  898. multiline := ctx.options.multiline || enc.arraysMultiline
  899. separator := ", "
  900. b = append(b, '[')
  901. subCtx := ctx
  902. subCtx.options = valueOptions{}
  903. if multiline {
  904. separator = ",\n"
  905. b = append(b, '\n')
  906. subCtx.indent++
  907. }
  908. var err error
  909. first := true
  910. for i := 0; i < v.Len(); i++ {
  911. if first {
  912. first = false
  913. } else {
  914. b = append(b, separator...)
  915. }
  916. if multiline {
  917. b = enc.indent(subCtx.indent, b)
  918. }
  919. b, err = enc.encode(b, subCtx, v.Index(i))
  920. if err != nil {
  921. return nil, err
  922. }
  923. }
  924. if multiline {
  925. b = append(b, '\n')
  926. b = enc.indent(ctx.indent, b)
  927. }
  928. b = append(b, ']')
  929. return b, nil
  930. }
  931. func (enc *Encoder) indent(level int, b []byte) []byte {
  932. for i := 0; i < level; i++ {
  933. b = append(b, enc.indentSymbol...)
  934. }
  935. return b
  936. }