Initial import
This commit is contained in:
248
storage/codec/binary.go
Normal file
248
storage/codec/binary.go
Normal file
@@ -0,0 +1,248 @@
|
||||
package codec
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Register("binray", func() Codec { return binaryCodec{order: binary.NativeEndian} })
|
||||
Register("be", func() Codec { return binaryCodec{order: binary.BigEndian} })
|
||||
Register("le", func() Codec { return binaryCodec{order: binary.LittleEndian} })
|
||||
Register("ssh", func() Codec { return sshCodec{} })
|
||||
}
|
||||
|
||||
type binaryCodec struct {
|
||||
order binary.ByteOrder
|
||||
scratch [16]byte
|
||||
}
|
||||
|
||||
func (binaryCodec) Type() string { return "binary" }
|
||||
|
||||
func (codec binaryCodec) Encode(value any) ([]byte, error) {
|
||||
switch value := value.(type) {
|
||||
case bool:
|
||||
if value {
|
||||
return []byte{1}, nil
|
||||
}
|
||||
return []byte{0}, nil
|
||||
case *bool:
|
||||
if *value {
|
||||
return []byte{1}, nil
|
||||
}
|
||||
return []byte{0}, nil
|
||||
case int:
|
||||
codec.order.PutUint64(codec.scratch[:], uint64(value))
|
||||
return codec.scratch[:8], nil
|
||||
case *int:
|
||||
return codec.Encode(*value)
|
||||
case int8:
|
||||
return []byte{uint8(value)}, nil
|
||||
case *int8:
|
||||
return []byte{uint8(*value)}, nil
|
||||
case int16:
|
||||
codec.order.PutUint16(codec.scratch[:], uint16(value))
|
||||
return codec.scratch[:2], nil
|
||||
case *int16:
|
||||
return codec.Encode(*value)
|
||||
case int32:
|
||||
codec.order.PutUint32(codec.scratch[:], uint32(value))
|
||||
return codec.scratch[:4], nil
|
||||
case *int32:
|
||||
return codec.Encode(*value)
|
||||
case int64:
|
||||
codec.order.PutUint64(codec.scratch[:], uint64(value))
|
||||
return codec.scratch[:8], nil
|
||||
case *int64:
|
||||
return codec.Encode(*value)
|
||||
case uint:
|
||||
codec.order.PutUint64(codec.scratch[:], uint64(value))
|
||||
return codec.scratch[:8], nil
|
||||
case *uint:
|
||||
return codec.Encode(*value)
|
||||
case uint8:
|
||||
return []byte{value}, nil
|
||||
case *uint8:
|
||||
return []byte{*value}, nil
|
||||
case uint16:
|
||||
codec.order.PutUint16(codec.scratch[:], value)
|
||||
return codec.scratch[:2], nil
|
||||
case *uint16:
|
||||
return codec.Encode(*value)
|
||||
case uint32:
|
||||
codec.order.PutUint32(codec.scratch[:], value)
|
||||
return codec.scratch[:4], nil
|
||||
case *uint32:
|
||||
return codec.Encode(*value)
|
||||
case uint64:
|
||||
codec.order.PutUint64(codec.scratch[:], value)
|
||||
return codec.scratch[:8], nil
|
||||
case *uint64:
|
||||
return codec.Encode(*value)
|
||||
case float32:
|
||||
codec.order.PutUint32(codec.scratch[:], math.Float32bits(value))
|
||||
return codec.scratch[:4], nil
|
||||
case *float32:
|
||||
codec.order.PutUint32(codec.scratch[:], math.Float32bits(*value))
|
||||
return codec.scratch[:4], nil
|
||||
case float64:
|
||||
codec.order.PutUint64(codec.scratch[:], math.Float64bits(value))
|
||||
return codec.scratch[:8], nil
|
||||
case *float64:
|
||||
codec.order.PutUint64(codec.scratch[:], math.Float64bits(*value))
|
||||
return codec.scratch[:8], nil
|
||||
case complex64:
|
||||
codec.order.PutUint32(codec.scratch[0:], math.Float32bits(real(value)))
|
||||
codec.order.PutUint32(codec.scratch[4:], math.Float32bits(imag(value)))
|
||||
return codec.scratch[:8], nil
|
||||
case *complex64:
|
||||
codec.order.PutUint32(codec.scratch[0:], math.Float32bits(real(*value)))
|
||||
codec.order.PutUint32(codec.scratch[4:], math.Float32bits(imag(*value)))
|
||||
return codec.scratch[:8], nil
|
||||
case complex128:
|
||||
codec.order.PutUint64(codec.scratch[0:], math.Float64bits(real(value)))
|
||||
codec.order.PutUint64(codec.scratch[4:], math.Float64bits(imag(value)))
|
||||
return codec.scratch[:16], nil
|
||||
case *complex128:
|
||||
codec.order.PutUint64(codec.scratch[0:], math.Float64bits(real(*value)))
|
||||
codec.order.PutUint64(codec.scratch[4:], math.Float64bits(imag(*value)))
|
||||
return codec.scratch[:16], nil
|
||||
case string:
|
||||
n := binary.PutUvarint(codec.scratch[:], uint64(len(value)))
|
||||
return append(codec.scratch[:n], []byte(value)...), nil
|
||||
case *string:
|
||||
n := binary.PutUvarint(codec.scratch[:], uint64(len(*value)))
|
||||
return append(codec.scratch[:n], []byte(*value)...), nil
|
||||
case []byte:
|
||||
n := binary.PutUvarint(codec.scratch[:], uint64(len(value)))
|
||||
return append(codec.scratch[:n], value...), nil
|
||||
case *[]byte:
|
||||
n := binary.PutUvarint(codec.scratch[:], uint64(len(*value)))
|
||||
return append(codec.scratch[:n], *value...), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("codec: don't know how to binary encode %T", value)
|
||||
}
|
||||
}
|
||||
|
||||
func (codec binaryCodec) Decode(data []byte, value any) error {
|
||||
switch value := value.(type) {
|
||||
case *bool:
|
||||
if len(data) < 1 {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
*value = data[0] != 0
|
||||
|
||||
case *int:
|
||||
if len(data) < 8 {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
*value = int(codec.order.Uint64(data))
|
||||
case *int8:
|
||||
if len(data) < 1 {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
*value = int8(data[0])
|
||||
case *int16:
|
||||
if len(data) < 2 {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
*value = int16(codec.order.Uint16(data))
|
||||
case *int32:
|
||||
if len(data) < 4 {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
*value = int32(codec.order.Uint32(data))
|
||||
case *int64:
|
||||
if len(data) < 8 {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
*value = int64(codec.order.Uint64(data))
|
||||
case *uint:
|
||||
if len(data) < 8 {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
*value = uint(codec.order.Uint64(data))
|
||||
case *uint8:
|
||||
if len(data) < 1 {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
*value = data[0]
|
||||
case *uint16:
|
||||
if len(data) < 1 {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
*value = codec.order.Uint16(data)
|
||||
case *uint32:
|
||||
if len(data) < 4 {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
*value = codec.order.Uint32(data)
|
||||
case *uint64:
|
||||
if len(data) < 8 {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
*value = codec.order.Uint64(data)
|
||||
case *float32:
|
||||
if len(data) < 4 {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
*value = math.Float32frombits(codec.order.Uint32(data))
|
||||
case *float64:
|
||||
if len(data) < 8 {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
*value = math.Float64frombits(codec.order.Uint64(data))
|
||||
case *complex64:
|
||||
if len(data) < 8 {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
*value = complex(
|
||||
math.Float32frombits(codec.order.Uint32(data[0:])),
|
||||
math.Float32frombits(codec.order.Uint32(data[4:])),
|
||||
)
|
||||
case *complex128:
|
||||
if len(data) < 16 {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
*value = complex(
|
||||
math.Float64frombits(codec.order.Uint64(data[0:])),
|
||||
math.Float64frombits(codec.order.Uint64(data[8:])),
|
||||
)
|
||||
case *string:
|
||||
r := bytes.NewReader(data)
|
||||
n, err := binary.ReadUvarint(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if uint64(r.Len()) < n {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
*value = string(data[len(data)-r.Len():])
|
||||
|
||||
case *[]byte:
|
||||
r := bytes.NewReader(data)
|
||||
n, err := binary.ReadUvarint(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if uint64(r.Len()) < n {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
copy(*value, data[len(data)-r.Len():])
|
||||
|
||||
default:
|
||||
return fmt.Errorf("codec: don't know how to binary decode %T", value)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type sshCodec struct{}
|
||||
|
||||
func (sshCodec) Type() string { return "ssh" }
|
||||
func (sshCodec) Encode(value any) ([]byte, error) { return ssh.Marshal(value), nil }
|
||||
func (sshCodec) Decode(data []byte, value any) error { return ssh.Unmarshal(data, value) }
|
Reference in New Issue
Block a user