github.com/stellar/go-xdr@v0.0.0-20231122183749-b53fb00bcac2/xdr3/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 // used to minimize heap allocations during encoding 84 scratchBuf [8]byte 85 w io.Writer 86 } 87 88 // EncodeInt writes the XDR encoded representation of the passed 32-bit signed 89 // integer to the encapsulated writer and returns the number of bytes written. 90 // 91 // A MarshalError with an error code of ErrIO is returned if writing the data 92 // fails. 93 // 94 // Reference: 95 // 96 // RFC Section 4.1 - Integer 97 // 32-bit big-endian signed integer in range [-2147483648, 2147483647] 98 func (enc *Encoder) EncodeInt(v int32) (int, error) { 99 enc.scratchBuf[0] = byte(v >> 24) 100 enc.scratchBuf[1] = byte(v >> 16) 101 enc.scratchBuf[2] = byte(v >> 8) 102 enc.scratchBuf[3] = byte(v) 103 104 n, err := enc.w.Write(enc.scratchBuf[:4]) 105 if err != nil { 106 msg := fmt.Sprintf(errIOEncode, err.Error(), 4) 107 err := marshalError("EncodeInt", ErrIO, msg, enc.scratchBuf[:n], err) 108 return n, err 109 } 110 111 return n, nil 112 } 113 114 // EncodeUint writes the XDR encoded representation of the passed 32-bit 115 // unsigned integer to the encapsulated writer and returns the number of bytes 116 // written. 117 // 118 // A MarshalError with an error code of ErrIO is returned if writing the data 119 // fails. 120 // 121 // Reference: 122 // 123 // RFC Section 4.2 - Unsigned Integer 124 // 32-bit big-endian unsigned integer in range [0, 4294967295] 125 func (enc *Encoder) EncodeUint(v uint32) (int, error) { 126 enc.scratchBuf[0] = byte(v >> 24) 127 enc.scratchBuf[1] = byte(v >> 16) 128 enc.scratchBuf[2] = byte(v >> 8) 129 enc.scratchBuf[3] = byte(v) 130 131 n, err := enc.w.Write(enc.scratchBuf[:4]) 132 if err != nil { 133 msg := fmt.Sprintf(errIOEncode, err.Error(), 4) 134 err := marshalError("EncodeUint", ErrIO, msg, enc.scratchBuf[:4], 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 enc.scratchBuf[0] = byte(v >> 56) 193 enc.scratchBuf[1] = byte(v >> 48) 194 enc.scratchBuf[2] = byte(v >> 40) 195 enc.scratchBuf[3] = byte(v >> 32) 196 enc.scratchBuf[4] = byte(v >> 24) 197 enc.scratchBuf[5] = byte(v >> 16) 198 enc.scratchBuf[6] = byte(v >> 8) 199 enc.scratchBuf[7] = byte(v) 200 201 n, err := enc.w.Write(enc.scratchBuf[:8]) 202 if err != nil { 203 msg := fmt.Sprintf(errIOEncode, err.Error(), 8) 204 err := marshalError("EncodeHyper", ErrIO, msg, enc.scratchBuf[:8], err) 205 return n, err 206 } 207 208 return n, nil 209 } 210 211 // EncodeUhyper writes the XDR encoded representation of the passed 64-bit 212 // unsigned integer to the encapsulated writer and returns the number of bytes 213 // written. 214 // 215 // A MarshalError with an error code of ErrIO is returned if writing the data 216 // fails. 217 // 218 // Reference: 219 // 220 // RFC Section 4.5 - Unsigned Hyper Integer 221 // 64-bit big-endian unsigned integer in range [0, 18446744073709551615] 222 func (enc *Encoder) EncodeUhyper(v uint64) (int, error) { 223 enc.scratchBuf[0] = byte(v >> 56) 224 enc.scratchBuf[1] = byte(v >> 48) 225 enc.scratchBuf[2] = byte(v >> 40) 226 enc.scratchBuf[3] = byte(v >> 32) 227 enc.scratchBuf[4] = byte(v >> 24) 228 enc.scratchBuf[5] = byte(v >> 16) 229 enc.scratchBuf[6] = byte(v >> 8) 230 enc.scratchBuf[7] = byte(v) 231 232 n, err := enc.w.Write(enc.scratchBuf[:8]) 233 if err != nil { 234 msg := fmt.Sprintf(errIOEncode, err.Error(), 8) 235 err := marshalError("EncodeUhyper", ErrIO, msg, enc.scratchBuf[:n], err) 236 return n, err 237 } 238 239 return n, nil 240 } 241 242 // EncodeFloat writes the XDR encoded representation of the passed 32-bit 243 // (single-precision) floating point to the encapsulated writer and returns the 244 // number of bytes written. 245 // 246 // A MarshalError with an error code of ErrIO is returned if writing the data 247 // fails. 248 // 249 // Reference: 250 // 251 // RFC Section 4.6 - Floating Point 252 // 32-bit single-precision IEEE 754 floating point 253 func (enc *Encoder) EncodeFloat(v float32) (int, error) { 254 ui := math.Float32bits(v) 255 return enc.EncodeUint(ui) 256 } 257 258 // EncodeDouble writes the XDR encoded representation of the passed 64-bit 259 // (double-precision) floating point to the encapsulated writer and returns the 260 // number of bytes written. 261 // 262 // A MarshalError with an error code of ErrIO is returned if writing the data 263 // fails. 264 // 265 // Reference: 266 // 267 // RFC Section 4.7 - Double-Precision Floating Point 268 // 64-bit double-precision IEEE 754 floating point 269 func (enc *Encoder) EncodeDouble(v float64) (int, error) { 270 ui := math.Float64bits(v) 271 return enc.EncodeUhyper(ui) 272 } 273 274 // RFC Section 4.8 - Quadruple-Precision Floating Point 275 // 128-bit quadruple-precision floating point 276 // Not Implemented 277 278 // EncodeFixedOpaque treats the passed byte slice as opaque data of a fixed 279 // size and writes the XDR encoded representation of it to the encapsulated 280 // writer. It returns the number of bytes written. 281 // 282 // A MarshalError with an error code of ErrIO is returned if writing the data 283 // fails. 284 // 285 // Reference: 286 // 287 // RFC Section 4.9 - Fixed-Length Opaque Data 288 // Fixed-length uninterpreted data zero-padded to a multiple of four 289 func (enc *Encoder) EncodeFixedOpaque(v []byte) (int, error) { 290 l := len(v) 291 pad := (4 - (l % 4)) % 4 292 293 // Write the actual bytes. 294 n, err := enc.w.Write(v) 295 if err != nil { 296 msg := fmt.Sprintf(errIOEncode, err.Error(), len(v)) 297 err := marshalError("EncodeFixedOpaque", ErrIO, msg, v[:n], err) 298 return n, err 299 } 300 301 // Write any padding if needed. 302 if pad > 0 { 303 // the maximum value of pad is 3, so the scratch buffer should be enough 304 _ = enc.scratchBuf[2] 305 b := enc.scratchBuf[:pad] 306 for i := 0; i < pad; i++ { 307 b[i] = 0x0 308 } 309 n2, err := enc.w.Write(b) 310 n += n2 311 if err != nil { 312 written := make([]byte, l+n2) 313 copy(written, v) 314 copy(written[l:], b[:n2]) 315 msg := fmt.Sprintf(errIOEncode, err.Error(), l+pad) 316 err := marshalError("EncodeFixedOpaque", ErrIO, msg, 317 written, err) 318 return n, err 319 } 320 } 321 322 return n, nil 323 } 324 325 // EncodeOpaque treats the passed byte slice as opaque data of a variable 326 // size and writes the XDR encoded representation of it to the encapsulated 327 // writer. It returns the number of bytes written. 328 // 329 // A MarshalError with an error code of ErrIO is returned if writing the data 330 // fails. 331 // 332 // Reference: 333 // 334 // RFC Section 4.10 - Variable-Length Opaque Data 335 // Unsigned integer length followed by fixed opaque data of that length 336 func (enc *Encoder) EncodeOpaque(v []byte) (int, error) { 337 // Length of opaque data. 338 n, err := enc.EncodeUint(uint32(len(v))) 339 if err != nil { 340 return n, err 341 } 342 343 n2, err := enc.EncodeFixedOpaque(v) 344 n += n2 345 return n, err 346 } 347 348 // EncodeString writes the XDR encoded representation of the passed string 349 // to the encapsulated writer and returns the number of bytes written. 350 // Character encoding is assumed to be UTF-8 and therefore ASCII compatible. If 351 // the underlying character encoding is not compatible with this assumption, the 352 // data can instead be written as variable-length opaque data (EncodeOpaque) and 353 // manually converted as needed. 354 // 355 // A MarshalError with an error code of ErrIO is returned if writing the data 356 // fails. 357 // 358 // Reference: 359 // 360 // RFC Section 4.11 - String 361 // Unsigned integer length followed by bytes zero-padded to a multiple of four 362 func (enc *Encoder) EncodeString(v string) (int, error) { 363 // Length of string. 364 n, err := enc.EncodeUint(uint32(len(v))) 365 if err != nil { 366 return n, err 367 } 368 369 n2, err := enc.EncodeFixedOpaque([]byte(v)) 370 n += n2 371 return n, err 372 } 373 374 // encodeFixedArray writes the XDR encoded representation of each element 375 // in the passed array represented by the reflection value to the encapsulated 376 // writer and returns the number of bytes written. The ignoreOpaque flag 377 // controls whether or not uint8 (byte) elements should be encoded individually 378 // or as a fixed sequence of opaque data. 379 // 380 // A MarshalError is returned if any issues are encountered while encoding 381 // the array elements. 382 // 383 // Reference: 384 // 385 // RFC Section 4.12 - Fixed-Length Array 386 // Individually XDR encoded array elements 387 func (enc *Encoder) encodeFixedArray(v reflect.Value, ignoreOpaque bool) (int, error) { 388 // Treat [#]byte (byte is alias for uint8) as opaque data unless ignored. 389 if !ignoreOpaque && v.Type().Elem().Kind() == reflect.Uint8 { 390 // Create a slice of the underlying array for better efficiency 391 // when possible. Can't create a slice of an unaddressable 392 // value. 393 if v.CanAddr() { 394 return enc.EncodeFixedOpaque(v.Slice(0, v.Len()).Bytes()) 395 } 396 397 // When the underlying array isn't addressable fall back to 398 // copying the array into a new slice. This is rather ugly, but 399 // the inability to create a constant slice from an 400 // unaddressable array is a limitation of Go. 401 slice := make([]byte, v.Len(), v.Len()) 402 reflect.Copy(reflect.ValueOf(slice), v) 403 return enc.EncodeFixedOpaque(slice) 404 } 405 406 // Encode each array element. 407 var n int 408 for i := 0; i < v.Len(); i++ { 409 n2, err := enc.encode(v.Index(i)) 410 n += n2 411 if err != nil { 412 return n, err 413 } 414 } 415 416 return n, nil 417 } 418 419 // encodeArray writes an XDR encoded integer representing the number of 420 // elements in the passed slice represented by the reflection value followed by 421 // the XDR encoded representation of each element in slice to the encapsulated 422 // writer and returns the number of bytes written. The ignoreOpaque flag 423 // controls whether or not uint8 (byte) elements should be encoded individually 424 // or as a variable sequence of opaque data. 425 // 426 // A MarshalError is returned if any issues are encountered while encoding 427 // the array elements. 428 // 429 // Reference: 430 // 431 // RFC Section 4.13 - Variable-Length Array 432 // Unsigned integer length followed by individually XDR encoded array elements 433 func (enc *Encoder) encodeArray(v reflect.Value, ignoreOpaque bool) (int, error) { 434 numItems := uint32(v.Len()) 435 n, err := enc.EncodeUint(numItems) 436 if err != nil { 437 return n, err 438 } 439 440 n2, err := enc.encodeFixedArray(v, ignoreOpaque) 441 n += n2 442 return n, err 443 } 444 445 // encodeUnion writes an XDR encoded representation of the union's disciminant, 446 // identified by the return value of the union's SwitchFieldName() 447 // implementation, and the union's value, a populated pointer field identified 448 // by the value returned by the union's ArmForSwitch() implementation. 449 // 450 // A MarshalError is returned if any issues are encountered while encoding 451 // the union. 452 // 453 // Reference: 454 // 455 // RFC Section 4.15 - Discriminated Union 456 func (enc *Encoder) encodeUnion(v reflect.Value) (int, error) { 457 // we should have already checked that v is a union 458 // prior to this call, so we panic if v is not a union 459 u := v.Interface().(Union) 460 461 vs := v.FieldByName(u.SwitchFieldName()) 462 n, err := enc.encode(vs) 463 464 if err != nil { 465 return n, err 466 } 467 468 kind := vs.Kind() 469 var sw int32 470 if kind == reflect.Uint || kind == reflect.Uint8 || kind == reflect.Uint16 || 471 kind == reflect.Uint32 || kind == reflect.Uint64 { 472 sw = int32(vs.Uint()) 473 } else { 474 sw = int32(vs.Int()) 475 } 476 arm, ok := u.ArmForSwitch(sw) 477 478 // void arm, we're done 479 if arm == "" { 480 return n, nil 481 } 482 483 vv := v.FieldByName(arm) 484 485 if !vv.IsValid() || !ok { 486 msg := fmt.Sprintf("invalid union switch: %d", sw) 487 err := marshalError("encodeUnion", ErrBadUnionSwitch, msg, nil, nil) 488 return n, err 489 } 490 491 if vv.Kind() != reflect.Ptr { 492 msg := fmt.Sprintf("invalid union value field: %v", vv.Kind()) 493 err := marshalError("encodeUnion", ErrBadUnionValue, msg, nil, nil) 494 return n, err 495 } 496 497 if vv.IsNil() { 498 msg := fmt.Sprintf("can't encode nil union value") 499 err := marshalError("encodeUnion", ErrBadUnionValue, msg, nil, nil) 500 return n, err 501 } 502 503 n2, err := enc.encode(vv.Elem()) 504 n += n2 505 return n, err 506 } 507 508 // encodeStruct writes an XDR encoded representation of each value in the 509 // exported fields of the struct represented by the passed reflection value to 510 // the encapsulated writer and returns the number of bytes written. Pointers 511 // are automatically indirected through arbitrary depth to encode the actual 512 // value pointed to. 513 // 514 // A MarshalError is returned if any issues are encountered while encoding 515 // the elements. 516 // 517 // Reference: 518 // 519 // RFC Section 4.14 - Structure 520 // XDR encoded elements in the order of their declaration in the struct 521 func (enc *Encoder) encodeStruct(v reflect.Value) (int, error) { 522 var n int 523 vt := v.Type() 524 for i := 0; i < v.NumField(); i++ { 525 // Skip unexported fields and indirect through pointers. 526 vtf := vt.Field(i) 527 if vtf.PkgPath != "" { 528 continue 529 } 530 vf := v.Field(i) 531 532 // Handle non-opaque data to []uint8 and [#]uint8 based on struct tag. 533 tag := vtf.Tag.Get("xdropaque") 534 if tag == "false" { 535 switch vf.Kind() { 536 case reflect.Slice: 537 n2, err := enc.encodeArray(vf, true) 538 n += n2 539 if err != nil { 540 return n, err 541 } 542 continue 543 544 case reflect.Array: 545 n2, err := enc.encodeFixedArray(vf, true) 546 n += n2 547 if err != nil { 548 return n, err 549 } 550 continue 551 } 552 } 553 554 // Encode each struct field. 555 n2, err := enc.encode(vf) 556 n += n2 557 if err != nil { 558 return n, err 559 } 560 } 561 562 return n, nil 563 } 564 565 // RFC Section 4.15 - Discriminated Union 566 // RFC Section 4.16 - Void 567 // RFC Section 4.17 - Constant 568 // RFC Section 4.18 - Typedef 569 // RFC Section 4.19 - Optional data 570 // RFC Sections 4.15 though 4.19 only apply to the data specification language 571 // which is not implemented by this package. In the case of discriminated 572 // unions, struct tags are used to perform a similar function. 573 574 // encodeMap treats the map represented by the passed reflection value as a 575 // variable-length array of 2-element structures whose fields are of the same 576 // type as the map keys and elements and writes its XDR encoded representation 577 // to the encapsulated writer. It returns the number of bytes written. 578 // 579 // A MarshalError is returned if any issues are encountered while encoding 580 // the elements. 581 func (enc *Encoder) encodeMap(v reflect.Value) (int, error) { 582 // Number of elements. 583 n, err := enc.EncodeUint(uint32(v.Len())) 584 if err != nil { 585 return n, err 586 } 587 588 // Encode each key and value according to their type. 589 for _, key := range v.MapKeys() { 590 n2, err := enc.encode(key) 591 n += n2 592 if err != nil { 593 return n, err 594 } 595 596 n2, err = enc.encode(v.MapIndex(key)) 597 n += n2 598 if err != nil { 599 return n, err 600 } 601 } 602 603 return n, nil 604 } 605 606 // encodeInterface examines the interface represented by the passed reflection 607 // value to detect whether it is an interface that can be encoded if it is, 608 // extracts the underlying value to pass back into the encode function for 609 // encoding according to its type. 610 // 611 // A MarshalError is returned if any issues are encountered while encoding 612 // the interface. 613 func (enc *Encoder) encodeInterface(v reflect.Value) (int, error) { 614 if v.IsNil() || !v.CanInterface() { 615 msg := fmt.Sprintf("can't encode nil interface") 616 err := marshalError("encodeInterface", ErrNilInterface, msg, 617 nil, nil) 618 return 0, err 619 } 620 621 // Extract underlying value from the interface and indirect through pointers. 622 ve := reflect.ValueOf(v.Interface()) 623 ve = enc.indirect(ve) 624 return enc.encode(ve) 625 } 626 627 // encode is the main workhorse for marshalling via reflection. It uses 628 // the passed reflection value to choose the XDR primitives to encode into 629 // the encapsulated writer and returns the number of bytes written. It is a 630 // recursive function, so cyclic data structures are not supported and will 631 // result in an infinite loop. 632 func (enc *Encoder) encode(ve reflect.Value) (int, error) { 633 var n int 634 635 if !ve.IsValid() { 636 msg := fmt.Sprintf("type '%s' is not valid", ve.Kind().String()) 637 err := marshalError("encode", ErrUnsupportedType, msg, nil, nil) 638 return n, err 639 } 640 641 if ve.Kind() == reflect.Ptr { 642 if ve.IsNil() { 643 return enc.EncodeBool(false) 644 } 645 646 n2, err := enc.EncodeBool(true) 647 n += n2 648 649 if err != nil { 650 return n, err 651 } 652 653 n2, err = enc.encode(ve.Elem()) 654 n += n2 655 return n, err 656 } 657 658 // Handle time.Time values by encoding them as an RFC3339 formatted 659 // string with nanosecond precision. Check the type string before 660 // doing a full blown conversion to interface and type assertion since 661 // checking a string is much quicker. 662 if ve.Type().String() == "time.Time" && ve.CanInterface() { 663 viface := ve.Interface() 664 if tv, ok := viface.(time.Time); ok { 665 return enc.EncodeString(tv.Format(time.RFC3339Nano)) 666 } 667 } 668 669 // Handle native Go types. 670 switch ve.Kind() { 671 case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int: 672 val := int32(ve.Int()) 673 674 if e, ok := ve.Interface().(Enum); ok { 675 if !e.ValidEnum(val) { 676 err := marshalError("encode", ErrBadEnumValue, "invalid enum", ve, nil) 677 return 0, err 678 } 679 } 680 681 return enc.EncodeInt(val) 682 case reflect.Int64: 683 return enc.EncodeHyper(ve.Int()) 684 685 case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint: 686 return enc.EncodeUint(uint32(ve.Uint())) 687 688 case reflect.Uint64: 689 return enc.EncodeUhyper(ve.Uint()) 690 691 case reflect.Bool: 692 return enc.EncodeBool(ve.Bool()) 693 694 case reflect.Float32: 695 return enc.EncodeFloat(float32(ve.Float())) 696 697 case reflect.Float64: 698 return enc.EncodeDouble(ve.Float()) 699 700 case reflect.String: 701 return enc.EncodeString(ve.String()) 702 703 case reflect.Array: 704 return enc.encodeFixedArray(ve, false) 705 706 case reflect.Slice: 707 return enc.encodeArray(ve, false) 708 709 case reflect.Struct: 710 711 if _, ok := ve.Interface().(Union); ok { 712 return enc.encodeUnion(ve) 713 } 714 715 return enc.encodeStruct(ve) 716 717 case reflect.Map: 718 return enc.encodeMap(ve) 719 720 case reflect.Interface: 721 return enc.encodeInterface(ve) 722 } 723 724 // The only unhandled types left are unsupported. At the time of this 725 // writing the only remaining unsupported types that exist are 726 // reflect.Uintptr and reflect.UnsafePointer. 727 msg := fmt.Sprintf("unsupported Go type '%s'", ve.Kind().String()) 728 err := marshalError("encode", ErrUnsupportedType, msg, nil, nil) 729 return 0, err 730 } 731 732 // indirect dereferences pointers until it reaches a non-pointer. This allows 733 // transparent encoding through arbitrary levels of indirection. 734 func (enc *Encoder) indirect(v reflect.Value) reflect.Value { 735 rv := v 736 for rv.Kind() == reflect.Ptr { 737 rv = rv.Elem() 738 } 739 return rv 740 } 741 742 // Encode operates identically to the Marshal function with the exception of 743 // using the writer associated with the Encoder for the destination of the 744 // XDR-encoded data instead of a user-supplied writer. See the Marshal 745 // documentation for specifics. 746 func (enc *Encoder) Encode(v interface{}) (int, error) { 747 if v == nil { 748 msg := "can't marshal nil interface" 749 err := marshalError("Marshal", ErrNilInterface, msg, nil, nil) 750 return 0, err 751 } 752 753 vv := reflect.ValueOf(v) 754 vve := vv 755 for vve.Kind() == reflect.Ptr { 756 if vve.IsNil() { 757 msg := fmt.Sprintf("can't marshal nil pointer '%v'", 758 vv.Type().String()) 759 err := marshalError("Marshal", ErrBadArguments, msg, 760 nil, nil) 761 return 0, err 762 } 763 vve = vve.Elem() 764 } 765 766 return enc.encode(vve) 767 } 768 769 // NewEncoder returns an object that can be used to manually choose fields to 770 // XDR encode to the passed writer w. Typically, Marshal should be used instead 771 // of manually creating an Encoder. An Encoder, along with several of its 772 // methods to encode XDR primitives, is exposed so it is possible to perform 773 // manual encoding of data without relying on reflection should it be necessary 774 // in complex scenarios where automatic reflection-based encoding won't work. 775 func NewEncoder(w io.Writer) *Encoder { 776 return &Encoder{w: w} 777 }