diff --git a/bin.go b/bin.go index c8d471f..baad344 100644 --- a/bin.go +++ b/bin.go @@ -1341,6 +1341,8 @@ const ( // типа float64 без потери точности MinSafeInt int64 = -(1 << 53) MaxSafeInt int64 = 1<<53 - 1 + + //x math.MaxUint64 ) // WriteMaxSafeUint - кодирует 2**53-1 // LH diff --git a/little/little.go b/little/little.go new file mode 100644 index 0000000..0c159c0 --- /dev/null +++ b/little/little.go @@ -0,0 +1,933 @@ +package little + +// LOW TO HIGHT + +import ( + "errors" + "fmt" + "io" + "math" +) + +const ( + maxReadAttempts = 5 + + //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") // слишком длинная строка или массив байт +) + +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 +} + +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) { + 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) { + 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) { + _, 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) { + _, 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 +} + +// 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 { + 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 { + 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 { + 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 { + 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 +} + +// 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 +} + +// 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) + for i := 0; i < 8; i++ { + 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 + for i := 0; i < 8; i++ { + 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 WriteVarSize(w io.Writer, n int) (int, error) { + num := uint64(n) + a := make([]byte, 9) + for i := 0; i < 8; i++ { + 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 + ) + for i := 0; i < 8; i++ { + 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 +} diff --git a/little/little_test.go b/little/little_test.go new file mode 100644 index 0000000..0408281 --- /dev/null +++ b/little/little_test.go @@ -0,0 +1,683 @@ +package little + +import ( + "bytes" + "fmt" + "math" + "math/rand" + "testing" +) + +const ( + 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 +) + +func TestContants(t *testing.T) { + fmt.Println(MinInt24 == -8388608) + fmt.Println(MaxInt24 == 8388607) + fmt.Println(MinInt48 == -140737488355328) + fmt.Println(MaxInt48 == 140737488355327) + fmt.Println(MaxUint24 == 16777215) + fmt.Println(MaxUint48 == 281474976710655) +} + +// PUT/GET INT +func TestPutGetInt16(t *testing.T) { + nums := []int16{ + math.MinInt16, + 0, + math.MaxInt16, + } + for _, num := range nums { + a := make([]byte, 2) + PutInt16(a, num) + decoded, err := GetInt16(a) + if err != nil { + t.Fatal(err) + } + if decoded != num { + t.Fatalf("num %d not equal decoded %d", num, decoded) + } + } +} + +func TestPutGetInt24(t *testing.T) { + nums := []int32{ + MinInt24, + 0, + MaxInt24, + } + for _, num := range nums { + a := make([]byte, 3) + PutInt24(a, num) + decoded, err := GetInt24(a) + if err != nil { + t.Fatal(err) + } + if decoded != num { + t.Fatalf("num %d not equal decoded %d", num, decoded) + } + } +} + +func TestPutGetInt32(t *testing.T) { + nums := []int32{ + math.MinInt32, + 0, + math.MaxInt32, + } + for _, num := range nums { + a := make([]byte, 4) + PutInt32(a, num) + decoded, err := GetInt32(a) + if err != nil { + t.Fatal(err) + } + if decoded != num { + t.Fatalf("num %d not equal decoded %d", num, decoded) + } + } +} + +func TestPutGetInt48(t *testing.T) { + nums := []int64{ + MinInt48, + 0, + MaxInt48, + } + for _, num := range nums { + a := make([]byte, 6) + PutInt48(a, num) + decoded, err := GetInt48(a) + if err != nil { + t.Fatal(err) + } + if decoded != num { + t.Fatalf("num %d not equal decoded %d", num, decoded) + } + } +} + +func TestPutGetInt64(t *testing.T) { + nums := []int64{ + math.MinInt64, + 0, + math.MaxInt64, + } + for _, num := range nums { + a := make([]byte, 8) + PutInt64(a, num) + decoded, err := GetInt64(a) + if err != nil { + t.Fatal(err) + } + if decoded != num { + t.Fatalf("num %d not equal decoded %d", num, decoded) + } + } +} + +// PUT/GET UINT +func TestPutGetUint16(t *testing.T) { + nums := []uint16{ + 0, + math.MaxUint16, + } + for _, num := range nums { + a := make([]byte, 2) + PutUint16(a, num) + decoded, err := GetUint16(a) + if err != nil { + t.Fatal(err) + } + if decoded != num { + t.Fatalf("num %d not equal decoded %d", num, decoded) + } + } +} + +func TestPutGetUint24(t *testing.T) { + nums := []uint32{ + 0, + MaxUint24, + } + for _, num := range nums { + a := make([]byte, 3) + PutUint24(a, num) + decoded, err := GetUint24(a) + if err != nil { + t.Fatal(err) + } + if decoded != num { + t.Fatalf("num %d not equal decoded %d", num, decoded) + } + } +} + +func TestPutGetUint32(t *testing.T) { + nums := []uint32{ + 0, + math.MaxUint32, + } + for _, num := range nums { + a := make([]byte, 4) + PutUint32(a, num) + decoded, err := GetUint32(a) + if err != nil { + t.Fatal(err) + } + if decoded != num { + t.Fatalf("num %d not equal decoded %d", num, decoded) + } + } +} + +func TestPutGetUint48(t *testing.T) { + nums := []uint64{ + 0, + MaxUint48, + } + for _, num := range nums { + a := make([]byte, 6) + PutUint48(a, num) + decoded, err := GetUint48(a) + if err != nil { + t.Fatal(err) + } + if decoded != num { + t.Fatalf("num %d not equal decoded %d", num, decoded) + } + } +} + +func TestPutGetUint64(t *testing.T) { + nums := []uint64{ + 0, + math.MaxUint64, + } + for _, num := range nums { + a := make([]byte, 8) + PutUint64(a, num) + decoded, err := GetUint64(a) + if err != nil { + t.Fatal(err) + } + if decoded != num { + t.Fatalf("num %d not equal decoded %d", num, decoded) + } + } +} + +// PUT/GET FLOAT + +func TestPutGetFloat32(t *testing.T) { + nums := []float32{ + -math.SmallestNonzeroFloat32, + math.SmallestNonzeroFloat32, + -1, + 0, + 1, + -math.MaxFloat32, + math.MaxFloat32, + } + for _, num := range nums { + a := make([]byte, 4) + PutFloat32(a, num) + decoded, err := GetFloat32(a) + if err != nil { + t.Fatal(err) + } + if decoded != num { + t.Fatalf("num %v not equal decoded %v", num, decoded) + } + } +} + +func TestPutGetFloat64(t *testing.T) { + nums := []float64{ + -math.SmallestNonzeroFloat64, + math.SmallestNonzeroFloat64, + -1, + 0, + 1, + -math.MaxFloat64, + math.MaxFloat64, + } + for _, num := range nums { + a := make([]byte, 8) + PutFloat64(a, num) + decoded, err := GetFloat64(a) + if err != nil { + t.Fatal(err) + } + if decoded != num { + t.Fatalf("num %v not equal decoded %v", num, decoded) + } + } +} + +// PUT/GET STRING + +func TestPutGetString8(t *testing.T) { + pSize := 1 // размер префикса, в котором закодирована длина строки + items := []string{ + "", + RandString(60), + RandString(150), + RandString(math.MaxUint8), + } + for _, origin := range items { + a := make([]byte, pSize+len(origin)) + err := PutString8(a, origin) + if err != nil { + t.Fatal(err) + } + decoded, err := GetString8(a) + if err != nil { + t.Fatal(err) + } + if decoded != origin { + t.Fatalf("origin %q not equal decoded %q", origin, decoded) + } + } + // запись слишком большой строки + tooLongStr := RandString(math.MaxUint8 + 1) + a := make([]byte, pSize+len(tooLongStr)) + err := PutString8(a, tooLongStr) + if err != ErrTooLong { + t.Fatal("too long string put did not return ErrTooLong") + } + // запись, когда в массиве недостаточно места + someStr := RandString(10) + a = make([]byte, 10) + err = PutString8(a, someStr) + if err != ErrNoSpace { + t.Fatal("put string longer then slice did not return ErrNoSpace") + } +} + +func TestPutGetString16(t *testing.T) { + pSize := 2 // размер префикса, в котором закодирована длина строки + items := []string{ + "", + RandString(255), + RandString(256), + RandString(math.MaxUint16), + } + for _, origin := range items { + a := make([]byte, pSize+len(origin)) + err := PutString16(a, origin) + if err != nil { + t.Fatal(err) + } + decoded, err := GetString16(a) + if err != nil { + t.Fatal(err) + } + if decoded != origin { + t.Fatalf("origin %q not equal decoded %q", origin, decoded) + } + } + // запись слишком большой строки + tooLongStr := RandString(math.MaxUint16 + 1) + a := make([]byte, pSize+len(tooLongStr)) + err := PutString16(a, tooLongStr) + if err != ErrTooLong { + t.Fatal("too long string put did not return ErrTooLong") + } + // запись, когда в массиве недостаточно места + someStr := RandString(10) + a = make([]byte, 11) + err = PutString16(a, someStr) + if err != ErrNoSpace { + t.Fatal("put string longer then slice did not return ErrNoSpace") + } +} + +// WRITE/READ INT + +func TestWriteReadInt16(t *testing.T) { + nums := []int16{ + math.MinInt16, + 0, + math.MaxInt16, + } + for _, num := range nums { + w := bytes.NewBuffer(nil) + err := WriteInt16(w, num) + if err != nil { + return + } + decoded, err := ReadInt16(w) + if err != nil { + t.Fatal(err) + } + if decoded != num { + t.Fatalf("num %d not equal decoded %d", num, decoded) + } + } +} + +func TestWriteReadInt24(t *testing.T) { + nums := []int32{ + MinInt24, + 0, + MaxInt24, + } + for _, num := range nums { + w := bytes.NewBuffer(nil) + err := WriteInt24(w, num) + if err != nil { + return + } + decoded, err := ReadInt24(w) + if err != nil { + t.Fatal(err) + } + if decoded != num { + t.Fatalf("num %d not equal decoded %d", num, decoded) + } + } +} + +func TestWriteReadInt32(t *testing.T) { + nums := []int32{ + math.MinInt32, + 0, + math.MaxInt32, + } + for _, num := range nums { + w := bytes.NewBuffer(nil) + err := WriteInt32(w, num) + if err != nil { + return + } + decoded, err := ReadInt32(w) + if err != nil { + t.Fatal(err) + } + if decoded != num { + t.Fatalf("num %d not equal decoded %d", num, decoded) + } + } +} + +func TestWriteReadInt48(t *testing.T) { + nums := []int64{ + MinInt48, + 0, + MaxInt48, + } + for _, num := range nums { + w := bytes.NewBuffer(nil) + err := WriteInt48(w, num) + if err != nil { + return + } + decoded, err := ReadInt48(w) + if err != nil { + t.Fatal(err) + } + if decoded != num { + t.Fatalf("num %d not equal decoded %d", num, decoded) + } + } +} + +func TestWriteReadInt64(t *testing.T) { + nums := []int64{ + math.MinInt64, + 0, + math.MaxInt64, + } + for _, num := range nums { + w := bytes.NewBuffer(nil) + err := WriteInt64(w, num) + if err != nil { + return + } + decoded, err := ReadInt64(w) + if err != nil { + t.Fatal(err) + } + if decoded != num { + t.Fatalf("num %d not equal decoded %d", num, decoded) + } + } +} + +// WRITE/READ UINT +func TestWriteReadUint16(t *testing.T) { + nums := []uint16{ + 0, + math.MaxUint16, + } + for _, num := range nums { + w := bytes.NewBuffer(nil) + err := WriteUint16(w, num) + if err != nil { + return + } + decoded, err := ReadUint16(w) + if err != nil { + t.Fatal(err) + } + if decoded != num { + t.Fatalf("num %d not equal decoded %d", num, decoded) + } + } +} + +func TestWriteReadUint24(t *testing.T) { + nums := []uint32{ + 0, + MaxUint24, + } + for _, num := range nums { + w := bytes.NewBuffer(nil) + err := WriteUint24(w, num) + if err != nil { + return + } + decoded, err := ReadUint24(w) + if err != nil { + t.Fatal(err) + } + if decoded != num { + t.Fatalf("num %d not equal decoded %d", num, decoded) + } + } +} + +func TestWriteReadUint32(t *testing.T) { + nums := []uint32{ + 0, + math.MaxUint32, + } + for _, num := range nums { + w := bytes.NewBuffer(nil) + err := WriteUint32(w, num) + if err != nil { + return + } + decoded, err := ReadUint32(w) + if err != nil { + t.Fatal(err) + } + if decoded != num { + t.Fatalf("num %d not equal decoded %d", num, decoded) + } + } +} + +func TestWriteReadUint48(t *testing.T) { + nums := []uint64{ + 0, + MaxUint48, + } + for _, num := range nums { + w := bytes.NewBuffer(nil) + err := WriteUint48(w, num) + if err != nil { + return + } + decoded, err := ReadUint48(w) + if err != nil { + t.Fatal(err) + } + if decoded != num { + t.Fatalf("num %d not equal decoded %d", num, decoded) + } + } +} + +func TestWriteReadUint64(t *testing.T) { + nums := []uint64{ + 0, + math.MaxUint64, + } + for _, num := range nums { + w := bytes.NewBuffer(nil) + err := WriteUint64(w, num) + if err != nil { + return + } + decoded, err := ReadUint64(w) + if err != nil { + t.Fatal(err) + } + if decoded != num { + t.Fatalf("num %d not equal decoded %d", num, decoded) + } + } +} + +// WRITE/READ FLOAT +func TestWriteReadFloat32(t *testing.T) { + nums := []float32{ + -math.SmallestNonzeroFloat32, + math.SmallestNonzeroFloat32, + -1, + 0, + 1, + -math.MaxFloat32, + math.MaxFloat32, + } + for _, num := range nums { + w := bytes.NewBuffer(nil) + err := WriteFloat32(w, num) + if err != nil { + return + } + decoded, err := ReadFloat32(w) + if err != nil { + t.Fatal(err) + } + if decoded != num { + t.Fatalf("num %v not equal decoded %v", num, decoded) + } + } +} + +func TestWriteReadFloat64(t *testing.T) { + nums := []float64{ + -math.SmallestNonzeroFloat64, + math.SmallestNonzeroFloat64, + -1, + 0, + 1, + -math.MaxFloat64, + math.MaxFloat64, + } + for _, num := range nums { + w := bytes.NewBuffer(nil) + err := WriteFloat64(w, num) + if err != nil { + return + } + decoded, err := ReadFloat64(w) + if err != nil { + t.Fatal(err) + } + if decoded != num { + t.Fatalf("num %v not equal decoded %v", num, decoded) + } + } +} + +// WRITE/READ STRING + +func TestWriteReadString8(t *testing.T) { + items := []string{ + "", + RandString(60), + RandString(150), + RandString(255), + } + for _, origin := range items { + w := bytes.NewBuffer(nil) + err := WriteString8(w, origin) + if err != nil { + return + } + decoded, err := ReadString8(w) + if err != nil { + t.Fatal(err) + } + if decoded != origin { + t.Fatalf("origin %q not equal decoded %q", origin, decoded) + } + } + // запись слишком большой строки + w := bytes.NewBuffer(nil) + err := WriteString8(w, RandString(256)) + if err != ErrTooLong { + t.Fatal("too long string write did not return ErrTooLong") + } +} + +func TestWriteReadString16(t *testing.T) { + items := []string{ + "", + RandString(255), + RandString(256), + RandString(math.MaxUint16), + } + for _, origin := range items { + w := bytes.NewBuffer(nil) + err := WriteString16(w, origin) + if err != nil { + return + } + decoded, err := ReadString16(w) + if err != nil { + t.Fatal(err) + } + if decoded != origin { + t.Fatalf("origin %q not equal decoded %q", origin, decoded) + } + } + // запись слишком большой строки + w := bytes.NewBuffer(nil) + err := WriteString8(w, RandString(math.MaxUint16+1)) + if err != ErrTooLong { + t.Fatal("too long string write did not return ErrTooLong") + } +} + +// HELPERS + +const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + +func RandString(n int) string { + b := make([]byte, n) + for i := range b { + b[i] = letters[rand.Intn(len(letters))] + } + return string(b) +}