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  }