Initial import

This commit is contained in:
2025-10-10 10:05:13 +02:00
parent 3effc1597b
commit b96b6e7f8f
164 changed files with 5473 additions and 0 deletions

248
storage/codec/binary.go Normal file
View 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) }

66
storage/codec/codec.go Normal file
View File

@@ -0,0 +1,66 @@
package codec
import (
"fmt"
"io"
)
type Codec interface {
Type() string
Encode(any) ([]byte, error)
Decode([]byte, any) error
}
type Stream interface {
Encode(any) error
Decode(any) error
}
var (
codecs = make(map[string]func() Codec)
streams = make(map[string]func(io.Reader, io.Writer) Stream)
)
func Register(name string, create func() Codec) {
if _, dupe := codecs[name]; dupe {
panic(fmt.Sprintf("codec: duplicate codec %q registered", name))
}
codecs[name] = create
}
func New(name string) (Codec, error) {
if f, ok := codecs[name]; ok {
return f(), nil
}
return nil, fmt.Errorf("codec: no %q codec registered", name)
}
func Must(name string) Codec {
c, err := New(name)
if err != nil {
panic(err)
}
return c
}
func RegisterStream(name string, create func(io.Reader, io.Writer) Stream) {
if _, dupe := streams[name]; dupe {
panic(fmt.Sprintf("codec: duplicate stream %q registered", name))
}
streams[name] = create
}
func NewStream(name string, r io.Reader, w io.Writer) (Stream, error) {
if f, ok := streams[name]; ok {
return f(r, w), nil
}
return nil, fmt.Errorf("codec: no %q stream registered", name)
}
func MustStream(name string, r io.Reader, w io.Writer) Stream {
s, err := NewStream(name, r, w)
if err != nil {
panic(err)
}
return s
}

77
storage/codec/default.go Normal file
View File

@@ -0,0 +1,77 @@
package codec
import (
"encoding/json"
"io"
"github.com/goccy/go-yaml"
)
func init() {
Register("json", func() Codec { return jsonCodec{} })
Register("yaml", func() Codec { return yamlCodec{} })
}
type jsonCodec struct{}
func (jsonCodec) Type() string { return "json" }
func (jsonCodec) Encode(value any) ([]byte, error) { return json.Marshal(value) }
func (jsonCodec) Decode(data []byte, value any) error { return json.Unmarshal(data, value) }
type jsonStream struct {
decoder *json.Decoder
encoder *json.Encoder
}
type JSONOption func(*json.Encoder)
func NewJSONStream(r io.Reader, w io.Writer, options ...JSONOption) Stream {
s := &jsonStream{
decoder: json.NewDecoder(r),
encoder: json.NewEncoder(w),
}
for _, option := range options {
option(s.encoder)
}
return s
}
func JSONIndent(prefix, indent string) JSONOption {
return func(e *json.Encoder) {
e.SetIndent(prefix, indent)
}
}
func JSONEscapeHTML(on bool) JSONOption {
return func(e *json.Encoder) {
e.SetEscapeHTML(on)
}
}
func (s jsonStream) Encode(value any) error { return s.encoder.Encode(value) }
func (s jsonStream) Decode(value any) error { return s.decoder.Decode(value) }
type yamlCodec struct{}
func (yamlCodec) Type() string { return "yaml" }
func (yamlCodec) Encode(value any) ([]byte, error) { return yaml.Marshal(value) }
func (yamlCodec) Decode(data []byte, value any) error { return yaml.Unmarshal(data, value) }
type yamlStream struct {
decoder *yaml.Decoder
encoder *yaml.Encoder
}
func NewYaMLStream(r io.Reader, w io.Writer, options ...yaml.EncodeOption) Stream {
s := &yamlStream{
decoder: yaml.NewDecoder(r),
encoder: yaml.NewEncoder(w),
}
for _, option := range options {
option(s.encoder)
}
return s
}
func (s yamlStream) Encode(value any) error { return s.encoder.Encode(value) }
func (s yamlStream) Decode(value any) error { return s.decoder.Decode(value) }