/* This package contains help functions for stable marshaller. Their usage is totally optional. One can implement fast stable marshaller without these runtime function calls. */ package proto import ( "encoding/binary" "math" "math/bits" "reflect" ) type ( stableMarshaller interface { StableMarshal([]byte) ([]byte, error) StableSize() int } ) func BytesMarshal(field int, buf, v []byte) (int, error) { if len(v) == 0 { return 0, nil } prefix := field<<3 | 0x2 // buf length check can prevent panic at PutUvarint, but it will make // marshaller a bit slower. i := binary.PutUvarint(buf, uint64(prefix)) i += binary.PutUvarint(buf[i:], uint64(len(v))) i += copy(buf[i:], v) return i, nil } func BytesSize(field int, v []byte) int { ln := len(v) if ln == 0 { return 0 } prefix := field<<3 | 0x2 return VarUIntSize(uint64(prefix)) + VarUIntSize(uint64(ln)) + ln } func StringMarshal(field int, buf []byte, v string) (int, error) { return BytesMarshal(field, buf, []byte(v)) } func StringSize(field int, v string) int { return BytesSize(field, []byte(v)) } func BoolMarshal(field int, buf []byte, v bool) (int, error) { if !v { return 0, nil } prefix := field << 3 // buf length check can prevent panic at PutUvarint, but it will make // marshaller a bit slower. i := binary.PutUvarint(buf, uint64(prefix)) buf[i] = 0x1 return i + 1, nil } func BoolSize(field int, v bool) int { if !v { return 0 } prefix := field << 3 return VarUIntSize(uint64(prefix)) + 1 // bool is always 1 byte long } func UInt64Marshal(field int, buf []byte, v uint64) (int, error) { if v == 0 { return 0, nil } prefix := field << 3 // buf length check can prevent panic at PutUvarint, but it will make // marshaller a bit slower. i := binary.PutUvarint(buf, uint64(prefix)) i += binary.PutUvarint(buf[i:], v) return i, nil } func UInt64Size(field int, v uint64) int { if v == 0 { return 0 } prefix := field << 3 return VarUIntSize(uint64(prefix)) + VarUIntSize(v) } func Int64Marshal(field int, buf []byte, v int64) (int, error) { return UInt64Marshal(field, buf, uint64(v)) } func Int64Size(field int, v int64) int { return UInt64Size(field, uint64(v)) } func UInt32Marshal(field int, buf []byte, v uint32) (int, error) { return UInt64Marshal(field, buf, uint64(v)) } func UInt32Size(field int, v uint32) int { return UInt64Size(field, uint64(v)) } func Int32Marshal(field int, buf []byte, v int32) (int, error) { return UInt64Marshal(field, buf, uint64(v)) } func Int32Size(field int, v int32) int { return UInt64Size(field, uint64(v)) } func EnumMarshal(field int, buf []byte, v int32) (int, error) { return UInt64Marshal(field, buf, uint64(v)) } func EnumSize(field int, v int32) int { return UInt64Size(field, uint64(v)) } func RepeatedBytesMarshal(field int, buf []byte, v [][]byte) (int, error) { var offset int for i := range v { off, err := BytesMarshal(field, buf[offset:], v[i]) if err != nil { return 0, err } offset += off } return offset, nil } func RepeatedBytesSize(field int, v [][]byte) (size int) { for i := range v { size += BytesSize(field, v[i]) } return size } func RepeatedStringMarshal(field int, buf []byte, v []string) (int, error) { var offset int for i := range v { off, err := StringMarshal(field, buf[offset:], v[i]) if err != nil { return 0, err } offset += off } return offset, nil } func RepeatedStringSize(field int, v []string) (size int) { for i := range v { size += StringSize(field, v[i]) } return size } func RepeatedUInt64Marshal(field int, buf []byte, v []uint64) (int, error) { if len(v) == 0 { return 0, nil } prefix := field<<3 | 0x02 offset := binary.PutUvarint(buf, uint64(prefix)) _, arrSize := RepeatedUInt64Size(field, v) offset += binary.PutUvarint(buf[offset:], uint64(arrSize)) for i := range v { offset += binary.PutUvarint(buf[offset:], v[i]) } return offset, nil } func RepeatedUInt64Size(field int, v []uint64) (size, arraySize int) { if len(v) == 0 { return 0, 0 } for i := range v { size += VarUIntSize(v[i]) } arraySize = size size += VarUIntSize(uint64(size)) prefix := field<<3 | 0x2 size += VarUIntSize(uint64(prefix)) return size, arraySize } func RepeatedInt64Marshal(field int, buf []byte, v []int64) (int, error) { if len(v) == 0 { return 0, nil } convert := make([]uint64, len(v)) for i := range v { convert[i] = uint64(v[i]) } return RepeatedUInt64Marshal(field, buf, convert) } func RepeatedInt64Size(field int, v []int64) (size, arraySize int) { if len(v) == 0 { return 0, 0 } convert := make([]uint64, len(v)) for i := range v { convert[i] = uint64(v[i]) } return RepeatedUInt64Size(field, convert) } func RepeatedUInt32Marshal(field int, buf []byte, v []uint32) (int, error) { if len(v) == 0 { return 0, nil } convert := make([]uint64, len(v)) for i := range v { convert[i] = uint64(v[i]) } return RepeatedUInt64Marshal(field, buf, convert) } func RepeatedUInt32Size(field int, v []uint32) (size, arraySize int) { if len(v) == 0 { return 0, 0 } convert := make([]uint64, len(v)) for i := range v { convert[i] = uint64(v[i]) } return RepeatedUInt64Size(field, convert) } func RepeatedInt32Marshal(field int, buf []byte, v []int32) (int, error) { if len(v) == 0 { return 0, nil } convert := make([]uint64, len(v)) for i := range v { convert[i] = uint64(v[i]) } return RepeatedUInt64Marshal(field, buf, convert) } func RepeatedInt32Size(field int, v []int32) (size, arraySize int) { if len(v) == 0 { return 0, 0 } convert := make([]uint64, len(v)) for i := range v { convert[i] = uint64(v[i]) } return RepeatedUInt64Size(field, convert) } // varUIntSize returns length of varint byte sequence for uint64 value 'x'. func VarUIntSize(x uint64) int { return (bits.Len64(x|1) + 6) / 7 } func NestedStructurePrefix(field int64) (prefix uint64, ln int) { prefix = uint64(field<<3 | 0x02) return prefix, VarUIntSize(prefix) } func NestedStructureMarshal(field int64, buf []byte, v stableMarshaller) (int, error) { if v == nil || reflect.ValueOf(v).IsNil() { return 0, nil } prefix, _ := NestedStructurePrefix(field) offset := binary.PutUvarint(buf, prefix) n := v.StableSize() offset += binary.PutUvarint(buf[offset:], uint64(n)) _, err := v.StableMarshal(buf[offset:]) if err != nil { return 0, err } return offset + n, nil } func NestedStructureSize(field int64, v stableMarshaller) (size int) { if v == nil || reflect.ValueOf(v).IsNil() { return 0 } _, ln := NestedStructurePrefix(field) n := v.StableSize() size = ln + VarUIntSize(uint64(n)) + n return size } func Fixed64Marshal(field int, buf []byte, v uint64) (int, error) { if v == 0 { return 0, nil } prefix := field<<3 | 1 // buf length check can prevent panic at PutUvarint, but it will make // marshaller a bit slower. i := binary.PutUvarint(buf, uint64(prefix)) binary.LittleEndian.PutUint64(buf[i:], v) return i + 8, nil } func Fixed64Size(fNum int, v uint64) int { if v == 0 { return 0 } prefix := fNum<<3 | 1 return VarUIntSize(uint64(prefix)) + 8 } func Float64Marshal(field int, buf []byte, v float64) (int, error) { if v == 0 { return 0, nil } prefix := field<<3 | 1 i := binary.PutUvarint(buf, uint64(prefix)) binary.LittleEndian.PutUint64(buf[i:], math.Float64bits(v)) return i + 8, nil } func Float64Size(fNum int, v float64) int { if v == 0 { return 0 } prefix := fNum<<3 | 1 return VarUIntSize(uint64(prefix)) + 8 }