Files
bin/little/little.go

1361 lines
30 KiB
Go
Raw Normal View History

2025-08-16 19:31:11 +00:00
package little
// LOW TO HIGHT
import (
"errors"
"fmt"
"io"
"math"
)
const (
maxReadAttempts = 5
2025-08-16 21:11:17 +00:00
MinInt24 = -1 << 23 // -8388608
MaxInt24 = 1<<23 - 1 // 8388607
MinInt48 = -1 << 47 // -140737488355328
MaxInt48 = 1<<47 - 1 // 140737488355327
MaxUint24 = 1<<24 - 1 // 16777215
MaxUint48 = 1<<48 - 1 // 281474976710655
2025-08-16 19:31:11 +00:00
//Int32SignBit uint32 = 1 << 31
//Int64SignBit uint64 = 1 << 63
)
var (
// ErrReadOverflow shows 100% bug in the source reader
ErrReadOverflow = errors.New("bin: reader returned 'n' > bufsize")
// ErrNegativeReadCount shows 100% bug in the source reader
ErrNegativeReadCount = errors.New("bin: reader returned negative 'n'")
ErrNoSpace = errors.New("bin: no space")
ErrTooLong = errors.New("bin: too long") // слишком длинная строка или массив байт
ErrRange = errors.New("bin: out of range")
ErrNegativeSize = errors.New("bin: negative size")
2025-08-16 19:31:11 +00:00
)
func ReadByteAsInt(r io.Reader) (i int, err error) {
a, err := ReadN(r, 1)
if err != nil {
return
}
return int(a[0]), nil
}
func ReadUint16AsInt(r io.Reader) (_ int, err error) {
u16, err := ReadUint16(r)
if err != nil {
return
}
return int(u16), nil
}
2025-08-24 01:41:35 +00:00
func ReadUint32AsInt(r io.Reader) (_ int, err error) {
u32, err := ReadUint32(r)
if err != nil {
return
}
return int(u32), nil
}
2025-08-16 19:31:11 +00:00
func ReadUint32AsInt64(r io.Reader) (_ int64, err error) {
u32, err := ReadUint32(r)
if err != nil {
return
}
return int64(u32), nil
}
func ReadByte(r io.Reader) (byte, error) {
buf := make([]byte, 1)
if err := ReadNInto(r, buf); err != nil {
return 0, err
}
return buf[0], nil
}
// ReadN - безопасно читаем n байт. Обрабатывает все возможные ситуации, в том числе
// баги Reader
func ReadN(r io.Reader, n int) (_ []byte, err error) {
if n < 0 {
err = fmt.Errorf("wrong n=%d", n)
return
}
buf := make([]byte, n)
err = ReadNInto(r, buf)
if err != nil {
return
}
return buf, nil
}
func ReadNInto(r io.Reader, buf []byte) (err error) {
if len(buf) == 0 {
return
}
var q, total, readAttempts int
// Избегаем вечного цикла из-за неправильной реализации ридера
for readAttempts < maxReadAttempts {
bufsize := len(buf) - total
q, err = r.Read(buf[total:])
// Если буфер заполнен - успех, err игнорируем
if q == bufsize {
return nil
}
// Если ошибка - выходим с ошибкой
if err != nil {
return
}
// Если прочитали больше чем размер буфера. Баг в Reader
if q > bufsize {
err = ErrReadOverflow
return
}
// Если прочитали < 0. Баг в Reader
if q < 0 {
err = ErrNegativeReadCount
return
}
// Если ошибки нет, а прочитали 0 байт - чтобы не войти в бесконечный цикл
// увеличиваем readAttempts
if q == 0 {
readAttempts++
} else {
// Что-то прочитали, но меньше чем нужно - увеличиваем счетчик
// суммарно прочитанного
total += q
}
}
err = io.ErrNoProgress
return
}
func ReadString(r io.Reader, n int) (string, error) {
buf, err := ReadN(r, n)
if err != nil {
return "", nil
}
return string(buf), nil
}
// ReadInt16 - читает из io.Reader 2 байта и декодирует их в int16.
func ReadInt16(src io.Reader) (int16, error) {
a, err := ReadN(src, 2)
if err != nil {
return 0, err
}
num := int16(a[0])
num |= int16(a[1]) << 8
return num, nil
}
// ReadInt24 - читает из io.Reader 3 байта и декодирует их в int32.
// Нужно для протокола mbus.
func ReadInt24(src io.Reader) (int32, error) {
a, err := ReadN(src, 3)
if err != nil {
return 0, err
}
tmp := uint32(a[0])
tmp |= uint32(a[1]) << 8
tmp |= uint32(a[2]&127) << 16
if a[2] > 127 {
// для отрицательного числа старшие 9 бит выставляю в единицы
tmp |= (1<<9 - 1) << 23
}
return int32(tmp), nil
}
// ReadInt32 - читает из io.Reader 4 байта и декодирует их в int32.
func ReadInt32(src io.Reader) (int32, error) {
a, err := ReadN(src, 4)
if err != nil {
return 0, err
}
num := int32(a[0])
num |= int32(a[1]) << 8
num |= int32(a[2]) << 16
num |= int32(a[3]) << 24
return num, nil
}
// ReadInt48 - читает из io.Reader 6 байт и декодирует их в int64.
func ReadInt48(src io.Reader) (int64, error) {
a, err := ReadN(src, 6)
if err != nil {
return 0, err
}
tmp := uint64(a[0])
tmp |= uint64(a[1]) << 8
tmp |= uint64(a[2]) << 16
tmp |= uint64(a[3]) << 24
tmp |= uint64(a[4]) << 32
tmp |= uint64(a[5]&127) << 40
if a[5] > 127 {
// для отрицательного числа старшие 17 бит выставляю в единицы
tmp |= (1<<17 - 1) << 47
}
return int64(tmp), nil
}
// ReadInt64 - читает из io.Reader 8 байт и декодирует их в int64.
func ReadInt64(src io.Reader) (int64, error) {
a, err := ReadN(src, 8)
if err != nil {
return 0, err
}
num := int64(a[0])
num |= int64(a[1]) << 8
num |= int64(a[2]) << 16
num |= int64(a[3]) << 24
num |= int64(a[4]) << 32
num |= int64(a[5]) << 40
num |= int64(a[6]) << 48
num |= int64(a[7]) << 56
return num, nil
}
// ReadUint16 - читает из io.Reader 2 байта и декодирует их в uint16.
func ReadUint16(src io.Reader) (uint16, error) {
a, err := ReadN(src, 2)
if err != nil {
return 0, err
}
num := uint16(a[0])
num |= uint16(a[1]) << 8
return num, nil
}
// ReadUint24 - читает из io.Reader 3 байта и декодирует их в uint32.
func ReadUint24(src io.Reader) (uint32, error) {
a, err := ReadN(src, 3)
if err != nil {
return 0, err
}
num := uint32(a[0])
num |= uint32(a[1]) << 8
num |= uint32(a[2]) << 16
return num, nil
}
// ReadUint32 - читает из io.Reader 4 байта и декодирует их в uint32.
func ReadUint32(src io.Reader) (uint32, error) {
a, err := ReadN(src, 4)
if err != nil {
return 0, err
}
num := uint32(a[0])
num |= uint32(a[1]) << 8
num |= uint32(a[2]) << 16
num |= uint32(a[3]) << 24
return num, nil
}
// ReadUint48 - читает из io.Reader 6 байт и декодирует их в uint64.
func ReadUint48(src io.Reader) (uint64, error) {
a, err := ReadN(src, 6)
if err != nil {
return 0, err
}
num := uint64(a[0])
num |= uint64(a[1]) << 8
num |= uint64(a[2]) << 16
num |= uint64(a[3]) << 24
num |= uint64(a[4]) << 32
num |= uint64(a[5]) << 40
return num, nil
}
// ReadUint64 - читает из io.Reader 8 байт и декодирует их в uint64.
func ReadUint64(src io.Reader) (uint64, error) {
a, err := ReadN(src, 8)
if err != nil {
return 0, err
}
num := uint64(a[0])
num |= uint64(a[1]) << 8
num |= uint64(a[2]) << 16
num |= uint64(a[3]) << 24
num |= uint64(a[4]) << 32
num |= uint64(a[5]) << 40
num |= uint64(a[6]) << 48
num |= uint64(a[7]) << 56
return num, nil
}
// ReadFloat32 - читает из io.Reader 4 байта и декодирует их в float32.
func ReadFloat32(src io.Reader) (float32, error) {
tmp, err := ReadUint32(src)
if err != nil {
return 0, err
}
return math.Float32frombits(tmp), nil
}
// ReadFloat64 - читает из io.Reader 8 байт и декодирует их в float64.
func ReadFloat64(src io.Reader) (_ float64, err error) {
tmp, err := ReadUint64(src)
if err != nil {
return
}
return math.Float64frombits(tmp), nil
}
func ReadString8(src io.Reader) (string, error) {
length, err := ReadByteAsInt(src)
if err != nil {
return "", io.ErrUnexpectedEOF
}
return ReadString(src, length)
}
func ReadString16(src io.Reader) (string, error) {
length, err := ReadUint16AsInt(src)
if err != nil {
return "", err
}
return ReadString(src, length)
}
// WRITE
// WriteInt16 - записывает в io.Writer 2 байта
func WriteInt16(w io.Writer, num int16) (err error) {
_, err = w.Write([]byte{
byte(num),
byte(num >> 8),
})
return
}
// WriteInt24 - записывает в io.Writer 3 байта
func WriteInt24(w io.Writer, num int32) (err error) {
2025-08-16 21:11:17 +00:00
if num < MinInt24 || num > MaxInt24 {
return ErrRange
}
2025-08-16 19:31:11 +00:00
var sign byte
if num < 0 {
sign = 128
}
_, err = w.Write([]byte{
byte(num),
byte(num >> 8),
byte((num>>16)&127) | sign,
})
return
}
// WriteInt32 - записывает в io.Writer 4 байта
func WriteInt32(w io.Writer, num int32) (err error) {
_, err = w.Write([]byte{
byte(num),
byte(num >> 8),
byte(num >> 16),
byte(num >> 24),
})
return
}
// WriteInt48 - записывает в io.Writer 6 байт
func WriteInt48(w io.Writer, num int64) (err error) {
2025-08-16 21:11:17 +00:00
if num < MinInt48 || num > MaxInt48 {
return ErrRange
}
2025-08-16 19:31:11 +00:00
var sign byte
if num < 0 {
sign = 128
}
_, err = w.Write([]byte{
byte(num),
byte(num >> 8),
byte(num >> 16),
byte(num >> 24),
byte(num >> 32),
byte((num>>40)&127) | sign,
})
return
}
// WriteInt64 - записывает в io.Writer 8 байт
func WriteInt64(w io.Writer, num int64) (err error) {
_, err = w.Write([]byte{
byte(num),
byte(num >> 8),
byte(num >> 16),
byte(num >> 24),
byte(num >> 32),
byte(num >> 40),
byte(num >> 48),
byte(num >> 56),
})
return
}
// WriteUint16 - записывает в io.Writer 2 байта
func WriteUint16(w io.Writer, num uint16) (err error) {
_, err = w.Write([]byte{
byte(num),
byte(num >> 8),
})
return
}
// WriteUint24 - записывает в io.Writer 3 байта
func WriteUint24(w io.Writer, num uint32) (err error) {
2025-08-16 21:11:17 +00:00
if num > MaxUint24 {
return ErrRange
}
2025-08-16 19:31:11 +00:00
_, err = w.Write([]byte{
byte(num),
byte(num >> 8),
byte(num >> 16),
})
return
}
// WriteUint32 - записывает в io.Writer 4 байта
func WriteUint32(w io.Writer, num uint32) (err error) {
_, err = w.Write([]byte{
byte(num),
byte(num >> 8),
byte(num >> 16),
byte(num >> 24),
})
return
}
// WriteUint48 - записывает в io.Writer 6 байт
func WriteUint48(w io.Writer, num uint64) (err error) {
2025-08-16 21:11:17 +00:00
if num > MaxUint48 {
return ErrRange
}
2025-08-16 19:31:11 +00:00
_, err = w.Write([]byte{
byte(num),
byte(num >> 8),
byte(num >> 16),
byte(num >> 24),
byte(num >> 32),
byte(num >> 40),
})
return
}
// WriteUint64 - записывает в io.Writer 8 байт
func WriteUint64(w io.Writer, num uint64) (err error) {
_, err = w.Write([]byte{
byte(num),
byte(num >> 8),
byte(num >> 16),
byte(num >> 24),
byte(num >> 32),
byte(num >> 40),
byte(num >> 48),
byte(num >> 56),
})
return
}
// WriteFloat32 - записывает 4 байта в io.Writer
func WriteFloat32(w io.Writer, num float32) error {
return WriteUint32(w, math.Float32bits(num))
}
// WriteFloat64 - записывает 8 байт в io.Writer
func WriteFloat64(w io.Writer, num float64) error {
return WriteUint64(w, math.Float64bits(num))
}
func WriteString8(w io.Writer, str string) error {
if len(str) > 255 {
return ErrTooLong
}
tmp := make([]byte, 1+len(str))
PutString8(tmp, str)
_, err := w.Write(tmp)
return err
}
func WriteString16(w io.Writer, str string) error {
if len(str) > math.MaxUint16 {
return ErrTooLong
}
tmp := make([]byte, 2+len(str))
PutString16(tmp, str)
_, err := w.Write(tmp)
return err
}
2025-08-16 21:11:17 +00:00
// для записи timestamp-ов
2025-08-16 21:13:23 +00:00
func WriteInt64AsUint32(w io.Writer, num int64) error {
2025-10-20 08:26:25 +00:00
if num < 0 || num > int64(math.MaxUint32) {
2025-08-16 21:11:17 +00:00
return ErrRange
}
return WriteUint32(w, uint32(num))
}
// удобное кодирования длины
func WriteIntAsByte(w io.Writer, num int) error {
if num < 0 || num > math.MaxUint8 {
return ErrRange
}
_, err := w.Write([]byte{
byte(num),
})
return err
}
// удобное кодирования длины
func WriteIntAsUint16(w io.Writer, num int) error {
if num < 0 || num > math.MaxUint16 {
return ErrRange
}
return WriteUint16(w, uint16(num))
}
// удобное кодирования длины
func WriteIntAsUint24(w io.Writer, num int) error {
if num < 0 || num > MaxUint24 {
return ErrRange
}
return WriteUint24(w, uint32(num))
}
// удобное кодирования длины
func WriteIntAsUint32(w io.Writer, num int) error {
2025-10-20 08:26:25 +00:00
if num < 0 || int64(num) > int64(math.MaxUint32) {
2025-08-16 21:11:17 +00:00
return ErrRange
}
return WriteUint32(w, uint32(num))
}
2025-08-16 19:31:11 +00:00
// PUT
func PutInt16(a []byte, num int16) error {
if len(a) < 2 {
return ErrNoSpace
}
a[0] = byte(num)
a[1] = byte(num >> 8)
return nil
}
func PutInt24(a []byte, num int32) error {
2025-08-16 21:11:17 +00:00
if num < MinInt24 || num > MaxInt24 {
return ErrRange
}
2025-08-16 19:31:11 +00:00
if len(a) < 3 {
return ErrNoSpace
}
var sign byte
if num < 0 {
sign = 128
}
a[0] = byte(num)
a[1] = byte(num >> 8)
a[2] = byte((num>>16)&127) | sign
return nil
}
func PutInt32(a []byte, num int32) error {
if len(a) < 4 {
return ErrNoSpace
}
a[0] = byte(num)
a[1] = byte(num >> 8)
a[2] = byte(num >> 16)
a[3] = byte(num >> 24)
return nil
}
func PutInt48(a []byte, num int64) error {
2025-08-16 21:11:17 +00:00
if num < MinInt48 || num > MaxInt48 {
return ErrRange
}
2025-08-16 19:31:11 +00:00
if len(a) < 6 {
return ErrNoSpace
}
var sign byte
if num < 0 {
sign = 128
}
a[0] = byte(num)
a[1] = byte(num >> 8)
a[2] = byte(num >> 16)
a[3] = byte(num >> 24)
a[4] = byte(num >> 32)
a[5] = byte((num>>40)&127) | sign
return nil
}
func PutInt64(a []byte, num int64) error {
if len(a) < 8 {
return ErrNoSpace
}
a[0] = byte(num)
a[1] = byte(num >> 8)
a[2] = byte(num >> 16)
a[3] = byte(num >> 24)
a[4] = byte(num >> 32)
a[5] = byte(num >> 40)
a[6] = byte(num >> 48)
a[7] = byte(num >> 56)
return nil
}
func PutUint16(a []byte, num uint16) error {
if len(a) < 2 {
return ErrNoSpace
}
a[0] = byte(num)
a[1] = byte(num >> 8)
return nil
}
func PutUint24(a []byte, num uint32) error {
2025-08-16 21:11:17 +00:00
if num > MaxUint24 {
return ErrRange
}
2025-08-16 19:31:11 +00:00
if len(a) < 3 {
return ErrNoSpace
}
a[0] = byte(num)
a[1] = byte(num >> 8)
a[2] = byte(num >> 16)
return nil
}
func PutUint32(a []byte, num uint32) error {
if len(a) < 4 {
return ErrNoSpace
}
a[0] = byte(num)
a[1] = byte(num >> 8)
a[2] = byte(num >> 16)
a[3] = byte(num >> 24)
return nil
}
func PutUint48(a []byte, num uint64) error {
2025-08-16 21:11:17 +00:00
if num > MaxUint48 {
return ErrRange
}
2025-08-16 19:31:11 +00:00
if len(a) < 6 {
return ErrNoSpace
}
a[0] = byte(num)
a[1] = byte(num >> 8)
a[2] = byte(num >> 16)
a[3] = byte(num >> 24)
a[4] = byte(num >> 32)
a[5] = byte(num >> 40)
return nil
}
func PutUint64(a []byte, num uint64) error {
if len(a) < 8 {
return ErrNoSpace
}
a[0] = byte(num)
a[1] = byte(num >> 8)
a[2] = byte(num >> 16)
a[3] = byte(num >> 24)
a[4] = byte(num >> 32)
a[5] = byte(num >> 40)
a[6] = byte(num >> 48)
a[7] = byte(num >> 56)
return nil
}
// PutFloat32 - записывает 4 байта в массив
func PutFloat32(a []byte, num float32) error {
return PutUint32(a, math.Float32bits(num))
}
// PutFloat64 - записывает 8 байт в массив
func PutFloat64(a []byte, num float64) error {
return PutUint64(a, math.Float64bits(num))
}
// PutInt64AsUint32 - записывает 4 байта в массив (для unix timestamp)
func PutInt64AsUint32(a []byte, num int64) error {
return PutUint32(a, uint32(num))
}
// PutIntAsUint16 - записывает 2 байта в массив
func PutIntAsUint16(a []byte, num int) error {
return PutUint16(a, uint16(num))
}
func PutString8(a []byte, str string) error {
if len(str) > 255 {
return ErrTooLong
}
if len(a) < (1 + len(str)) {
return ErrNoSpace
}
a[0] = byte(len(str))
copy(a[1:], str)
return nil
}
func PutString16(a []byte, str string) error {
if len(str) > math.MaxUint16 {
return ErrTooLong
}
if len(a) < (2 + len(str)) {
return ErrNoSpace
}
PutUint16(a, uint16(len(str)))
copy(a[2:], str)
return nil
}
2025-09-11 11:06:45 +00:00
func PutBool(a []byte, flag bool) error {
if len(a) == 0 {
return ErrNoSpace
}
if flag {
a[0] = 1
} else {
a[0] = 0
}
return nil
}
2025-08-16 19:31:11 +00:00
// GET
// GetInt16 - читает из массива 2 байта и декодирует их в int16.
func GetInt16(a []byte) (num int16, err error) {
if len(a) < 2 {
return 0, io.ErrUnexpectedEOF
}
num = int16(a[0])
num |= int16(a[1]) << 8
return
}
// GetInt24 - читает из массива 3 байта и декодирует их в int32.
func GetInt24(a []byte) (num int32, err error) {
if len(a) < 3 {
return 0, io.ErrUnexpectedEOF
}
tmp := uint32(a[0])
tmp |= uint32(a[1]) << 8
tmp |= uint32(a[2]&127) << 16
if a[2] > 127 {
// для отрицательного числа старшие 9 бит выставляю в единицы
tmp |= (1<<9 - 1) << 23
}
return int32(tmp), nil
}
// GetInt32 - читает из массива 4 байта и декодирует их в int32.
func GetInt32(a []byte) (num int32, err error) {
if len(a) < 4 {
return 0, io.ErrUnexpectedEOF
}
num = int32(a[0])
num |= int32(a[1]) << 8
num |= int32(a[2]) << 16
num |= int32(a[3]) << 24
return
}
// GetInt48 - читает из массива 6 байт и декодирует их в int64.
func GetInt48(a []byte) (int64, error) {
if len(a) < 6 {
return 0, io.ErrUnexpectedEOF
}
tmp := uint64(a[0])
tmp |= uint64(a[1]) << 8
tmp |= uint64(a[2]) << 16
tmp |= uint64(a[3]) << 24
tmp |= uint64(a[4]) << 32
tmp |= uint64(a[5]&127) << 40
if a[5] > 127 {
// для отрицательного числа старшие 17 бит выставляю в единицы
tmp |= (1<<17 - 1) << 47
}
return int64(tmp), nil
}
// GetInt64 - читает из массива 8 байт и декодирует их в int64.
func GetInt64(a []byte) (num int64, err error) {
if len(a) < 8 {
return 0, io.ErrUnexpectedEOF
}
num = int64(a[0])
num |= int64(a[1]) << 8
num |= int64(a[2]) << 16
num |= int64(a[3]) << 24
num |= int64(a[4]) << 32
num |= int64(a[5]) << 40
num |= int64(a[6]) << 48
num |= int64(a[7]) << 56
return
}
// GetUint16 - читает из массива 2 байта и декодирует их в uint16.
func GetUint16(a []byte) (num uint16, err error) {
if len(a) < 2 {
return 0, io.ErrUnexpectedEOF
}
num = uint16(a[0])
num |= uint16(a[1]) << 8
return
}
// GetUint24 - читает из массива 3 байта и декодирует их в uint32.
func GetUint24(a []byte) (num uint32, err error) {
if len(a) < 3 {
return 0, io.ErrUnexpectedEOF
}
num = uint32(a[0])
num |= uint32(a[1]) << 8
num |= uint32(a[2]) << 16
return
}
// GetUint32 - читает из массива 4 байта и декодирует их в uint32.
func GetUint32(a []byte) (num uint32, err error) {
if len(a) < 4 {
return 0, io.ErrUnexpectedEOF
}
num = uint32(a[0])
num |= uint32(a[1]) << 8
num |= uint32(a[2]) << 16
num |= uint32(a[3]) << 24
return
}
// GetUint48 - читает из массива 6 байт и декодирует их в uint64.
func GetUint48(a []byte) (num uint64, err error) {
if len(a) < 6 {
return 0, io.ErrUnexpectedEOF
}
num = uint64(a[0])
num |= uint64(a[1]) << 8
num |= uint64(a[2]) << 16
num |= uint64(a[3]) << 24
num |= uint64(a[4]) << 32
num |= uint64(a[5]) << 40
return
}
// GetUint64 - читает из массива 8 байт и декодирует их в uint64.
func GetUint64(a []byte) (num uint64, err error) {
if len(a) < 8 {
return 0, io.ErrUnexpectedEOF
}
num = uint64(a[0])
num |= uint64(a[1]) << 8
num |= uint64(a[2]) << 16
num |= uint64(a[3]) << 24
num |= uint64(a[4]) << 32
num |= uint64(a[5]) << 40
num |= uint64(a[6]) << 48
num |= uint64(a[7]) << 56
return
}
// GetFloat32 - читает из массива 4 байта и декодирует их в float32.
func GetFloat32(a []byte) (float32, error) {
tmp, err := GetUint32(a)
if err != nil {
return 0, err
}
return math.Float32frombits(tmp), nil
}
// GetFloat64 - читает из массива 8 байт и декодирует их в float64.
func GetFloat64(a []byte) (float64, error) {
tmp, err := GetUint64(a)
if err != nil {
return 0, err
}
return math.Float64frombits(tmp), nil
}
func GetString8(a []byte) (string, error) {
pSize := 1
if len(a) < pSize {
return "", io.ErrUnexpectedEOF
}
length := int(a[0])
end := pSize + length
if len(a) < end {
return "", io.ErrUnexpectedEOF
}
return string(a[pSize:end]), nil
}
func GetString16(a []byte) (string, error) {
pSize := 2
if len(a) < pSize {
return "", io.ErrUnexpectedEOF
}
length, err := GetUint16(a)
if err != nil {
return "", err
}
end := pSize + int(length)
if len(a) < end {
return "", io.ErrUnexpectedEOF
}
return string(a[pSize:end]), nil
}
2025-09-11 11:06:45 +00:00
func GetBool(a []byte) (bool, error) {
if len(a) == 0 {
return false, io.ErrUnexpectedEOF
}
if a[0] == 1 {
return true, nil
} else {
return false, nil
}
}
2025-08-16 19:31:11 +00:00
// VAR
// WriteVarUint32 - записывает в Writer от 1 до 5 байт, возвращает количество
// записанных байт. Порядок байт - от младшего к старшему. Значение последнего
// байта всегда >= 128, остальных < 128.
func WriteVarUint32(w io.Writer, num uint32) (i int) {
a := make([]byte, 5)
for ; i < 5; i++ {
a[i] = byte(num & 127)
num >>= 7
if num == 0 {
break
}
}
a[i] |= 128
i++
w.Write(a[:i])
return
}
// ReadVarUint32 - читает из io.Reader от 1 до 5 байт, и декодирует их в uint32.
func ReadVarUint32(src io.Reader) (num uint32, err error) {
var b byte
for i := 0; i < 5; i++ {
b, err = ReadByte(src)
if err != nil {
return
}
if b >= 128 {
num |= uint32(b&127) << uint(i*7)
return
}
num |= uint32(b) << uint(i*7)
}
err = fmt.Errorf("value encoded as VarUint32 not found")
return
}
// WriteVarUint64 - записывает в Writer от 1 до 9 байт, возвращает количество
// записанных байт. Порядок байт - от младшего к старшему. В 9м байте все биты
// значащие.
func WriteVarUint64(w io.Writer, num uint64) (int, error) {
a := make([]byte, 9)
2026-06-04 23:56:18 +00:00
for i := range 8 {
2025-08-16 19:31:11 +00:00
a[i] = byte(num & 127)
num >>= 7
if num == 0 {
a[i] |= 128
i++
return w.Write(a[:i])
}
}
// в последнем 9м байте все биты значащие
a[8] = byte(num)
return w.Write(a)
}
// ReadVarUint64 - читает из io.Reader от 1 до 9 байт, и декодирует их в uint64.
func ReadVarUint64(src io.Reader) (num uint64, err error) {
var b byte
2026-06-04 23:56:18 +00:00
for i := range 8 {
2025-08-16 19:31:11 +00:00
b, err = ReadByte(src)
if err != nil {
return
}
if b >= 128 {
num |= uint64(b&127) << uint(i*7)
return
}
num |= uint64(b) << uint(i*7)
}
b, err = ReadByte(src)
if err != nil {
return
}
// в последнем 9м байте все биты значащие
num |= uint64(b) << 56
return
}
func WriteBool(w io.Writer, flag bool) (err error) {
var b byte
if flag {
b = 1
}
_, err = w.Write([]byte{b})
return
}
func ReadBool(src io.Reader) (bool, error) {
b, err := ReadByte(src)
if err != nil {
return false, err
}
return b == 1, nil
}
// READ/WRITE VAR SIZE
2025-08-16 19:31:11 +00:00
func WriteVarSize(w io.Writer, n int) (int, error) {
if n < 0 {
return 0, ErrNegativeSize
}
var (
num = uint64(n)
a = make([]byte, 9)
)
2026-06-04 23:56:18 +00:00
for i := range 8 {
2025-08-16 19:31:11 +00:00
a[i] = byte(num & 127)
num >>= 7
if num == 0 {
a[i] |= 128
i++
return w.Write(a[:i])
}
}
// в последнем 9м байте все биты значащие
a[8] = byte(num)
return w.Write(a)
}
func ReadVarSize(src io.Reader) (_ int, err error) {
var (
b byte
num uint64
)
2026-06-04 23:56:18 +00:00
for i := range 8 {
2025-08-16 19:31:11 +00:00
b, err = ReadByte(src)
if err != nil {
return
}
if b >= 128 {
num |= uint64(b&127) << uint(i*7)
return int(num), nil
}
num |= uint64(b) << uint(i*7)
}
b, err = ReadByte(src)
if err != nil {
return
}
// в последнем 9м байте все биты значащие
num |= uint64(b) << 56
return int(num), nil
}
2025-09-11 11:06:45 +00:00
var varUint32Cutoffs = []uint32{
1 << 7,
1 << 14,
1 << 21,
1 << 28,
}
func CountVarUint32(n uint32) int {
for i, cutoff := range varUint32Cutoffs {
if n < cutoff {
return i + 1
}
2025-09-11 11:06:45 +00:00
}
return 5
}
var varUint64Cutoffs = []uint64{
1 << 7,
1 << 14,
1 << 21,
1 << 28,
1 << 35,
1 << 42,
1 << 49,
1 << 56,
}
func CountVarUint64(n uint64) int {
for i, cutoff := range varUint64Cutoffs {
if n < cutoff {
return i + 1
}
}
return 9
}
2026-06-04 23:56:18 +00:00
var varInt64PlusCutoffs = []int64{
1 << 6,
1 << 13,
1 << 20,
1 << 27,
1 << 34,
1 << 41,
1 << 48,
1 << 55,
}
var varInt64MinusCutoffs = []int64{
-1 << 6,
-1 << 13,
-1 << 20,
-1 << 27,
-1 << 34,
-1 << 41,
-1 << 48,
-1 << 55,
}
func CountVarInt64(n int64) int {
if n >= 0 {
for i, cutoff := range varInt64PlusCutoffs {
if n < cutoff {
return i + 1
}
}
} else {
for i, cutoff := range varInt64MinusCutoffs {
if n >= cutoff {
return i + 1
}
}
}
return 9
}
func CountVarSize(n int) int {
u64 := uint64(n)
for i, cutoff := range varUint64Cutoffs {
if u64 < cutoff {
return i + 1
}
}
return 9
2025-09-11 11:06:45 +00:00
}
// PUT/GET VAR SIZE
2026-06-04 23:56:18 +00:00
func PutVarUint64(a []byte, num uint64) (int, error) {
var tmp [9]byte
for i := range 8 {
if i < len(a) {
if num < 128 {
tmp[i] = byte(num) | 128
q := i + 1
copy(a, tmp[:q])
return q, nil
}
tmp[i] = byte(num & 127)
num >>= 7
} else {
return 0, ErrNoSpace
}
}
if len(a) < 9 {
return 0, ErrNoSpace
}
tmp[8] = byte(num)
2026-06-04 23:56:18 +00:00
copy(a, tmp[:])
return 9, nil
}
2026-06-04 23:56:18 +00:00
func GetVarUint64(a []byte) (uint64, int, error) {
var num uint64
2026-06-04 23:56:18 +00:00
for i := range 8 {
if i < len(a) {
b := a[i]
num |= uint64(b&127) << uint(i*7)
if b >= 128 {
2026-06-04 23:56:18 +00:00
return num, i + 1, nil
}
} else {
2026-06-04 23:56:18 +00:00
return 0, 0, ErrNoSpace
}
}
if len(a) < 9 {
2026-06-04 23:56:18 +00:00
return 0, 0, ErrNoSpace
}
num |= uint64(a[8]) << 56
2026-06-04 23:56:18 +00:00
return num, 9, nil
}
func PutVarSize(arr []byte, n int) (int, error) {
if n < 0 {
return 0, ErrNegativeSize
}
return PutVarUint64(arr, uint64(n))
}
func GetVarSize(arr []byte) (int, error) {
num, _, err := GetVarUint64(arr)
if err != nil {
return 0, err
}
return int(num), nil
}
2026-06-04 23:56:18 +00:00
func PutVarInt64(arr []byte, num int64) (int, error) {
return PutVarUint64(arr, EncodeZigZag(num))
}
func GetVarInt64(arr []byte) (int64, int, error) {
u64, n, err := GetVarUint64(arr)
if err != nil {
return 0, 0, err
}
return DecodeZigZag(u64), n, nil
}
// REVERSE
// func reverseCopy(dst []byte, src []byte) error {
// if len(dst) >= len(src) {
// i := len(dst) - 1
// for _, b := range src {
// dst[i] = b
// i--
// }
// return nil
// }
// return ErrNoSpace
// }
func copyReversed(dst []byte, src []byte) error {
if len(dst) >= len(src) {
j := 0
for i := len(src) - 1; i >= 0; i-- {
dst[j] = src[i]
j++
}
return nil
}
return ErrNoSpace
}
// ReversePutVarUint64 - записує закодоване значення як PutVarUint64, але із оберненим
// порядком байт. Прочитати значення можна функцією ReverseGetVarUint64, вказавши правильне
// початкове зміщення справа.
func ReversePutVarUint64(arr []byte, num uint64) (int, error) {
var tmp [9]byte
for i := range 8 {
tmp[i] = byte(num & 127)
num >>= 7
if num == 0 {
tmp[i] |= 128
n := i + 1
err := copyReversed(arr, tmp[:n])
if err != nil {
return 0, err
}
return n, nil
}
}
tmp[8] = byte(num)
err := copyReversed(arr, tmp[:])
if err != nil {
return 0, err
}
return 9, nil
}
// ReverseGetVarUint64 - читає значення, закодоване функцією ReversePutVarUint64.
// Останній байт arr - це молодший байт закодованного значення.
func ReverseGetVarUint64(arr []byte) (uint64, int, error) {
var (
num uint64
j = len(arr) - 1
)
for i := range 8 {
if j >= 0 {
b := arr[j]
num |= uint64(b&127) << uint(i*7)
if b >= 128 {
return num, i + 1, nil
}
j--
} else {
return 0, 0, io.EOF
}
}
if j >= 0 {
num |= uint64(arr[j]) << 56
return num, 9, nil
}
return 0, 0, io.EOF
}
// ReversePutVarInt64 - записує закодоване значення як PutVarInt64, але із оберненим
// порядком байт. Прочитати значення можна функцією ReverseGetVarInt64, вказавши правильне
// початкове зміщення справа.
func ReversePutVarInt64(arr []byte, num int64) (int, error) {
return ReversePutVarUint64(arr, EncodeZigZag(num))
}
// ReverseGetVarInt64 - читає значення, закодоване функцією ReversePutVarInt64.
// Останній байт arr - це молодший байт закодованного значення.
func ReverseGetVarInt64(arr []byte) (int64, int, error) {
u64, n, err := ReverseGetVarUint64(arr)
if err != nil {
return 0, 0, err
}
return DecodeZigZag(u64), n, nil
}
// TailPutVarUint64 - записує закодоване значення в кінці arr.
// Прочитати значення можна функцією GetVarUint64, вказавши правильне
// початкове зміщення зліва.
func TailPutVarUint64(arr []byte, num uint64) (int, error) {
var tmp [9]byte
for i := range 8 {
tmp[i] = byte(num & 127)
num >>= 7
if num == 0 {
tmp[i] |= 128
n := i + 1
if len(arr) < n {
return 0, ErrNoSpace
}
copy(arr[len(arr)-n:], tmp[:n])
return n, nil
}
}
tmp[8] = byte(num)
if len(arr) < 9 {
return 0, ErrNoSpace
}
copy(arr[len(arr)-9:], tmp[:])
return 9, nil
}
// TailPutVarInt64 - записує закодоване значення в кінці arr.
// Прочитати значення можна функцією GetVarInt64, вказавши правильне
// початкове зміщення зліва.
func TailPutVarInt64(arr []byte, num int64) (int, error) {
return TailPutVarUint64(arr, EncodeZigZag(num))
}
// ZigZag encoding: int64 -> uint64
func EncodeZigZag(x int64) uint64 {
return uint64(x<<1) ^ uint64(x>>63)
}
// ZigZag decoding: uint64 -> int64
func DecodeZigZag(u uint64) int64 {
return int64(u>>1) ^ -(int64(u & 1))
}