Big nasty commit to add code generation for encoding
This commit is contained in:
48
tape/dynamic.go
Normal file
48
tape/dynamic.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package tape
|
||||
|
||||
import "fmt"
|
||||
import "reflect"
|
||||
import "git.tebibyte.media/sashakoshka/hopp/codec"
|
||||
|
||||
// EncodeAny encodes an "any" value. Returns an error if the underlying type is
|
||||
// unsupported. Supported types are:
|
||||
//
|
||||
// - int
|
||||
// - int<N>
|
||||
// - uint
|
||||
// - uint<N>
|
||||
// - string
|
||||
// - []<supported type>
|
||||
// - map[uint16]<supported type>
|
||||
func EncodeAny(encoder *codec.Encoder, value any) (Tag, error) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
// TagAny returns the correct tag for an "any" value. Returns an error if the
|
||||
// underlying type is unsupported. See [EncodeAny] for a list of supported
|
||||
// types.
|
||||
func TagAny(value any) (Tag, error) {
|
||||
// primitives
|
||||
switch value := value.(type) {
|
||||
case int, uint: return LI.WithCN(3), nil
|
||||
case int8, uint8: return LI.WithCN(0), nil
|
||||
case int16, uint16: return LI.WithCN(1), nil
|
||||
case int32, uint32: return LI.WithCN(3), nil
|
||||
case int64, uint64: return LI.WithCN(8), nil
|
||||
case string: return bufferLenTag(len(value)), nil
|
||||
case []byte: return bufferLenTag(len(value)), nil
|
||||
}
|
||||
|
||||
// aggregates
|
||||
reflectType := reflect.TypeOf(value)
|
||||
switch reflectType.Kind() {
|
||||
case reflect.Slice: return OTA.WithCN(reflect.ValueOf(value).Len()), nil
|
||||
case reflect.Array: return OTA.WithCN(reflectType.Len()), nil
|
||||
case reflect.Map:
|
||||
if reflectType.Key() == reflect.TypeOf(uint16(0)) {
|
||||
return OTA.WithCN(reflect.ValueOf(value).Len()), nil
|
||||
}
|
||||
return 0, fmt.Errorf("cannot encode map key %T, key must be uint16", value)
|
||||
}
|
||||
return 0, fmt.Errorf("cannot encode type %T", value)
|
||||
}
|
||||
45
tape/tag.go
Normal file
45
tape/tag.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package tape
|
||||
|
||||
import "git.tebibyte.media/sashakoshka/hopp/codec"
|
||||
|
||||
type Tag byte; const (
|
||||
SI Tag = 0 << 5 // Small integer
|
||||
LI Tag = 1 << 5 // Large integer
|
||||
FP Tag = 2 << 5 // Floating point
|
||||
SBA Tag = 3 << 5 // Small byte array
|
||||
LBA Tag = 4 << 5 // Large byte array
|
||||
OTA Tag = 5 << 5 // One-tag array
|
||||
KTV Tag = 6 << 5 // Key-tag-value table
|
||||
TNMask Tag = 0xE0 // The entire TN bitfield
|
||||
CNMask Tag = 0x20 // The entire CN bitfield
|
||||
CNLimit Tag = 32 // All valid CNs are < CNLimit
|
||||
)
|
||||
|
||||
func (tag Tag) TN() int {
|
||||
return int(tag >> 5)
|
||||
}
|
||||
|
||||
func (tag Tag) CN() int {
|
||||
return int(tag & CNMask)
|
||||
}
|
||||
|
||||
func (tag Tag) WithCN(cn int) Tag {
|
||||
return (tag & TNMask) | Tag(cn % 32)
|
||||
}
|
||||
|
||||
func (tag Tag) Is(other Tag) bool {
|
||||
return tag.TN() == other.TN()
|
||||
}
|
||||
|
||||
// BufferTag returns the appropriate tag for a buffer.
|
||||
func BufferTag(value []byte) Tag {
|
||||
return bufferLenTag(len(value))
|
||||
}
|
||||
|
||||
func bufferLenTag(length int) Tag {
|
||||
if length < int(CNLimit) {
|
||||
return SBA.WithCN(length)
|
||||
} else {
|
||||
return LBA.WithCN(codec.IntBytes(uint64(length)))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user