package registry import ( "fmt" "reflect" "git.maximhutz.com/max/lambda/pkg/codec" ) // A Codec is a type-erased codec that serializes and deserializes expressions // as Expr values, regardless of the underlying representation type. type Codec interface { codec.Codec[Expr] // InType returns the name of the representation this codec handles. InType() string } // A registeredCodec adapts a typed codec.Codec[T] into the type-erased Codec // interface. It wraps decoded values into Expr on decode, and extracts the // underlying T from an Expr on encode. type registeredCodec[T any] struct { codec codec.Codec[T] inType string } func (c registeredCodec[T]) Decode(s string) (Expr, error) { t, err := c.codec.Decode(s) if err != nil { return nil, err } return NewExpr(c.inType, t), nil } func (c registeredCodec[T]) Encode(r Expr) (string, error) { t, ok := r.Data().(T) if !ok { dataType := reflect.TypeOf(r.Data()) allowedType := reflect.TypeFor[T]() return "", fmt.Errorf("Codec for '%s' cannot parse '%s'", allowedType, dataType) } return c.codec.Encode(t) } func (c registeredCodec[T]) InType() string { return c.inType } // RegisterCodec registers a typed codec under the given representation name. // Returns an error if a codec for that representation is already registered. func RegisterCodec[T any](registry *Registry, m codec.Codec[T], inType string) error { if _, ok := registry.codecs[inType]; ok { return fmt.Errorf("Codec for '%s' already registered", inType) } registry.codecs[inType] = registeredCodec[T]{m, inType} return nil }