encode.go (19658B)
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 }