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