func NewEncoder() *Encoder {
	return &Encoder{}
}
NewEncoder returns an object that can be used to manually build an XDR
encoded byte slice.  Typically, Marshal should be used instead of manually
creating an Encoder. An Encoder, along with several of its methods to encode
XDR primitives, is exposed so it is possible to perform manual encoding of
data without relying on reflection should it be necessary in complex
scenarios where automatic reflection-based decoding won't work.
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
}
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
}
func (enc *Encoder) encodeInterface(v reflect.Value) (err error) {
	if v.IsNil() || !v.CanInterface() {
		msg := fmt.Sprintf("can't encode nil interface")
		err = marshalError("encodeInterface", ErrNilInterface, msg, nil)
		return err
	}
	ve := reflect.ValueOf(v.Interface())
	ve = enc.indirect(ve)
	return enc.encode(ve)
}
func (enc *Encoder) encode(v reflect.Value) (err error) {
	if !v.IsValid() {
		msg := fmt.Sprintf("type '%s' is not valid", v.Kind().String())
		err = marshalError("encode", ErrUnsupportedType, msg, nil)
		return
	}
	ve := enc.indirect(v)
	if ve.Type().String() == "time.Time" && ve.CanInterface() {
		viface := ve.Interface()
		if tv, ok := viface.(time.Time); ok {
			err = enc.EncodeString(tv.Format(time.RFC3339Nano))
			return
		}
	}
	switch ve.Kind() {
	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int:
		err = enc.EncodeInt(int32(ve.Int()))
	case reflect.Int64:
		err = enc.EncodeHyper(ve.Int())
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint:
		err = enc.EncodeUint(uint32(ve.Uint()))
	case reflect.Uint64:
		err = enc.EncodeUhyper(ve.Uint())
	case reflect.Bool:
		err = enc.EncodeBool(ve.Bool())
	case reflect.Float32:
		err = enc.EncodeFloat(float32(ve.Float()))
	case reflect.Float64:
		err = enc.EncodeDouble(ve.Float())
	case reflect.String:
		err = enc.EncodeString(ve.String())
	case reflect.Array:
		err = enc.encodeFixedArray(ve, false)
	case reflect.Slice:
		err = enc.encodeArray(ve, false)
	case reflect.Struct:
		err = enc.encodeStruct(ve)
	case reflect.Map:
		err = enc.encodeMap(ve)
	case reflect.Interface:
		err = enc.encodeInterface(ve)
	default:
		msg := fmt.Sprintf("unsupported Go type '%s'", ve.Kind().String())
		err = marshalError("encode", ErrUnsupportedType, msg, nil)
	}
	return
}
func (enc *Encoder) indirect(v reflect.Value) (rv reflect.Value) {
	rv = v
	for rv.Kind() == reflect.Ptr {
		rv = rv.Elem()
	}
	return
}
func (enc *Encoder) Data() (rv []byte) {
	return enc.data[:]
}
func (enc *Encoder) Reset() {
	enc.data = enc.data[0:0]
}