func (enc *Encoder) encodeMap(v reflect.Value) (err error) {
	dataLen := v.Len()
	if uint(dataLen) > math.MaxUint32 {
		err = marshalError("encodeMap", ErrOverflow, errMaxXdr, dataLen)
		return
	}
	err = enc.EncodeUint(uint32(dataLen))
	if err != nil {
		return
	}
	for _, key := range v.MapKeys() {
		err = enc.encode(key)
		if err != nil {
			return
		}
		err = enc.encode(v.MapIndex(key))
		if err != nil {
			return
		}
	}
	return
}
RFC Section 4.15 - Discriminated Union
RFC Section 4.16 - Void
RFC Section 4.17 - Constant
RFC Section 4.18 - Typedef
RFC Section 4.19 - Optional data
RFC Sections 4.15 though 4.19 only apply to the data specification language
which is not implemented by this package.  In the case of discriminated
unions, struct tags are used to perform a similar function.
encodeMap treats the map represented by the passed reflection value as a
variable-length array of 2-element structures whose fields are of the same
type as the map keys and elements and appends its XDR encoded representation
to the Encoder's data.

A MarshalError is returned if any issues are encountered while encoding
the elements.
package xdr
import (
	"fmt"
	"math"
	"reflect"
	"time"
)
var errMaxXdr = "data exceeds max xdr size limit"
func Marshal(v interface{}) (rv []byte, err error) {
	if v == nil {
		msg := "can't marshal nil interface"
		err = marshalError("Marshal", ErrNilInterface, msg, nil)
		return nil, err
	}
	vv := reflect.ValueOf(v)
	vve := vv
	for vve.Kind() == reflect.Ptr {
		if vve.IsNil() {
			msg := fmt.Sprintf("can't marshal nil pointer '%v'",
				vv.Type().String())
			err = marshalError("Marshal", ErrBadArguments, msg, nil)
			return nil, err
		}
		vve = vve.Elem()
	}
	enc := Encoder{}
	err = enc.encode(vve)
	return enc.data, err
}
type Encoder struct {
	data []byte
	off  int
}
func (enc *Encoder) EncodeInt(v int32) (err error) {
	b := make([]byte, 4, 4)
	b[0] = byte(v >> 24)
	b[1] = byte(v >> 16)
	b[2] = byte(v >> 8)
	b[3] = byte(v)
	if len(enc.data) > maxInt-4 {
		err = marshalError("EncodeInt", ErrOverflow, errMaxSlice, b)
		return
	}
	enc.data = append(enc.data, b...)
	return
}
func (enc *Encoder) EncodeUint(v uint32) (err error) {
	b := make([]byte, 4, 4)
	b[0] = byte(v >> 24)
	b[1] = byte(v >> 16)
	b[2] = byte(v >> 8)
	b[3] = byte(v)
	if len(enc.data) > maxInt-4 {
		err = marshalError("EncodeUint", ErrOverflow, errMaxSlice, b)
		return
	}
	enc.data = append(enc.data, b...)
	return
}
func (enc *Encoder) EncodeEnum(v int32, validEnums map[int32]bool) (err error) {
	if !validEnums[v] {
		err = marshalError("EncodeEnum", ErrBadEnumValue, "invalid enum", v)
		return
	}
	return enc.EncodeInt(v)
}
func (enc *Encoder) EncodeBool(v bool) (err error) {
	i := int32(0)
	if v == true {
		i = 1
	}
	return enc.EncodeInt(i)
}
func (enc *Encoder) EncodeHyper(v int64) (err error) {
	b := make([]byte, 8, 8)
	b[0] = byte(v >> 56)
	b[1] = byte(v >> 48)
	b[2] = byte(v >> 40)
	b[3] = byte(v >> 32)
	b[4] = byte(v >> 24)
	b[5] = byte(v >> 16)
	b[6] = byte(v >> 8)
	b[7] = byte(v)
	if len(enc.data) > maxInt-8 {
		err = marshalError("EncodeHyper", ErrOverflow, errMaxSlice, b)
		return
	}
	enc.data = append(enc.data, b...)
	return
}
func (enc *Encoder) EncodeUhyper(v uint64) (err error) {
	b := make([]byte, 8, 8)
	b[0] = byte(v >> 56)
	b[1] = byte(v >> 48)
	b[2] = byte(v >> 40)
	b[3] = byte(v >> 32)
	b[4] = byte(v >> 24)
	b[5] = byte(v >> 16)
	b[6] = byte(v >> 8)
	b[7] = byte(v)
	if len(enc.data) > maxInt-8 {
		err = marshalError("EncodeUhyper", ErrOverflow, errMaxSlice, b)
		return
	}
	enc.data = append(enc.data, b...)
	return
}
func (enc *Encoder) EncodeFloat(v float32) (err error) {
	ui := math.Float32bits(v)
	return enc.EncodeUint(ui)
}
func (enc *Encoder) EncodeDouble(v float64) (err error) {
	ui := math.Float64bits(v)
	return enc.EncodeUhyper(ui)
}
func (enc *Encoder) EncodeFixedOpaque(v []byte) (err error) {
	l := len(v)
	pad := (4 - (l % 4)) % 4
	size := l + pad
	if len(enc.data) > maxInt-size {
		err = marshalError("EncodeFixedOpaque", ErrOverflow, errMaxSlice, size)
		return
	}
	enc.data = append(enc.data, v...)
	if pad > 0 {
		b := make([]byte, pad, pad)
		for i := 0; i < pad; i++ {
			b[i] = 0
		}
		enc.data = append(enc.data, b...)
	}
	return
}
func (enc *Encoder) EncodeOpaque(v []byte) (err error) {
	dataLen := len(v)
	if uint(dataLen) > math.MaxUint32 {
		err = marshalError("EncodeOpaque", ErrOverflow, errMaxXdr, dataLen)
		return
	}
	err = enc.EncodeUint(uint32(dataLen))
	if err != nil {
		return
	}
	err = enc.EncodeFixedOpaque(v)
	return
}
func (enc *Encoder) EncodeString(v string) (err error) {
	dataLen := len(v)
	if uint(dataLen) > math.MaxUint32 {
		err = marshalError("EncodeString", ErrOverflow, errMaxXdr, dataLen)
		return
	}
	err = enc.EncodeUint(uint32(dataLen))
	if err != nil {
		return
	}
	err = enc.EncodeFixedOpaque([]byte(v))
	return
}
func (enc *Encoder) encodeFixedArray(v reflect.Value, ignoreOpaque bool) (err error) {
	if !ignoreOpaque && v.Type().Elem().Kind() == reflect.Uint8 {
		if v.CanAddr() {
			err = enc.EncodeFixedOpaque(v.Slice(0, v.Len()).Bytes())
			return
		}
		slice := make([]byte, v.Len(), v.Len())
		reflect.Copy(reflect.ValueOf(slice), v)
		err = enc.EncodeFixedOpaque(slice)
		return
	}
	for i := 0; i < v.Len(); i++ {
		err = enc.encode(v.Index(i))
		if err != nil {
			return err
		}
	}
	return
}
func (enc *Encoder) encodeArray(v reflect.Value, ignoreOpaque bool) (err error) {
	numItems := uint32(v.Len())
	err = enc.encode(reflect.ValueOf(numItems))
	if err != nil {
		return err
	}
	err = enc.encodeFixedArray(v, ignoreOpaque)
	return
}
func (enc *Encoder) encodeStruct(v reflect.Value) (err error) {
	vt := v.Type()
	for i := 0; i < v.NumField(); i++ {
		vtf := vt.Field(i)
		if vtf.PkgPath != "" {
			continue
		}
		vf := v.Field(i)
		vf = enc.indirect(vf)
		tag := vtf.Tag.Get("xdropaque")
		if tag == "false" {
			switch vf.Kind() {
			case reflect.Slice:
				err = enc.encodeArray(vf, true)
				if err != nil {
					return
				}
				continue
			case reflect.Array:
				err = enc.encodeFixedArray(vf, true)
				if err != nil {
					return
				}
				continue
			}
		}
		err = enc.encode(vf)
		if err != nil {
			return err
		}
	}
	return
}