package codec import ( "encoding/binary" "encoding/json" "fmt" "strconv" ) func NewUint64Key[T ~uint64]() NameableKeyCodec[T] { return uint64Key[T]{} } type uint64Key[T ~uint64] struct{} func (uint64Key[T]) Encode(buffer []byte, key T) (int, error) { binary.BigEndian.PutUint64(buffer, (uint64)(key)) return 8, nil } func (uint64Key[T]) Decode(buffer []byte) (int, T, error) { if size := len(buffer); size < 8 { return 0, 0, fmt.Errorf("%w: wanted at least 8, got: %d", ErrEncoding, size) } return 8, (T)(binary.BigEndian.Uint64(buffer)), nil } func (uint64Key[T]) EncodeJSON(value T) ([]byte, error) { return uintEncodeJSON((uint64)(value)) } func (uint64Key[T]) DecodeJSON(b []byte) (T, error) { u, err := uintDecodeJSON(b, 64) if err != nil { return 0, err } return (T)(u), nil } func (uint64Key[T]) Size(_ T) int { return 8 } func (u uint64Key[T]) EncodeNonTerminal(buffer []byte, key T) (int, error) { return u.Encode(buffer, key) } func (u uint64Key[T]) DecodeNonTerminal(buffer []byte) (int, T, error) { return u.Decode(buffer) } func (u uint64Key[T]) SizeNonTerminal(key T) int { return u.Size(key) } func (uint64Key[T]) Stringify(key T) string { return strconv.FormatUint((uint64)(key), 10) } func (uint64Key[T]) KeyType() string { return "uint64" } func (u uint64Key[T]) WithName(name string) KeyCodec[T] { return NamedKeyCodec[T]{KeyCodec: u, Name: name} } func NewUint32Key[T ~uint32]() NameableKeyCodec[T] { return uint32Key[T]{} } type uint32Key[T ~uint32] struct{} func (uint32Key[T]) Encode(buffer []byte, key T) (int, error) { binary.BigEndian.PutUint32(buffer, (uint32)(key)) return 4, nil } func (uint32Key[T]) Decode(buffer []byte) (int, T, error) { if len(buffer) < 4 { return 0, 0, fmt.Errorf("%w: expected buffer of size 4", ErrEncoding) } return 4, (T)(binary.BigEndian.Uint32(buffer)), nil } func (uint32Key[T]) Size(_ T) int { return 4 } func (uint32Key[T]) EncodeJSON(value T) ([]byte, error) { return uintEncodeJSON((uint64)(value)) } func (uint32Key[T]) DecodeJSON(b []byte) (T, error) { u, err := uintDecodeJSON(b, 32) if err != nil { return 0, err } return (T)(u), nil } func (uint32Key[T]) Stringify(key T) string { return strconv.FormatUint(uint64(key), 10) } func (uint32Key[T]) KeyType() string { return "uint32" } func (u uint32Key[T]) EncodeNonTerminal(buffer []byte, key T) (int, error) { return u.Encode(buffer, key) } func (u uint32Key[T]) DecodeNonTerminal(buffer []byte) (int, T, error) { return u.Decode(buffer) } func (uint32Key[T]) SizeNonTerminal(_ T) int { return 4 } func (u uint32Key[T]) WithName(name string) KeyCodec[T] { return NamedKeyCodec[T]{KeyCodec: u, Name: name} } func NewUint16Key[T ~uint16]() NameableKeyCodec[T] { return uint16Key[T]{} } type uint16Key[T ~uint16] struct{} func (uint16Key[T]) Encode(buffer []byte, key T) (int, error) { binary.BigEndian.PutUint16(buffer, (uint16)(key)) return 2, nil } func (uint16Key[T]) Decode(buffer []byte) (int, T, error) { if len(buffer) < 2 { return 0, 0, fmt.Errorf("%w: invalid buffer size, wanted at least 2", ErrEncoding) } return 2, (T)(binary.BigEndian.Uint16(buffer)), nil } func (uint16Key[T]) Size(key T) int { return 2 } func (uint16Key[T]) EncodeJSON(value T) ([]byte, error) { return uintEncodeJSON((uint64)(value)) } func (uint16Key[T]) DecodeJSON(b []byte) (T, error) { u, err := uintDecodeJSON(b, 16) if err != nil { return 0, err } return (T)(u), nil } func (uint16Key[T]) Stringify(key T) string { return strconv.FormatUint((uint64)(key), 10) } func (uint16Key[T]) KeyType() string { return "uint16" } func (u uint16Key[T]) EncodeNonTerminal(buffer []byte, key T) (int, error) { return u.Encode(buffer, key) } func (u uint16Key[T]) DecodeNonTerminal(buffer []byte) (int, T, error) { return u.Decode(buffer) } func (u uint16Key[T]) SizeNonTerminal(key T) int { return u.Size(key) } func (u uint16Key[T]) WithName(name string) KeyCodec[T] { return NamedKeyCodec[T]{KeyCodec: u, Name: name} } func uintEncodeJSON(value uint64) ([]byte, error) { str := `"` + strconv.FormatUint(value, 10) + `"` return []byte(str), nil } func uintDecodeJSON(b []byte, bitSize int) (uint64, error) { var str string err := json.Unmarshal(b, &str) if err != nil { return 0, err } return strconv.ParseUint(str, 10, bitSize) }