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  }