func (enc *Encoder) encodeMap(v reflect.Value) (int, error) {
	n, err := enc.EncodeUint(uint32(v.Len()))
	if err != nil {
		return n, err
	}
	for _, key := range v.MapKeys() {
		n2, err := enc.encode(key)
		n += n2
		if err != nil {
			return n, err
		}
		n2, err = enc.encode(v.MapIndex(key))
		n += n2
		if err != nil {
			return n, err
		}
	}
	return n, nil
}
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 writes its XDR encoded representation
to the encapsulated writer.  It returns the number of bytes written.

A MarshalError is returned if any issues are encountered while encoding
the elements.
package xdr
import (
	"fmt"
	"io"
	"math"
	"reflect"
	"time"
)
var errIOEncode = "%s while encoding %d bytes"
func Marshal(w io.Writer, v interface{}) (int, error) {
	enc := Encoder{w: w}
	return enc.Encode(v)
}
type Encoder struct {
	w io.Writer
}
func (enc *Encoder) EncodeInt(v int32) (int, error) {
	var b [4]byte
	b[0] = byte(v >> 24)
	b[1] = byte(v >> 16)
	b[2] = byte(v >> 8)
	b[3] = byte(v)
	n, err := enc.w.Write(b[:])
	if err != nil {
		msg := fmt.Sprintf(errIOEncode, err.Error(), 4)
		err := marshalError("EncodeInt", ErrIO, msg, b[:n], err)
		return n, err
	}
	return n, nil
}
func (enc *Encoder) EncodeUint(v uint32) (int, error) {
	var b [4]byte
	b[0] = byte(v >> 24)
	b[1] = byte(v >> 16)
	b[2] = byte(v >> 8)
	b[3] = byte(v)
	n, err := enc.w.Write(b[:])
	if err != nil {
		msg := fmt.Sprintf(errIOEncode, err.Error(), 4)
		err := marshalError("EncodeUint", ErrIO, msg, b[:n], err)
		return n, err
	}
	return n, nil
}
func (enc *Encoder) EncodeEnum(v int32, validEnums map[int32]bool) (int, error) {
	if !validEnums[v] {
		err := marshalError("EncodeEnum", ErrBadEnumValue,
			"invalid enum", v, nil)
		return 0, err
	}
	return enc.EncodeInt(v)
}
func (enc *Encoder) EncodeBool(v bool) (int, error) {
	i := int32(0)
	if v == true {
		i = 1
	}
	return enc.EncodeInt(i)
}
func (enc *Encoder) EncodeHyper(v int64) (int, error) {
	var b [8]byte
	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)
	n, err := enc.w.Write(b[:])
	if err != nil {
		msg := fmt.Sprintf(errIOEncode, err.Error(), 8)
		err := marshalError("EncodeHyper", ErrIO, msg, b[:n], err)
		return n, err
	}
	return n, nil
}
func (enc *Encoder) EncodeUhyper(v uint64) (int, error) {
	var b [8]byte
	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)
	n, err := enc.w.Write(b[:])
	if err != nil {
		msg := fmt.Sprintf(errIOEncode, err.Error(), 8)
		err := marshalError("EncodeUhyper", ErrIO, msg, b[:n], err)
		return n, err
	}
	return n, nil
}
func (enc *Encoder) EncodeFloat(v float32) (int, error) {
	ui := math.Float32bits(v)
	return enc.EncodeUint(ui)
}
func (enc *Encoder) EncodeDouble(v float64) (int, error) {
	ui := math.Float64bits(v)
	return enc.EncodeUhyper(ui)
}
func (enc *Encoder) EncodeFixedOpaque(v []byte) (int, error) {
	l := len(v)
	pad := (4 - (l % 4)) % 4
	n, err := enc.w.Write(v)
	if err != nil {
		msg := fmt.Sprintf(errIOEncode, err.Error(), len(v))
		err := marshalError("EncodeFixedOpaque", ErrIO, msg, v[:n], err)
		return n, err
	}
	if pad > 0 {
		b := make([]byte, pad)
		n2, err := enc.w.Write(b)
		n += n2
		if err != nil {
			written := make([]byte, l+n2)
			copy(written, v)
			copy(written[l:], b[:n2])
			msg := fmt.Sprintf(errIOEncode, err.Error(), l+pad)
			err := marshalError("EncodeFixedOpaque", ErrIO, msg,
				written, err)
			return n, err
		}
	}
	return n, nil
}
func (enc *Encoder) EncodeOpaque(v []byte) (int, error) {
	n, err := enc.EncodeUint(uint32(len(v)))
	if err != nil {
		return n, err
	}
	n2, err := enc.EncodeFixedOpaque(v)
	n += n2
	return n, err
}
func (enc *Encoder) EncodeString(v string) (int, error) {
	n, err := enc.EncodeUint(uint32(len(v)))
	if err != nil {
		return n, err
	}
	n2, err := enc.EncodeFixedOpaque([]byte(v))
	n += n2
	return n, err
}
func (enc *Encoder) encodeFixedArray(v reflect.Value, ignoreOpaque bool) (int, error) {
	if !ignoreOpaque && v.Type().Elem().Kind() == reflect.Uint8 {
		if v.CanAddr() {
			return enc.EncodeFixedOpaque(v.Slice(0, v.Len()).Bytes())
		}
		slice := make([]byte, v.Len(), v.Len())
		reflect.Copy(reflect.ValueOf(slice), v)
		return enc.EncodeFixedOpaque(slice)
	}
	var n int
	for i := 0; i < v.Len(); i++ {
		n2, err := enc.encode(v.Index(i))
		n += n2
		if err != nil {
			return n, err
		}
	}
	return n, nil
}
func (enc *Encoder) encodeArray(v reflect.Value, ignoreOpaque bool) (int, error) {
	numItems := uint32(v.Len())
	n, err := enc.EncodeUint(numItems)
	if err != nil {
		return n, err
	}
	n2, err := enc.encodeFixedArray(v, ignoreOpaque)
	n += n2
	return n, err
}
func (enc *Encoder) encodeUnion(v reflect.Value) (int, error) {
	u := v.Interface().(Union)
	vs := v.FieldByName(u.SwitchFieldName())
	n, err := enc.encode(vs)
	if err != nil {
		return n, err
	}
	sw := int32(vs.Int())
	arm, ok := u.ArmForSwitch(sw)
	if arm == "" {
		return n, nil
	}
	vv := v.FieldByName(arm)
	if !vv.IsValid() || !ok {
		msg := fmt.Sprintf("invalid union switch: %d", sw)
		err := marshalError("encodeUnion", ErrBadUnionSwitch, msg, nil, nil)
		return n, err
	}
	if vv.Kind() != reflect.Ptr {
		msg := fmt.Sprintf("invalid union value field: %v", vv.Kind())
		err := marshalError("encodeUnion", ErrBadUnionValue, msg, nil, nil)
		return n, err
	}
	if vv.IsNil() {
		msg := fmt.Sprintf("can't encode nil union value")
		err := marshalError("encodeUnion", ErrBadUnionValue, msg, nil, nil)
		return n, err
	}
	n2, err := enc.encode(vv.Elem())
	n += n2
	return n, err
}
func (enc *Encoder) encodeStruct(v reflect.Value) (int, error) {
	var n int
	vt := v.Type()
	for i := 0; i < v.NumField(); i++ {
		vtf := vt.Field(i)
		if vtf.PkgPath != "" {
			continue
		}
		vf := v.Field(i)
		tag := vtf.Tag.Get("xdropaque")
		if tag == "false" {
			switch vf.Kind() {
			case reflect.Slice:
				n2, err := enc.encodeArray(vf, true)
				n += n2
				if err != nil {
					return n, err
				}
				continue
			case reflect.Array:
				n2, err := enc.encodeFixedArray(vf, true)
				n += n2
				if err != nil {
					return n, err
				}
				continue
			}
		}
		n2, err := enc.encode(vf)
		n += n2
		if err != nil {
			return n, err
		}
	}
	return n, nil
}