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