github.com/stellar/go-xdr@v0.0.0-20231122183749-b53fb00bcac2/xdr2/encode.go (about) 1 /* 2 * Copyright (c) 2012-2014 Dave Collins <dave@davec.name> 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 package xdr 18 19 import ( 20 "fmt" 21 "io" 22 "math" 23 "reflect" 24 "time" 25 ) 26 27 var errIOEncode = "%s while encoding %d bytes" 28 29 /* 30 Marshal writes the XDR encoding of v to writer w and returns the number of bytes 31 written. It traverses v recursively and automatically indirects pointers 32 through arbitrary depth to encode the actual value pointed to. 33 34 Marshal uses reflection to determine the type of the concrete value contained by 35 v and performs a mapping of Go types to the underlying XDR types as follows: 36 37 Go Type -> XDR Type 38 -------------------- 39 int8, int16, int32, int -> XDR Integer 40 uint8, uint16, uint32, uint -> XDR Unsigned Integer 41 int64 -> XDR Hyper Integer 42 uint64 -> XDR Unsigned Hyper Integer 43 bool -> XDR Boolean 44 float32 -> XDR Floating-Point 45 float64 -> XDR Double-Precision Floating-Point 46 string -> XDR String 47 byte -> XDR Integer 48 []byte -> XDR Variable-Length Opaque Data 49 [#]byte -> XDR Fixed-Length Opaque Data 50 []<type> -> XDR Variable-Length Array 51 [#]<type> -> XDR Fixed-Length Array 52 struct -> XDR Structure 53 map -> XDR Variable-Length Array of two-element XDR Structures 54 time.Time -> XDR String encoded with RFC3339 nanosecond precision 55 56 Notes and Limitations: 57 58 - Automatic marshalling of variable and fixed-length arrays of uint8s 59 requires a special struct tag `xdropaque:"false"` since byte slices and 60 byte arrays are assumed to be opaque data and byte is a Go alias for uint8 61 thus indistinguishable under reflection 62 - Channel, complex, and function types cannot be encoded 63 - Interfaces without a concrete value cannot be encoded 64 - Cyclic data structures are not supported and will result in infinite loops 65 - Strings are marshalled with UTF-8 character encoding which differs from 66 the XDR specification of ASCII, however UTF-8 is backwards compatible with 67 ASCII so this should rarely cause issues 68 69 If any issues are encountered during the marshalling process, a MarshalError is 70 returned with a human readable description as well as an ErrorCode value for 71 further inspection from sophisticated callers. Some potential issues are 72 unsupported Go types, attempting to encode more opaque data than can be 73 represented by a single opaque XDR entry, and exceeding max slice limitations. 74 */ 75 func Marshal(w io.Writer, v interface{}) (int, error) { 76 enc := Encoder{w: w} 77 return enc.Encode(v) 78 } 79 80 // An Encoder wraps an io.Writer that will receive the XDR encoded byte stream. 81 // See NewEncoder. 82 type Encoder struct { 83 w io.Writer 84 } 85 86 // EncodeInt writes the XDR encoded representation of the passed 32-bit signed 87 // integer to the encapsulated writer and returns the number of bytes written. 88 // 89 // A MarshalError with an error code of ErrIO is returned if writing the data 90 // fails. 91 // 92 // Reference: 93 // 94 // RFC Section 4.1 - Integer 95 // 32-bit big-endian signed integer in range [-2147483648, 2147483647] 96 func (enc *Encoder) EncodeInt(v int32) (int, error) { 97 var b [4]byte 98 b[0] = byte(v >> 24) 99 b[1] = byte(v >> 16) 100 b[2] = byte(v >> 8) 101 b[3] = byte(v) 102 103 n, err := enc.w.Write(b[:]) 104 if err != nil { 105 msg := fmt.Sprintf(errIOEncode, err.Error(), 4) 106 err := marshalError("EncodeInt", ErrIO, msg, b[:n], err) 107 return n, err 108 } 109 110 return n, nil 111 } 112 113 // EncodeUint writes the XDR encoded representation of the passed 32-bit 114 // unsigned integer to the encapsulated writer and returns the number of bytes 115 // written. 116 // 117 // A MarshalError with an error code of ErrIO is returned if writing the data 118 // fails. 119 // 120 // Reference: 121 // 122 // RFC Section 4.2 - Unsigned Integer 123 // 32-bit big-endian unsigned integer in range [0, 4294967295] 124 func (enc *Encoder) EncodeUint(v uint32) (int, error) { 125 var b [4]byte 126 b[0] = byte(v >> 24) 127 b[1] = byte(v >> 16) 128 b[2] = byte(v >> 8) 129 b[3] = byte(v) 130 131 n, err := enc.w.Write(b[:]) 132 if err != nil { 133 msg := fmt.Sprintf(errIOEncode, err.Error(), 4) 134 err := marshalError("EncodeUint", ErrIO, msg, b[:n], err) 135 return n, err 136 } 137 138 return n, nil 139 } 140 141 // EncodeEnum treats the passed 32-bit signed integer as an enumeration value 142 // and, if it is in the list of passed valid enumeration values, writes the XDR 143 // encoded representation of it to the encapsulated writer. It returns the 144 // number of bytes written. 145 // 146 // A MarshalError is returned if the enumeration value is not one of the 147 // provided valid values or if writing the data fails. 148 // 149 // Reference: 150 // 151 // RFC Section 4.3 - Enumeration 152 // Represented as an XDR encoded signed integer 153 func (enc *Encoder) EncodeEnum(v int32, validEnums map[int32]bool) (int, error) { 154 if !validEnums[v] { 155 err := marshalError("EncodeEnum", ErrBadEnumValue, 156 "invalid enum", v, nil) 157 return 0, err 158 } 159 return enc.EncodeInt(v) 160 } 161 162 // EncodeBool writes the XDR encoded representation of the passed boolean to the 163 // encapsulated writer and returns the number of bytes written. 164 // 165 // A MarshalError with an error code of ErrIO is returned if writing the data 166 // fails. 167 // 168 // Reference: 169 // 170 // RFC Section 4.4 - Boolean 171 // Represented as an XDR encoded enumeration where 0 is false and 1 is true 172 func (enc *Encoder) EncodeBool(v bool) (int, error) { 173 i := int32(0) 174 if v == true { 175 i = 1 176 } 177 return enc.EncodeInt(i) 178 } 179 180 // EncodeHyper writes the XDR encoded representation of the passed 64-bit 181 // signed integer to the encapsulated writer and returns the number of bytes 182 // written. 183 // 184 // A MarshalError with an error code of ErrIO is returned if writing the data 185 // fails. 186 // 187 // Reference: 188 // 189 // RFC Section 4.5 - Hyper Integer 190 // 64-bit big-endian signed integer in range [-9223372036854775808, 9223372036854775807] 191 func (enc *Encoder) EncodeHyper(v int64) (int, error) { 192 var b [8]byte 193 b[0] = byte(v >> 56) 194 b[1] = byte(v >> 48) 195 b[2] = byte(v >> 40) 196 b[3] = byte(v >> 32) 197 b[4] = byte(v >> 24) 198 b[5] = byte(v >> 16) 199 b[6] = byte(v >> 8) 200 b[7] = byte(v) 201 202 n, err := enc.w.Write(b[:]) 203 if err != nil { 204 msg := fmt.Sprintf(errIOEncode, err.Error(), 8) 205 err := marshalError("EncodeHyper", ErrIO, msg, b[:n], err) 206 return n, err 207 } 208 209 return n, nil 210 } 211 212 // EncodeUhyper writes the XDR encoded representation of the passed 64-bit 213 // unsigned integer to the encapsulated writer and returns the number of bytes 214 // written. 215 // 216 // A MarshalError with an error code of ErrIO is returned if writing the data 217 // fails. 218 // 219 // Reference: 220 // 221 // RFC Section 4.5 - Unsigned Hyper Integer 222 // 64-bit big-endian unsigned integer in range [0, 18446744073709551615] 223 func (enc *Encoder) EncodeUhyper(v uint64) (int, error) { 224 var b [8]byte 225 b[0] = byte(v >> 56) 226 b[1] = byte(v >> 48) 227 b[2] = byte(v >> 40) 228 b[3] = byte(v >> 32) 229 b[4] = byte(v >> 24) 230 b[5] = byte(v >> 16) 231 b[6] = byte(v >> 8) 232 b[7] = byte(v) 233 234 n, err := enc.w.Write(b[:]) 235 if err != nil { 236 msg := fmt.Sprintf(errIOEncode, err.Error(), 8) 237 err := marshalError("EncodeUhyper", ErrIO, msg, b[:n], err) 238 return n, err 239 } 240 241 return n, nil 242 } 243 244 // EncodeFloat writes the XDR encoded representation of the passed 32-bit 245 // (single-precision) floating point to the encapsulated writer and returns the 246 // number of bytes written. 247 // 248 // A MarshalError with an error code of ErrIO is returned if writing the data 249 // fails. 250 // 251 // Reference: 252 // 253 // RFC Section 4.6 - Floating Point 254 // 32-bit single-precision IEEE 754 floating point 255 func (enc *Encoder) EncodeFloat(v float32) (int, error) { 256 ui := math.Float32bits(v) 257 return enc.EncodeUint(ui) 258 } 259 260 // EncodeDouble writes the XDR encoded representation of the passed 64-bit 261 // (double-precision) floating point to the encapsulated writer and returns the 262 // number of bytes written. 263 // 264 // A MarshalError with an error code of ErrIO is returned if writing the data 265 // fails. 266 // 267 // Reference: 268 // 269 // RFC Section 4.7 - Double-Precision Floating Point 270 // 64-bit double-precision IEEE 754 floating point 271 func (enc *Encoder) EncodeDouble(v float64) (int, error) { 272 ui := math.Float64bits(v) 273 return enc.EncodeUhyper(ui) 274 } 275 276 // RFC Section 4.8 - Quadruple-Precision Floating Point 277 // 128-bit quadruple-precision floating point 278 // Not Implemented 279 280 // EncodeFixedOpaque treats the passed byte slice as opaque data of a fixed 281 // size and writes the XDR encoded representation of it to the encapsulated 282 // writer. It returns the number of bytes written. 283 // 284 // A MarshalError with an error code of ErrIO is returned if writing the data 285 // fails. 286 // 287 // Reference: 288 // 289 // RFC Section 4.9 - Fixed-Length Opaque Data 290 // Fixed-length uninterpreted data zero-padded to a multiple of four 291 func (enc *Encoder) EncodeFixedOpaque(v []byte) (int, error) { 292 l := len(v) 293 pad := (4 - (l % 4)) % 4 294 295 // Write the actual bytes. 296 n, err := enc.w.Write(v) 297 if err != nil { 298 msg := fmt.Sprintf(errIOEncode, err.Error(), len(v)) 299 err := marshalError("EncodeFixedOpaque", ErrIO, msg, v[:n], err) 300 return n, err 301 } 302 303 // Write any padding if needed. 304 if pad > 0 { 305 b := make([]byte, pad) 306 n2, err := enc.w.Write(b) 307 n += n2 308 if err != nil { 309 written := make([]byte, l+n2) 310 copy(written, v) 311 copy(written[l:], b[:n2]) 312 msg := fmt.Sprintf(errIOEncode, err.Error(), l+pad) 313 err := marshalError("EncodeFixedOpaque", ErrIO, msg, 314 written, err) 315 return n, err 316 } 317 } 318 319 return n, nil 320 } 321 322 // EncodeOpaque treats the passed byte slice as opaque data of a variable 323 // size and writes the XDR encoded representation of it to the encapsulated 324 // writer. It returns the number of bytes written. 325 // 326 // A MarshalError with an error code of ErrIO is returned if writing the data 327 // fails. 328 // 329 // Reference: 330 // 331 // RFC Section 4.10 - Variable-Length Opaque Data 332 // Unsigned integer length followed by fixed opaque data of that length 333 func (enc *Encoder) EncodeOpaque(v []byte) (int, error) { 334 // Length of opaque data. 335 n, err := enc.EncodeUint(uint32(len(v))) 336 if err != nil { 337 return n, err 338 } 339 340 n2, err := enc.EncodeFixedOpaque(v) 341 n += n2 342 return n, err 343 } 344 345 // EncodeString writes the XDR encoded representation of the passed string 346 // to the encapsulated writer and returns the number of bytes written. 347 // Character encoding is assumed to be UTF-8 and therefore ASCII compatible. If 348 // the underlying character encoding is not compatible with this assumption, the 349 // data can instead be written as variable-length opaque data (EncodeOpaque) and 350 // manually converted as needed. 351 // 352 // A MarshalError with an error code of ErrIO is returned if writing the data 353 // fails. 354 // 355 // Reference: 356 // 357 // RFC Section 4.11 - String 358 // Unsigned integer length followed by bytes zero-padded to a multiple of four 359 func (enc *Encoder) EncodeString(v string) (int, error) { 360 // Length of string. 361 n, err := enc.EncodeUint(uint32(len(v))) 362 if err != nil { 363 return n, err 364 } 365 366 n2, err := enc.EncodeFixedOpaque([]byte(v)) 367 n += n2 368 return n, err 369 } 370 371 // encodeFixedArray writes the XDR encoded representation of each element 372 // in the passed array represented by the reflection value to the encapsulated 373 // writer and returns the number of bytes written. The ignoreOpaque flag 374 // controls whether or not uint8 (byte) elements should be encoded individually 375 // or as a fixed sequence of opaque data. 376 // 377 // A MarshalError is returned if any issues are encountered while encoding 378 // the array elements. 379 // 380 // Reference: 381 // 382 // RFC Section 4.12 - Fixed-Length Array 383 // Individually XDR encoded array elements 384 func (enc *Encoder) encodeFixedArray(v reflect.Value, ignoreOpaque bool) (int, error) { 385 // Treat [#]byte (byte is alias for uint8) as opaque data unless ignored. 386 if !ignoreOpaque && v.Type().Elem().Kind() == reflect.Uint8 { 387 // Create a slice of the underlying array for better efficiency 388 // when possible. Can't create a slice of an unaddressable 389 // value. 390 if v.CanAddr() { 391 return enc.EncodeFixedOpaque(v.Slice(0, v.Len()).Bytes()) 392 } 393 394 // When the underlying array isn't addressable fall back to 395 // copying the array into a new slice. This is rather ugly, but 396 // the inability to create a constant slice from an 397 // unaddressable array is a limitation of Go. 398 slice := make([]byte, v.Len(), v.Len()) 399 reflect.Copy(reflect.ValueOf(slice), v) 400 return enc.EncodeFixedOpaque(slice) 401 } 402 403 // Encode each array element. 404 var n int 405 for i := 0; i < v.Len(); i++ { 406 n2, err := enc.encode(v.Index(i)) 407 n += n2 408 if err != nil { 409 return n, err 410 } 411 } 412 413 return n, nil 414 } 415 416 // encodeArray writes an XDR encoded integer representing the number of 417 // elements in the passed slice represented by the reflection value followed by 418 // the XDR encoded representation of each element in slice to the encapsulated 419 // writer and returns the number of bytes written. The ignoreOpaque flag 420 // controls whether or not uint8 (byte) elements should be encoded individually 421 // or as a variable sequence of opaque data. 422 // 423 // A MarshalError is returned if any issues are encountered while encoding 424 // the array elements. 425 // 426 // Reference: 427 // 428 // RFC Section 4.13 - Variable-Length Array 429 // Unsigned integer length followed by individually XDR encoded array elements 430 func (enc *Encoder) encodeArray(v reflect.Value, ignoreOpaque bool) (int, error) { 431 numItems := uint32(v.Len()) 432 n, err := enc.EncodeUint(numItems) 433 if err != nil { 434 return n, err 435 } 436 437 n2, err := enc.encodeFixedArray(v, ignoreOpaque) 438 n += n2 439 return n, err 440 } 441 442 // encodeStruct writes an XDR encoded representation of each value in the 443 // exported fields of the struct represented by the passed reflection value to 444 // the encapsulated writer and returns the number of bytes written. Pointers 445 // are automatically indirected through arbitrary depth to encode the actual 446 // value pointed to. 447 // 448 // A MarshalError is returned if any issues are encountered while encoding 449 // the elements. 450 // 451 // Reference: 452 // 453 // RFC Section 4.14 - Structure 454 // XDR encoded elements in the order of their declaration in the struct 455 func (enc *Encoder) encodeStruct(v reflect.Value) (int, error) { 456 var n int 457 vt := v.Type() 458 for i := 0; i < v.NumField(); i++ { 459 // Skip unexported fields and indirect through pointers. 460 vtf := vt.Field(i) 461 if vtf.PkgPath != "" { 462 continue 463 } 464 vf := v.Field(i) 465 vf = enc.indirect(vf) 466 467 // Handle non-opaque data to []uint8 and [#]uint8 based on struct tag. 468 tag := vtf.Tag.Get("xdropaque") 469 if tag == "false" { 470 switch vf.Kind() { 471 case reflect.Slice: 472 n2, err := enc.encodeArray(vf, true) 473 n += n2 474 if err != nil { 475 return n, err 476 } 477 continue 478 479 case reflect.Array: 480 n2, err := enc.encodeFixedArray(vf, true) 481 n += n2 482 if err != nil { 483 return n, err 484 } 485 continue 486 } 487 } 488 489 // Encode each struct field. 490 n2, err := enc.encode(vf) 491 n += n2 492 if err != nil { 493 return n, err 494 } 495 } 496 497 return n, nil 498 } 499 500 // RFC Section 4.15 - Discriminated Union 501 // RFC Section 4.16 - Void 502 // RFC Section 4.17 - Constant 503 // RFC Section 4.18 - Typedef 504 // RFC Section 4.19 - Optional data 505 // RFC Sections 4.15 though 4.19 only apply to the data specification language 506 // which is not implemented by this package. In the case of discriminated 507 // unions, struct tags are used to perform a similar function. 508 509 // encodeMap treats the map represented by the passed reflection value as a 510 // variable-length array of 2-element structures whose fields are of the same 511 // type as the map keys and elements and writes its XDR encoded representation 512 // to the encapsulated writer. It returns the number of bytes written. 513 // 514 // A MarshalError is returned if any issues are encountered while encoding 515 // the elements. 516 func (enc *Encoder) encodeMap(v reflect.Value) (int, error) { 517 // Number of elements. 518 n, err := enc.EncodeUint(uint32(v.Len())) 519 if err != nil { 520 return n, err 521 } 522 523 // Encode each key and value according to their type. 524 for _, key := range v.MapKeys() { 525 n2, err := enc.encode(key) 526 n += n2 527 if err != nil { 528 return n, err 529 } 530 531 n2, err = enc.encode(v.MapIndex(key)) 532 n += n2 533 if err != nil { 534 return n, err 535 } 536 } 537 538 return n, nil 539 } 540 541 // encodeInterface examines the interface represented by the passed reflection 542 // value to detect whether it is an interface that can be encoded if it is, 543 // extracts the underlying value to pass back into the encode function for 544 // encoding according to its type. 545 // 546 // A MarshalError is returned if any issues are encountered while encoding 547 // the interface. 548 func (enc *Encoder) encodeInterface(v reflect.Value) (int, error) { 549 if v.IsNil() || !v.CanInterface() { 550 msg := fmt.Sprintf("can't encode nil interface") 551 err := marshalError("encodeInterface", ErrNilInterface, msg, 552 nil, nil) 553 return 0, err 554 } 555 556 // Extract underlying value from the interface and indirect through pointers. 557 ve := reflect.ValueOf(v.Interface()) 558 ve = enc.indirect(ve) 559 return enc.encode(ve) 560 } 561 562 // encode is the main workhorse for marshalling via reflection. It uses 563 // the passed reflection value to choose the XDR primitives to encode into 564 // the encapsulated writer and returns the number of bytes written. It is a 565 // recursive function, so cyclic data structures are not supported and will 566 // result in an infinite loop. 567 func (enc *Encoder) encode(v reflect.Value) (int, error) { 568 if !v.IsValid() { 569 msg := fmt.Sprintf("type '%s' is not valid", v.Kind().String()) 570 err := marshalError("encode", ErrUnsupportedType, msg, nil, nil) 571 return 0, err 572 } 573 574 // Indirect through pointers to get at the concrete value. 575 ve := enc.indirect(v) 576 577 // Handle time.Time values by encoding them as an RFC3339 formatted 578 // string with nanosecond precision. Check the type string before 579 // doing a full blown conversion to interface and type assertion since 580 // checking a string is much quicker. 581 if ve.Type().String() == "time.Time" && ve.CanInterface() { 582 viface := ve.Interface() 583 if tv, ok := viface.(time.Time); ok { 584 return enc.EncodeString(tv.Format(time.RFC3339Nano)) 585 } 586 } 587 588 // Handle native Go types. 589 switch ve.Kind() { 590 case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int: 591 return enc.EncodeInt(int32(ve.Int())) 592 593 case reflect.Int64: 594 return enc.EncodeHyper(ve.Int()) 595 596 case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint: 597 return enc.EncodeUint(uint32(ve.Uint())) 598 599 case reflect.Uint64: 600 return enc.EncodeUhyper(ve.Uint()) 601 602 case reflect.Bool: 603 return enc.EncodeBool(ve.Bool()) 604 605 case reflect.Float32: 606 return enc.EncodeFloat(float32(ve.Float())) 607 608 case reflect.Float64: 609 return enc.EncodeDouble(ve.Float()) 610 611 case reflect.String: 612 return enc.EncodeString(ve.String()) 613 614 case reflect.Array: 615 return enc.encodeFixedArray(ve, false) 616 617 case reflect.Slice: 618 return enc.encodeArray(ve, false) 619 620 case reflect.Struct: 621 return enc.encodeStruct(ve) 622 623 case reflect.Map: 624 return enc.encodeMap(ve) 625 626 case reflect.Interface: 627 return enc.encodeInterface(ve) 628 } 629 630 // The only unhandled types left are unsupported. At the time of this 631 // writing the only remaining unsupported types that exist are 632 // reflect.Uintptr and reflect.UnsafePointer. 633 msg := fmt.Sprintf("unsupported Go type '%s'", ve.Kind().String()) 634 err := marshalError("encode", ErrUnsupportedType, msg, nil, nil) 635 return 0, err 636 } 637 638 // indirect dereferences pointers until it reaches a non-pointer. This allows 639 // transparent encoding through arbitrary levels of indirection. 640 func (enc *Encoder) indirect(v reflect.Value) reflect.Value { 641 rv := v 642 for rv.Kind() == reflect.Ptr { 643 rv = rv.Elem() 644 } 645 return rv 646 } 647 648 // Encode operates identically to the Marshal function with the exception of 649 // using the writer associated with the Encoder for the destination of the 650 // XDR-encoded data instead of a user-supplied writer. See the Marshal 651 // documentation for specifics. 652 func (enc *Encoder) Encode(v interface{}) (int, error) { 653 if v == nil { 654 msg := "can't marshal nil interface" 655 err := marshalError("Marshal", ErrNilInterface, msg, nil, nil) 656 return 0, err 657 } 658 659 vv := reflect.ValueOf(v) 660 vve := vv 661 for vve.Kind() == reflect.Ptr { 662 if vve.IsNil() { 663 msg := fmt.Sprintf("can't marshal nil pointer '%v'", 664 vv.Type().String()) 665 err := marshalError("Marshal", ErrBadArguments, msg, 666 nil, nil) 667 return 0, err 668 } 669 vve = vve.Elem() 670 } 671 672 return enc.encode(vve) 673 } 674 675 // NewEncoder returns an object that can be used to manually choose fields to 676 // XDR encode to the passed writer w. Typically, Marshal should be used instead 677 // of manually creating an Encoder. An Encoder, along with several of its 678 // methods to encode XDR primitives, is exposed so it is possible to perform 679 // manual encoding of data without relying on reflection should it be necessary 680 // in complex scenarios where automatic reflection-based encoding won't work. 681 func NewEncoder(w io.Writer) *Encoder { 682 return &Encoder{w: w} 683 }