<|start_filename|>struct.go<|end_filename|>
package surge

import (
	"reflect"
)

func sizeHintReflectedStruct(v reflect.Value) int {
	sizeHint := 0
	numField := v.NumField()
	for i := 0; i < numField; i++ {
		if f := v.Field(i); f.IsValid() {
			sizeHint += sizeHintReflected(f)
		}
	}
	return sizeHint
}

func marshalReflectedStruct(v reflect.Value, buf []byte, rem int) ([]byte, int, error) {
	var err error
	numField := v.NumField()
	for i := 0; i < numField; i++ {
		if f := v.Field(i); f.IsValid() {
			if buf, rem, err = marshalReflected(f, buf, rem); err != nil {
				return buf, rem, err
			}
		}
	}
	return buf, rem, nil
}

func unmarshalReflectedStruct(v reflect.Value, buf []byte, rem int) ([]byte, int, error) {
	var err error
	elem := v.Elem()
	numField := elem.NumField()
	for i := 0; i < numField; i++ {
		if f := elem.Field(i); f.IsValid() {
			if buf, rem, err = unmarshalReflected(f.Addr(), buf, rem); err != nil {
				return buf, rem, err
			}
		}
	}
	return buf, rem, nil
}


<|start_filename|>surge.go<|end_filename|>
package surge

import (
	"reflect"
	"unsafe"
)

// MaxBytes is set to 64 MB by default.
const MaxBytes = int(64 * 1024 * 1024)

// A SizeHinter can hint at the number of bytes required to represented it in
// binary.
type SizeHinter interface {
	// SizeHint returns the upper bound for the number of bytes required to
	// represent this value in binary.
	SizeHint() int
}

// A Marshaler can marshal itself into bytes.
type Marshaler interface {
	SizeHinter

	// Marshal this value into bytes.
	Marshal(buf []byte, rem int) ([]byte, int, error)
}

// An Unmarshaler can unmarshal itself from bytes.
type Unmarshaler interface {
	// Unmarshal this value from bytes.
	Unmarshal(buf []byte, rem int) ([]byte, int, error)
}

// A MarshalUnmarshaler is a marshaler and an unmarshaler.
type MarshalUnmarshaler interface {
	Marshaler
	Unmarshaler
}

// ToBinary returns the byte representation of a value. In uses the maximum
// memory quota to restrict the number of bytes that will be allocated during
// marshaling.
func ToBinary(v interface{}) ([]byte, error) {
	buf := make([]byte, SizeHint(v))
	_, _, err := Marshal(v, buf, MaxBytes)
	return buf, err
}

// FromBinary unmarshals a byte representation of a value to a pointer to that
// value. In uses the maximum memory quota to restrict the number of bytes that
// will be allocated during unmarshaling.
func FromBinary(v interface{}, buf []byte) error {
	_, _, err := Unmarshal(v, buf, MaxBytes)
	return err
}

// SizeHint returns the number of bytes required to store a value in its binary
// representation. This is the number of bytes "on the wire", not the number of
// bytes that need to be allocated during marshaling/unmarshaling (which can be
// different, depending on the representation of the value). SizeHint supports
// all scalars, strings, arrays, slices, maps, structs, and custom
// implementations (for types that implement the SizeHinter interface). If the
// type is not supported, then zero is returned. If the value is a pointer, then
// the size of the underlying value being pointed to will be returned.
//
//  x := int64(0)
//  sizeHint := surge.SizeHint(x)
//  if sizeHint != 8 {
//      panic("assertion failed: size of int64 must be 8 bytes")
//  }
//
func SizeHint(v interface{}) int {
	return sizeHintReflected(reflect.ValueOf(v))
}

// Marshal a value into its binary representation, and store the value in a byte
// slice. The "remaining memory quota" defines the maximum amount of bytes that
// can be allocated on the heap when marshaling the value. In this way, the
// remaining memory quota can be used to avoid allocating too much memory during
// marshaling. Marshaling supports all scalars, strings, arrays, slices, maps,
// structs, and custom implementations (for types that implement the Marshaler
// interface). After marshaling, the unconsumed tail of the byte slice, and the
// remaining memory quota, are returned. If the byte slice is too small, then an
// error is returned. Similarly, if the remaining memory quote is too small,
// then an error is returned. If the type is not supported, then an error is
// returned. An error does not imply that nothing from the byte slice, or
// remaining memory quota, was consumed. If the value is a pointer, then the
// underlying value being pointed to will be marshaled.
//
//  x := int64(0)
//  buf := make([]byte, 8)
//  tail, rem, err := surge.Marshal(x, buf, 8)
//  if len(tail) != 0 {
//      panic("assertion failed: int64 must consume 8 bytes")
//  }
//  if rem != 0 {
//      panic("assertion failed: int64 must consume 8 bytes of the memory quota")
//  }
//  if err != nil {
//      panic(fmt.Errorf("assertion failed: %v", err))
//  }
//
func Marshal(v interface{}, buf []byte, rem int) ([]byte, int, error) {
	return marshalReflected(reflect.ValueOf(v), buf, rem)
}

// Unmarshal a value from its binary representation by reading from a byte
// slice. The "remaining memory quota" defines the maximum amount of bytes that
// can be allocated on the heap when unmarshaling the value. In this way, the
// remaining memory quota can be used to avoid allocating too much memory during
// unmarshaling (this is particularly useful when dealing with potentially
// malicious input). Unmarshaling supports pointers to all scalars, strings,
// arrays, slices, maps, structs, and custom implementations (for types that
// implement the Unmarshaler interface). After unmarshaling, the unconsumed tail
// of the byte slice, and the remaining memory quota, are returned. If the byte
// slice is too small, then an error is returned. Similarly, if the remaining
// memory quote is too small, then an error is returned. If the type is not a
// pointer to one of the supported types, then an error is returned. An error
// does not imply that nothing from the byte slice, or remaining memory quota,
// was consumed. If the value is not a pointer, then an error is returned.
//
//  x := int64(0)
//  buf := make([]byte, 8)
//  tail, rem, err := surge.Unmarshal(&x, buf, 8)
//  if len(tail) != 0 {
//      panic("assertion failed: int64 must consume 8 bytes")
//  }
//  if rem != 0 {
//      panic("assertion failed: int64 must consume 8 bytes of the memory quota")
//  }
//  if err != nil {
//      panic(fmt.Errorf("assertion failed: %v", err))
//  }
//
func Unmarshal(v interface{}, buf []byte, rem int) ([]byte, int, error) {
	valueOf := reflect.ValueOf(v)
	if valueOf.Kind() != reflect.Ptr {
		return buf, rem, NewErrUnsupportedUnmarshalType(v)
	}
	return unmarshalReflected(valueOf, buf, rem)
}

func sizeHintReflected(v reflect.Value) int {
	if v.Type().Implements(sizeHinter) {
		return v.Interface().(SizeHinter).SizeHint()
	}

	switch v.Kind() {
	case reflect.Bool:
		return SizeHintBool

	case reflect.Uint8:
		return SizeHintU8
	case reflect.Uint16:
		return SizeHintU16
	case reflect.Uint32:
		return SizeHintU32
	case reflect.Uint, reflect.Uint64:
		return SizeHintU64

	case reflect.Int8:
		return SizeHintI8
	case reflect.Int16:
		return SizeHintI16
	case reflect.Int32:
		return SizeHintI32
	case reflect.Int64:
		return SizeHintI64

	case reflect.Float32:
		return SizeHintF32
	case reflect.Float64:
		return SizeHintF64

	case reflect.String:
		return SizeHintString(v.String())

	case reflect.Array:
		return sizeHintReflectedArray(v)
	case reflect.Slice:
		if v, ok := v.Interface().([]byte); ok {
			return SizeHintBytes(v)
		}
		return sizeHintReflectedSlice(v)
	case reflect.Map:
		return sizeHintReflectedMap(v)
	case reflect.Struct:
		return sizeHintReflectedStruct(v)
	case reflect.Ptr:
		v = reflect.Indirect(v)
		if v.IsValid() {
			return sizeHintReflected(v)
		}
		return 0
	}

	return 0
}

func marshalReflected(v reflect.Value, buf []byte, rem int) ([]byte, int, error) {
	if v.Type().Implements(marshaler) {
		return v.Interface().(Marshaler).Marshal(buf, rem)
	}

	switch v.Kind() {
	case reflect.Bool:
		return MarshalBool(v.Bool(), buf, rem)

	case reflect.Uint8:
		return MarshalU8(uint8(v.Uint()), buf, rem)
	case reflect.Uint16:
		return MarshalU16(uint16(v.Uint()), buf, rem)
	case reflect.Uint32:
		return MarshalU32(uint32(v.Uint()), buf, rem)
	case reflect.Uint, reflect.Uint64:
		return MarshalU64(uint64(v.Uint()), buf, rem)

	case reflect.Int8:
		return MarshalI8(int8(v.Int()), buf, rem)
	case reflect.Int16:
		return MarshalI16(int16(v.Int()), buf, rem)
	case reflect.Int32:
		return MarshalI32(int32(v.Int()), buf, rem)
	case reflect.Int64:
		return MarshalI64(int64(v.Int()), buf, rem)

	case reflect.Float32:
		return MarshalF32(float32(v.Float()), buf, rem)
	case reflect.Float64:
		return MarshalF64(float64(v.Float()), buf, rem)

	case reflect.String:
		return MarshalString(v.String(), buf, rem)

	case reflect.Array:
		return marshalReflectedArray(v, buf, rem)
	case reflect.Slice:
		if v, ok := v.Interface().([]byte); ok {
			return MarshalBytes(v, buf, rem)
		}
		return marshalReflectedSlice(v, buf, rem)
	case reflect.Map:
		return marshalReflectedMap(v, buf, rem)
	case reflect.Struct:
		return marshalReflectedStruct(v, buf, rem)
	case reflect.Ptr:
		v = reflect.Indirect(v)
		if v.IsValid() {
			return marshalReflected(v, buf, rem)
		}
		return buf, rem, nil
	}

	return buf, rem, NewErrUnsupportedMarshalType(v.Interface())
}

func unmarshalReflected(v reflect.Value, buf []byte, rem int) ([]byte, int, error) {
	if v.Type().Implements(unmarshaler) {
		return v.Interface().(Unmarshaler).Unmarshal(buf, rem)
	}

	switch v.Type().Elem().Kind() {
	case reflect.Bool:
		return UnmarshalBool((*bool)(unsafe.Pointer(v.Pointer())), buf, rem)

	case reflect.Uint8:
		return UnmarshalU8((*uint8)(unsafe.Pointer(v.Pointer())), buf, rem)
	case reflect.Uint16:
		return UnmarshalU16((*uint16)(unsafe.Pointer(v.Pointer())), buf, rem)
	case reflect.Uint32:
		return UnmarshalU32((*uint32)(unsafe.Pointer(v.Pointer())), buf, rem)
	case reflect.Uint64:
		return UnmarshalU64((*uint64)(unsafe.Pointer(v.Pointer())), buf, rem)

	case reflect.Int8:
		return UnmarshalI8((*int8)(unsafe.Pointer(v.Pointer())), buf, rem)
	case reflect.Int16:
		return UnmarshalI16((*int16)(unsafe.Pointer(v.Pointer())), buf, rem)
	case reflect.Int32:
		return UnmarshalI32((*int32)(unsafe.Pointer(v.Pointer())), buf, rem)
	case reflect.Int64:
		return UnmarshalI64((*int64)(unsafe.Pointer(v.Pointer())), buf, rem)

	case reflect.Float32:
		return UnmarshalF32((*float32)(unsafe.Pointer(v.Pointer())), buf, rem)
	case reflect.Float64:
		return UnmarshalF64((*float64)(unsafe.Pointer(v.Pointer())), buf, rem)

	case reflect.String:
		return UnmarshalString((*string)(unsafe.Pointer(v.Pointer())), buf, rem)

	case reflect.Array:
		return unmarshalReflectedArray(v, buf, rem)
	case reflect.Slice:
		if v, ok := v.Interface().(*[]byte); ok {
			return UnmarshalBytes(v, buf, rem)
		}
		return unmarshalReflectedSlice(v, buf, rem)
	case reflect.Map:
		return unmarshalReflectedMap(v, buf, rem)
	case reflect.Struct:
		return unmarshalReflectedStruct(v, buf, rem)
	}

	return buf, rem, NewErrUnsupportedUnmarshalType(v.Interface())
}

var (
	sizeHinter  = reflect.ValueOf((*SizeHinter)(nil)).Type().Elem()
	marshaler   = reflect.ValueOf((*Marshaler)(nil)).Type().Elem()
	unmarshaler = reflect.ValueOf((*Unmarshaler)(nil)).Type().Elem()
)


<|start_filename|>array.go<|end_filename|>
package surge

import (
	"reflect"
)

func sizeHintReflectedArray(v reflect.Value) int {
	sizeHint := 0
	for i := 0; i < v.Len(); i++ {
		sizeHint += sizeHintReflected(v.Index(i))
	}
	return sizeHint
}

func marshalReflectedArray(v reflect.Value, buf []byte, rem int) ([]byte, int, error) {
	arrayLen := v.Len()
	if len(buf) < arrayLen || rem < arrayLen {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	var err error
	for i := 0; i < arrayLen; i++ {
		if buf, rem, err = marshalReflected(v.Index(i), buf, rem); err != nil {
			return buf, rem, err
		}
	}
	return buf, rem, nil
}

func unmarshalReflectedArray(v reflect.Value, buf []byte, rem int) ([]byte, int, error) {
	elem := v.Elem()
	arrayLen := elem.Len()
	if len(buf) < arrayLen || rem < arrayLen {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	var err error
	for i := 0; i < arrayLen; i++ {
		if buf, rem, err = unmarshalReflected(elem.Index(i).Addr(), buf, rem); err != nil {
			return buf, rem, err
		}
	}
	return buf, rem, nil
}


<|start_filename|>map.go<|end_filename|>
package surge

import (
	"reflect"
	"sort"
	"unsafe"
)

func sizeHintReflectedMap(v reflect.Value) int {
	sizeHint := SizeHintU32
	iter := v.MapRange()
	for iter.Next() {
		sizeHint += sizeHintReflected(iter.Key())
		sizeHint += sizeHintReflected(iter.Value())
	}
	return sizeHint
}

func marshalReflectedMap(v reflect.Value, buf []byte, rem int) ([]byte, int, error) {
	buf, rem, err := MarshalLen(uint32(v.Len()), buf, rem)
	if err != nil {
		return buf, rem, err
	}

	// Define a local key/value type that can be used to sort the key/value
	// pairs. It is worth noting, the key is explicitly defined to be bytes, so
	// we will need to marshal all keys and then convert those bytes to strings.
	// This guarantees that, regardless of the key type, we can sort the keys
	// deterministically.
	type KeyValue struct {
		keyData []byte
		key     reflect.Value
	}

	// Allocate a slice for storing the key/value pairs. This is needed so that
	// we can then sort the slice, ensuring that the key/value ordering is
	// deterministic.
	n := v.Len() * int(unsafe.Sizeof(KeyValue{}))
	if n < 0 || n < v.Len() {
		return buf, rem, ErrLengthOverflow
	}
	if rem < n {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	rem -= n
	keyValues := make([]KeyValue, 0, v.Len())

	for _, key := range v.MapKeys() {
		// Marshal the key into bytes, so that we can guarantee that the keys
		// can be compared.
		sizeHint := sizeHintReflected(key)
		if rem < sizeHint {
			return buf, rem, ErrUnexpectedEndOfBuffer
		}
		rem -= sizeHint
		keyValue := KeyValue{
			keyData: make([]byte, sizeHint),
			key:     key,
		}
		if _, rem, err = marshalReflected(key, keyValue.keyData, rem+sizeHint); err != nil {
			return buf, rem, err
		}

		// Search and insert to ensure that the key/values are always in sorted
		// order.
		i := sort.Search(len(keyValues), func(i int) bool {
			other := keyValues[i]
			if len(keyValue.keyData) < len(other.keyData) {
				return true
			}
			if len(keyValue.keyData) > len(other.keyData) {
				return false
			}
			for j := range keyValue.keyData {
				if keyValue.keyData[j] < other.keyData[j] {
					return true
				}
				if keyValue.keyData[j] > other.keyData[j] {
					return false
				}
			}
			return true
		})
		keyValues = append(keyValues, KeyValue{})
		copy(keyValues[i+1:], keyValues[i:])
		keyValues[i] = keyValue
	}

	for _, keyValue := range keyValues {
		// Marshal the key. This is the second time we are doing it, so we do
		// not check/decrement rem again. This is the first time we are actually
		// writing out to the buffer though, so we do need to check buffer
		// lengths.
		keyDataLen := len(keyValue.keyData)
		if len(buf) < keyDataLen {
			return buf, rem, ErrUnexpectedEndOfBuffer
		}
		copy(buf, keyValue.keyData)
		buf = buf[keyDataLen:]

		// Marshal the value.
		if buf, rem, err = marshalReflected(v.MapIndex(keyValue.key), buf, rem); err != nil {
			return buf, rem, err
		}
	}
	return buf, rem, nil
}

func unmarshalReflectedMap(v reflect.Value, buf []byte, rem int) ([]byte, int, error) {
	var err error

	mapLen := uint32(0)
	elem := v.Elem()
	size := int(elem.Type().Key().Size() + elem.Type().Elem().Size())
	if buf, rem, err = UnmarshalLen(&mapLen, size, buf, rem); err != nil {
		return buf, rem, err
	}
	rem -= int(mapLen) * size
	elem.Set(reflect.MakeMapWithSize(elem.Type(), int(mapLen)))

	for i := uint32(0); i < mapLen; i++ {
		k := reflect.New(elem.Type().Key())
		v := reflect.New(elem.Type().Elem())
		if buf, rem, err = unmarshalReflected(k, buf, rem); err != nil {
			return buf, rem, err
		}
		if buf, rem, err = unmarshalReflected(v, buf, rem); err != nil {
			return buf, rem, err
		}
		elem.SetMapIndex(reflect.Indirect(k), reflect.Indirect(v))
	}
	return buf, rem, nil
}


<|start_filename|>slice.go<|end_filename|>
package surge

import (
	"reflect"
)

// SizeHintBytes is the number of bytes required to represent the given byte
// slice in binary.
func SizeHintBytes(v []byte) int {
	return SizeHintU32 + len(v)
}

// MarshalBytes into a byte slice. It will not consume more memory than the
// remaining memory quota (either through writes, or in-memory allocations). It
// will return the unconsumed tail of the byte slice, and the remaining memory
// quota. An error is returned if the byte slice is too small, or if the
// remainin memory quote is insufficient.
func MarshalBytes(v []byte, buf []byte, rem int) ([]byte, int, error) {
	buf, rem, err := MarshalLen(uint32(len(v)), buf, rem)
	if err != nil {
		return buf, rem, err
	}
	if len(buf) < len(v) || rem < len(v) {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	copy(buf, v)
	buf = buf[len(v):]
	rem -= len(v)
	return buf, rem, nil
}

// UnmarshalBytes from a byte slice. It will not consume more memory than the
// remaining memory quota (either through reads, or in-memory allocations). It
// will return the unconsumed tail of the byte slice, and the remaining memory
// quota. An error is returned if the byte slice is too small, or if the
// remainin memory quote is insufficient.
func UnmarshalBytes(v *[]byte, buf []byte, rem int) ([]byte, int, error) {
	vLen := uint32(0)
	buf, rem, err := UnmarshalLen(&vLen, 1, buf, rem)
	if err != nil {
		return buf, rem, err
	}

	if len(buf) < int(vLen) {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	*v = make([]byte, vLen)
	copy(*v, buf)
	buf = buf[vLen:]
	rem -= int(vLen)

	return buf, rem, nil
}

func sizeHintReflectedSlice(v reflect.Value) int {
	sizeHint := SizeHintU32
	for i := 0; i < v.Len(); i++ {
		sizeHint += sizeHintReflected(v.Index(i))
	}
	return sizeHint
}

func marshalReflectedSlice(v reflect.Value, buf []byte, rem int) ([]byte, int, error) {
	buf, rem, err := MarshalLen(uint32(v.Len()), buf, rem)
	if err != nil {
		return buf, rem, err
	}
	for i := 0; i < v.Len(); i++ {
		if buf, rem, err = marshalReflected(v.Index(i), buf, rem); err != nil {
			return buf, rem, err
		}
	}
	return buf, rem, nil
}

func unmarshalReflectedSlice(v reflect.Value, buf []byte, rem int) ([]byte, int, error) {
	sliceLen := uint32(0)
	elem := v.Elem()
	size := int(elem.Type().Elem().Size())
	buf, rem, err := UnmarshalLen(&sliceLen, size, buf, rem)
	if err != nil {
		return buf, rem, err
	}
	rem -= int(sliceLen) * size

	elem.Set(reflect.MakeSlice(elem.Type(), int(sliceLen), int(sliceLen)))
	for i := uint32(0); i < sliceLen; i++ {
		if buf, rem, err = unmarshalReflected(elem.Index(int(i)).Addr(), buf, rem); err != nil {
			return buf, rem, err
		}
	}
	return buf, rem, nil
}


<|start_filename|>bool.go<|end_filename|>
package surge

const (
	// SizeHintBool is the number of bytes required to represent a boolean value
	// in binary.
	SizeHintBool = 1
)

// MarshalBool into a byte slice. It will not consume more memory than the
// remaining memory quota (either through writes, or in-memory allocations). It
// will return the unconsumed tail of the byte slice, and the remaining memory
// quota. An error is returned if the byte slice is too small, or if the
// remainin memory quote is insufficient.
func MarshalBool(x bool, buf []byte, rem int) ([]byte, int, error) {
	if len(buf) < SizeHintBool || rem < SizeHintBool {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	if x {
		buf[0] = 1
	} else {
		buf[0] = 0
	}
	return buf[SizeHintBool:], rem - SizeHintBool, nil
}

// UnmarshalBool from a byte slice. It will not consume more memory than the
// remaining memory quota (either through reads, or in-memory allocations). It
// will return the unconsumed tail of the byte slice, and the remaining memory
// quota. An error is returned if the byte slice is too small, or if the
// remainin memory quote is insufficient.
func UnmarshalBool(x *bool, buf []byte, rem int) ([]byte, int, error) {
	if len(buf) < SizeHintBool || rem < SizeHintBool {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	*x = buf[0] != 0
	return buf[SizeHintBool:], rem - SizeHintBool, nil
}


<|start_filename|>err.go<|end_filename|>
package surge

import (
	"errors"
	"fmt"
)

// ErrUnexpectedEndOfBuffer is used when reading/writing from/to a buffer that
// has less space than expected.
var ErrUnexpectedEndOfBuffer = errors.New("unexpected end of buffer")

// ErrLengthOverflow is returned when the length of an array or slice has
// overflowed.
var ErrLengthOverflow = errors.New("max bytes exceeded")

// ErrUnsupportedMarshalType is returned when the an unsupported type is
// encountered during marshaling.
type ErrUnsupportedMarshalType struct {
	error
}

// NewErrUnsupportedMarshalType constructs a new unsupported marshal type error
// for the given type.
func NewErrUnsupportedMarshalType(v interface{}) error {
	return ErrUnsupportedMarshalType{error: fmt.Errorf("marshal error: unsupported type %T", v)}
}

// ErrUnsupportedUnmarshalType is returned when the an unsupported type is
// encountered during unmarshaling.
type ErrUnsupportedUnmarshalType struct {
	error
}

// NewErrUnsupportedUnmarshalType constructs a new unsupported unmarshal type
// error for the given type.
func NewErrUnsupportedUnmarshalType(v interface{}) error {
	return ErrUnsupportedUnmarshalType{error: fmt.Errorf("unmarshal error: unsupported type %T", v)}
}


<|start_filename|>float.go<|end_filename|>
package surge

import (
	"encoding/binary"
	"math"
)

const (
	// SizeHintF32 is the number of bytes required to represent a float32 value
	// in binary.
	SizeHintF32 = 4
	// SizeHintF64 is the number of bytes required to represent a float64 value
	// in binary.
	SizeHintF64 = 8
)

// MarshalF32 into a byte slice. It will not consume more memory than the
// remaining memory quota (either through writes, or in-memory allocations). It
// will return the unconsumed tail of the byte slice, and the remaining memory
// quota. An error is returned if the byte slice is too small, or if the
// remainin memory quote is insufficient.
func MarshalF32(x float32, buf []byte, rem int) ([]byte, int, error) {
	if len(buf) < SizeHintF32 || rem < SizeHintF32 {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	binary.BigEndian.PutUint32(buf, math.Float32bits(x))
	return buf[SizeHintF32:], rem - SizeHintF32, nil
}

// MarshalF64 into a byte slice. It will not consume more memory than the
// remaining memory quota (either through writes, or in-memory allocations). It
// will return the unconsumed tail of the byte slice, and the remaining memory
// quota. An error is returned if the byte slice is too small, or if the
// remainin memory quote is insufficient.
func MarshalF64(x float64, buf []byte, rem int) ([]byte, int, error) {
	if len(buf) < SizeHintF64 || rem < SizeHintF64 {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	binary.BigEndian.PutUint64(buf, math.Float64bits(x))
	return buf[SizeHintF64:], rem - SizeHintF64, nil
}

// UnmarshalF32 from a byte slice. It will not consume more memory than the
// remaining memory quota (either through reads, or in-memory allocations). It
// will return the unconsumed tail of the byte slice, and the remaining memory
// quota. An error is returned if the byte slice is too small, or if the
// remainin memory quote is insufficient.
func UnmarshalF32(x *float32, buf []byte, rem int) ([]byte, int, error) {
	if len(buf) < SizeHintF32 || rem < SizeHintF32 {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	*x = math.Float32frombits(binary.BigEndian.Uint32(buf))
	return buf[SizeHintF32:], rem - SizeHintF32, nil
}

// UnmarshalF64 from a byte slice. It will not consume more memory than the
// remaining memory quota (either through reads, or in-memory allocations). It
// will return the unconsumed tail of the byte slice, and the remaining memory
// quota. An error is returned if the byte slice is too small, or if the
// remainin memory quote is insufficient.
func UnmarshalF64(x *float64, buf []byte, rem int) ([]byte, int, error) {
	if len(buf) < SizeHintF64 || rem < SizeHintF64 {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	*x = math.Float64frombits(binary.BigEndian.Uint64(buf))
	return buf[SizeHintF64:], rem - SizeHintF64, nil
}


<|start_filename|>len.go<|end_filename|>
package surge

// MarshalLen marshals the given slice length.
func MarshalLen(l uint32, buf []byte, rem int) ([]byte, int, error) {
	return MarshalU32(l, buf, rem)
}

// UnmarshalLen unmarshals a slice length, checking that the total space
// required for the slice will not exceed rem.
func UnmarshalLen(dst *uint32, elemSize int, buf []byte, rem int) ([]byte, int, error) {
	var l uint32
	buf, rem, err := UnmarshalU32(&l, buf, rem)
	if err != nil {
		return buf, rem, err
	}

	if elemSize < 1 {
		elemSize = 1
	}
	var c uint64 = uint64(l) * uint64(elemSize)

	// Check if there was overflow in the multiplication.
	// NOTE: This can only occur on systems for which the int type is 64 bits,
	// and in addition when elemSize >= 2^32 = 4 Gb. Elements with this size
	// are unlikely to be used in practice.
	if c/uint64(elemSize) != uint64(l) {
		return buf, rem, ErrLengthOverflow
	}

	if uint64(rem) < c {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}

	*dst = l
	return buf, rem, nil
}


<|start_filename|>int.go<|end_filename|>
package surge

import (
	"encoding/binary"
)

const (
	// SizeHintU8 is the number of bytes required to represent a uint8 value in
	// binary.
	SizeHintU8 = 1
	// SizeHintU16 is the number of bytes required to represent a uint16 value
	// in binary.
	SizeHintU16 = 2
	// SizeHintU32 is the number of bytes required to represent a uint32 value
	// in binary.
	SizeHintU32 = 4
	// SizeHintU64 is the number of bytes required to represent a uint64 value
	// in binary.
	SizeHintU64 = 8
	// SizeHintI8 is the number of bytes required to represent a int8 value in
	// binary.
	SizeHintI8 = 1
	// SizeHintI16 is the number of bytes required to represent a int16 value in
	// binary.
	SizeHintI16 = 2
	// SizeHintI32 is the number of bytes required to represent a int32 value in
	// binary.
	SizeHintI32 = 4
	// SizeHintI64 is the number of bytes required to represent a int64 value in
	// binary.
	SizeHintI64 = 8
)

// MarshalU8 into a byte slice. It will not consume more memory than the
// remaining memory quota (either through writes, or in-memory allocations). It
// will return the unconsumed tail of the byte slice, and the remaining memory
// quota. An error is returned if the byte slice is too small, or if the
// remainin memory quote is insufficient.
func MarshalU8(x uint8, buf []byte, rem int) ([]byte, int, error) {
	if len(buf) < SizeHintU8 || rem < SizeHintU8 {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	buf[0] = x
	return buf[SizeHintU8:], rem - SizeHintU8, nil
}

// MarshalU16 into a byte slice. It will not consume more memory than the
// remaining memory quota (either through writes, or in-memory allocations). It
// will return the unconsumed tail of the byte slice, and the remaining memory
// quota. An error is returned if the byte slice is too small, or if the
// remainin memory quote is insufficient.
func MarshalU16(x uint16, buf []byte, rem int) ([]byte, int, error) {
	if len(buf) < SizeHintU16 || rem < SizeHintU16 {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	binary.BigEndian.PutUint16(buf, x)
	return buf[SizeHintU16:], rem - SizeHintU16, nil
}

// MarshalU32 into a byte slice. It will not consume more memory than the
// remaining memory quota (either through writes, or in-memory allocations). It
// will return the unconsumed tail of the byte slice, and the remaining memory
// quota. An error is returned if the byte slice is too small, or if the
// remainin memory quote is insufficient.
func MarshalU32(x uint32, buf []byte, rem int) ([]byte, int, error) {
	if len(buf) < SizeHintU32 || rem < SizeHintU32 {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	binary.BigEndian.PutUint32(buf, x)
	return buf[SizeHintU32:], rem - SizeHintU32, nil
}

// MarshalU64 into a byte slice. It will not consume more memory than the
// remaining memory quota (either through writes, or in-memory allocations). It
// will return the unconsumed tail of the byte slice, and the remaining memory
// quota. An error is returned if the byte slice is too small, or if the
// remainin memory quote is insufficient.
func MarshalU64(x uint64, buf []byte, rem int) ([]byte, int, error) {
	if len(buf) < SizeHintU64 || rem < SizeHintU64 {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	binary.BigEndian.PutUint64(buf, x)
	return buf[SizeHintU64:], rem - SizeHintU64, nil
}

// MarshalI8 into a byte slice. It will not consume more memory than the
// remaining memory quota (either through writes, or in-memory allocations). It
// will return the unconsumed tail of the byte slice, and the remaining memory
// quota. An error is returned if the byte slice is too small, or if the
// remainin memory quote is insufficient.
func MarshalI8(x int8, buf []byte, rem int) ([]byte, int, error) {
	if len(buf) < SizeHintI8 || rem < SizeHintI8 {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	buf[0] = uint8(x)
	return buf[SizeHintI8:], rem - SizeHintI8, nil
}

// MarshalI16 into a byte slice. It will not consume more memory than the
// remaining memory quota (either through writes, or in-memory allocations). It
// will return the unconsumed tail of the byte slice, and the remaining memory
// quota. An error is returned if the byte slice is too small, or if the
// remainin memory quote is insufficient.
func MarshalI16(x int16, buf []byte, rem int) ([]byte, int, error) {
	if len(buf) < SizeHintI16 || rem < SizeHintI16 {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	binary.BigEndian.PutUint16(buf, uint16(x))
	return buf[SizeHintI16:], rem - SizeHintI16, nil
}

// MarshalI32 into a byte slice. It will not consume more memory than the
// remaining memory quota (either through writes, or in-memory allocations). It
// will return the unconsumed tail of the byte slice, and the remaining memory
// quota. An error is returned if the byte slice is too small, or if the
// remainin memory quote is insufficient.
func MarshalI32(x int32, buf []byte, rem int) ([]byte, int, error) {
	if len(buf) < SizeHintI32 || rem < SizeHintI32 {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	binary.BigEndian.PutUint32(buf, uint32(x))
	return buf[SizeHintI32:], rem - SizeHintI32, nil
}

// MarshalI64 into a byte slice. It will not consume more memory than the
// remaining memory quota (either through writes, or in-memory allocations). It
// will return the unconsumed tail of the byte slice, and the remaining memory
// quota. An error is returned if the byte slice is too small, or if the
// remainin memory quote is insufficient.
func MarshalI64(x int64, buf []byte, rem int) ([]byte, int, error) {
	if len(buf) < SizeHintI64 || rem < SizeHintI64 {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	binary.BigEndian.PutUint64(buf, uint64(x))
	return buf[SizeHintI64:], rem - SizeHintI64, nil
}

// UnmarshalU8 from a byte slice. It will not consume more memory than the
// remaining memory quota (either through reads, or in-memory allocations). It
// will return the unconsumed tail of the byte slice, and the remaining memory
// quota. An error is returned if the byte slice is too small, or if the
// remainin memory quote is insufficient.
func UnmarshalU8(x *uint8, buf []byte, rem int) ([]byte, int, error) {
	if len(buf) < SizeHintU8 || rem < SizeHintU8 {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	*x = buf[0]
	return buf[SizeHintU8:], rem - SizeHintU8, nil
}

// UnmarshalU16 from a byte slice. It will not consume more memory than the
// remaining memory quota (either through reads, or in-memory allocations). It
// will return the unconsumed tail of the byte slice, and the remaining memory
// quota. An error is returned if the byte slice is too small, or if the
// remainin memory quote is insufficient.
func UnmarshalU16(x *uint16, buf []byte, rem int) ([]byte, int, error) {
	if len(buf) < SizeHintU16 || rem < SizeHintU16 {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	*x = binary.BigEndian.Uint16(buf[:])
	return buf[SizeHintU16:], rem - SizeHintU16, nil
}

// UnmarshalU32 from a byte slice. It will not consume more memory than the
// remaining memory quota (either through reads, or in-memory allocations). It
// will return the unconsumed tail of the byte slice, and the remaining memory
// quota. An error is returned if the byte slice is too small, or if the
// remainin memory quote is insufficient.
func UnmarshalU32(x *uint32, buf []byte, rem int) ([]byte, int, error) {
	if len(buf) < SizeHintU32 || rem < SizeHintU32 {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	*x = binary.BigEndian.Uint32(buf[:])
	return buf[SizeHintU32:], rem - SizeHintU32, nil
}

// UnmarshalU64 from a byte slice. It will not consume more memory than the
// remaining memory quota (either through reads, or in-memory allocations). It
// will return the unconsumed tail of the byte slice, and the remaining memory
// quota. An error is returned if the byte slice is too small, or if the
// remainin memory quote is insufficient.
func UnmarshalU64(x *uint64, buf []byte, rem int) ([]byte, int, error) {
	if len(buf) < SizeHintU64 || rem < SizeHintU64 {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	*x = binary.BigEndian.Uint64(buf[:])
	return buf[SizeHintU64:], rem - SizeHintU64, nil
}

// UnmarshalI8 from a byte slice. It will not consume more memory than the
// remaining memory quota (either through reads, or in-memory allocations). It
// will return the unconsumed tail of the byte slice, and the remaining memory
// quota. An error is returned if the byte slice is too small, or if the
// remainin memory quote is insufficient.
func UnmarshalI8(x *int8, buf []byte, rem int) ([]byte, int, error) {
	if len(buf) < SizeHintI8 || rem < SizeHintI8 {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	*x = int8(buf[0])
	return buf[SizeHintI8:], rem - SizeHintI8, nil
}

// UnmarshalI16 from a byte slice. It will not consume more memory than the
// remaining memory quota (either through reads, or in-memory allocations). It
// will return the unconsumed tail of the byte slice, and the remaining memory
// quota. An error is returned if the byte slice is too small, or if the
// remainin memory quote is insufficient.
func UnmarshalI16(x *int16, buf []byte, rem int) ([]byte, int, error) {
	if len(buf) < SizeHintI16 || rem < SizeHintI16 {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	*x = int16(binary.BigEndian.Uint16(buf[:]))
	return buf[SizeHintI16:], rem - SizeHintI16, nil
}

// UnmarshalI32 from a byte slice. It will not consume more memory than the
// remaining memory quota (either through reads, or in-memory allocations). It
// will return the unconsumed tail of the byte slice, and the remaining memory
// quota. An error is returned if the byte slice is too small, or if the
// remainin memory quote is insufficient.
func UnmarshalI32(x *int32, buf []byte, rem int) ([]byte, int, error) {
	if len(buf) < SizeHintI32 || rem < SizeHintI32 {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	*x = int32(binary.BigEndian.Uint32(buf))
	return buf[SizeHintI32:], rem - SizeHintI32, nil
}

// UnmarshalI64 from a byte slice. It will not consume more memory than the
// remaining memory quota (either through reads, or in-memory allocations). It
// will return the unconsumed tail of the byte slice, and the remaining memory
// quota. An error is returned if the byte slice is too small, or if the
// remainin memory quote is insufficient.
func UnmarshalI64(x *int64, buf []byte, rem int) ([]byte, int, error) {
	if len(buf) < SizeHintI64 || rem < SizeHintI64 {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	*x = int64(binary.BigEndian.Uint64(buf))
	return buf[SizeHintI64:], rem - SizeHintI64, nil
}


<|start_filename|>string.go<|end_filename|>
package surge

// SizeHintString is the number of bytes required to represent the given string
// in binary.
func SizeHintString(v string) int {
	return SizeHintU32 + len(v)
}

// MarshalString into a byte slice. It will not consume more memory than the
// remaining memory quota (either through writes, or in-memory allocations). It
// will return the unconsumed tail of the byte slice, and the remaining memory
// quota. An error is returned if the byte slice is too small, or if the
// remainin memory quote is insufficient.
func MarshalString(v string, buf []byte, rem int) ([]byte, int, error) {
	buf, rem, err := MarshalLen(uint32(len(v)), buf, rem)
	if err != nil {
		return buf, rem, err
	}
	if len(buf) < len(v) || rem < len(v) {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	n := copy(buf, v)
	return buf[n:], rem - n, nil
}

// UnmarshalString from a byte slice. It will not consume more memory than the
// remaining memory quota (either through reads, or in-memory allocations). It
// will return the unconsumed tail of the byte slice, and the remaining memory
// quota. An error is returned if the byte slice is too small, or if the
// remainin memory quote is insufficient.
func UnmarshalString(v *string, buf []byte, rem int) ([]byte, int, error) {
	strLen := uint32(0)
	buf, rem, err := UnmarshalLen(&strLen, 1, buf, rem)
	if err != nil {
		return buf, rem, err
	}
	n := int(strLen)
	if len(buf) < n {
		return buf, rem, ErrUnexpectedEndOfBuffer
	}
	strBuf, bufRem := buf[:n], buf[n:]
	*v = string(strBuf)
	return bufRem, rem - n, nil
}
