From 30382bee7e4d014796f966d8a47ec6e571223b51 Mon Sep 17 00:00:00 2001 From: "M.V. Hutz" Date: Sat, 7 Feb 2026 00:36:05 -0500 Subject: [PATCH] feat: marshalers to codecs --- cmd/lambda/registry.go | 7 ++-- internal/registry/codec.go | 50 +++++++++++++++++++++++ internal/registry/conversion.go | 40 ++++-------------- internal/registry/marshaler.go | 50 ----------------------- internal/registry/registry.go | 16 ++++---- pkg/codec/codec.go | 10 ++--- pkg/convert/saccharine_to_lambda.go | 9 +--- pkg/lambda/{marshaler.go => codec.go} | 2 +- pkg/saccharine/{marshaler.go => codec.go} | 2 +- 9 files changed, 79 insertions(+), 107 deletions(-) create mode 100644 internal/registry/codec.go delete mode 100644 internal/registry/marshaler.go rename pkg/lambda/{marshaler.go => codec.go} (84%) rename pkg/saccharine/{marshaler.go => codec.go} (89%) diff --git a/cmd/lambda/registry.go b/cmd/lambda/registry.go index 968b18a..e0b3f57 100644 --- a/cmd/lambda/registry.go +++ b/cmd/lambda/registry.go @@ -12,14 +12,15 @@ func GetRegistry() *registry.Registry { r := registry.New() // Codecs - (registry.RegisterCodec(r, convert.Saccharine2Lambda{}, "saccharine", "lambda")) + (registry.RegisterConversion(r, convert.Saccharine2Lambda, "saccharine", "lambda")) + (registry.RegisterConversion(r, convert.Lambda2Saccharine, "lambda", "saccharine")) // Engines (registry.RegisterEngine(r, normalorder.NewProcess, "normalorder", "lambda")) // Marshalers - (registry.RegisterMarshaler(r, lambda.Marshaler{}, "lambda")) - (registry.RegisterMarshaler(r, saccharine.Marshaler{}, "saccharine")) + (registry.RegisterCodec(r, lambda.Marshaler{}, "lambda")) + (registry.RegisterCodec(r, saccharine.Marshaler{}, "saccharine")) return r } diff --git a/internal/registry/codec.go b/internal/registry/codec.go new file mode 100644 index 0000000..f23da98 --- /dev/null +++ b/internal/registry/codec.go @@ -0,0 +1,50 @@ +package registry + +import ( + "fmt" + "reflect" + + "git.maximhutz.com/max/lambda/pkg/codec" +) + +type Codec interface { + codec.Codec[Repr] + + InType() string +} + +type convertedCodec[T any] struct { + codec codec.Codec[T] + inType string +} + +func (c convertedCodec[T]) Decode(s string) (Repr, error) { + t, err := c.codec.Decode(s) + if err != nil { + return nil, err + } + + return NewRepr(c.inType, t), nil +} + +func (c convertedCodec[T]) Encode(r Repr) (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 convertedCodec[T]) InType() string { return c.inType } + +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] = convertedCodec[T]{m, inType} + return nil +} diff --git a/internal/registry/conversion.go b/internal/registry/conversion.go index 2cf4fad..b793ed2 100644 --- a/internal/registry/conversion.go +++ b/internal/registry/conversion.go @@ -13,18 +13,18 @@ type Conversion interface { Run(Repr) (Repr, error) } -type forwardCodec[T, U any] struct { - codec codec.Codec[T, U] +type convertedConversion[T, U any] struct { + conversion codec.Conversion[T, U] inType, outType string } -func (c forwardCodec[T, U]) Run(r Repr) (Repr, error) { +func (c convertedConversion[T, U]) Run(r Repr) (Repr, error) { t, ok := r.Data().(T) if !ok { return nil, fmt.Errorf("could not parse '%v' as '%s'", t, c.inType) } - u, err := c.codec.Encode(t) + u, err := c.conversion(t) if err != nil { return nil, err } @@ -32,36 +32,12 @@ func (c forwardCodec[T, U]) Run(r Repr) (Repr, error) { return NewRepr(c.outType, u), nil } -func (c forwardCodec[T, U]) InType() string { return c.inType } +func (c convertedConversion[T, U]) InType() string { return c.inType } -func (c forwardCodec[T, U]) OutType() string { return c.outType } +func (c convertedConversion[T, U]) OutType() string { return c.outType } -type backwardCodec[T, U any] struct { - codec codec.Codec[T, U] - inType, outType string -} - -func (c backwardCodec[T, U]) Run(r Repr) (Repr, error) { - u, ok := r.Data().(U) - if !ok { - return nil, fmt.Errorf("could not parse '%v' as '%s'", r, c.outType) - } - - t, err := c.codec.Decode(u) - if err != nil { - return nil, err - } - - return NewRepr(c.inType, t), nil -} - -func (c backwardCodec[T, U]) InType() string { return c.outType } - -func (c backwardCodec[T, U]) OutType() string { return c.inType } - -func RegisterCodec[T, U any](registry *Registry, c codec.Codec[T, U], inType, outType string) error { - registry.converter.Add(forwardCodec[T, U]{c, inType, outType}) - registry.converter.Add(backwardCodec[T, U]{c, inType, outType}) +func RegisterConversion[T, U any](registry *Registry, conversion func(T) (U, error), inType, outType string) error { + registry.converter.Add(convertedConversion[T, U]{conversion, inType, outType}) return nil } diff --git a/internal/registry/marshaler.go b/internal/registry/marshaler.go deleted file mode 100644 index d7a104b..0000000 --- a/internal/registry/marshaler.go +++ /dev/null @@ -1,50 +0,0 @@ -package registry - -import ( - "fmt" - "reflect" - - "git.maximhutz.com/max/lambda/pkg/codec" -) - -type Marshaler interface { - codec.Marshaler[Repr] - - InType() string -} - -type convertedMarshaler[T any] struct { - codec codec.Marshaler[T] - inType string -} - -func (c convertedMarshaler[T]) Decode(s string) (Repr, error) { - t, err := c.codec.Decode(s) - if err != nil { - return nil, err - } - - return NewRepr(c.inType, t), nil -} - -func (c convertedMarshaler[T]) Encode(r Repr) (string, error) { - t, ok := r.Data().(T) - if !ok { - dataType := reflect.TypeOf(r.Data()) - allowedType := reflect.TypeFor[T]() - return "", fmt.Errorf("marshaler for '%s' cannot parse '%s'", allowedType, dataType) - } - - return c.codec.Encode(t) -} - -func (c convertedMarshaler[T]) InType() string { return c.inType } - -func RegisterMarshaler[T any](registry *Registry, m codec.Marshaler[T], inType string) error { - if _, ok := registry.marshalers[inType]; ok { - return fmt.Errorf("marshaler for '%s' already registered", inType) - } - - registry.marshalers[inType] = convertedMarshaler[T]{m, inType} - return nil -} diff --git a/internal/registry/registry.go b/internal/registry/registry.go index 9171ef5..dea5d34 100644 --- a/internal/registry/registry.go +++ b/internal/registry/registry.go @@ -7,16 +7,16 @@ import ( ) type Registry struct { - marshalers map[string]Marshaler - converter *Converter - engines map[string]Engine + codecs map[string]Codec + converter *Converter + engines map[string]Engine } func New() *Registry { return &Registry{ - marshalers: map[string]Marshaler{}, - converter: NewConverter(), - engines: map[string]Engine{}, + codecs: map[string]Codec{}, + converter: NewConverter(), + engines: map[string]Engine{}, } } @@ -61,7 +61,7 @@ func (r *Registry) ConvertTo(repr Repr, outType string) (Repr, error) { } func (r *Registry) Marshal(repr Repr) (string, error) { - m, ok := r.marshalers[repr.ID()] + m, ok := r.codecs[repr.ID()] if !ok { return "", fmt.Errorf("no marshaler for '%s'", repr.ID()) } @@ -70,7 +70,7 @@ func (r *Registry) Marshal(repr Repr) (string, error) { } func (r *Registry) Unmarshal(s string, outType string) (Repr, error) { - m, ok := r.marshalers[outType] + m, ok := r.codecs[outType] if !ok { return nil, fmt.Errorf("no marshaler for '%s'", outType) } diff --git a/pkg/codec/codec.go b/pkg/codec/codec.go index 3132409..ecbe258 100644 --- a/pkg/codec/codec.go +++ b/pkg/codec/codec.go @@ -1,8 +1,8 @@ package codec -type Codec[T, U any] interface { - Encode(T) (U, error) - Decode(U) (T, error) -} +type Conversion[T, U any] = func(T) (U, error) -type Marshaler[T any] = Codec[T, string] +type Codec[T any] interface { + Encode(T) (string, error) + Decode(string) (T, error) +} diff --git a/pkg/convert/saccharine_to_lambda.go b/pkg/convert/saccharine_to_lambda.go index e19e77c..73aeb0f 100644 --- a/pkg/convert/saccharine_to_lambda.go +++ b/pkg/convert/saccharine_to_lambda.go @@ -3,7 +3,6 @@ package convert import ( "fmt" - "git.maximhutz.com/max/lambda/pkg/codec" "git.maximhutz.com/max/lambda/pkg/lambda" "git.maximhutz.com/max/lambda/pkg/saccharine" ) @@ -125,14 +124,10 @@ func decodeExression(l lambda.Expression) saccharine.Expression { } } -type Saccharine2Lambda struct{} - -func (c Saccharine2Lambda) Decode(l lambda.Expression) (saccharine.Expression, error) { +func Lambda2Saccharine(l lambda.Expression) (saccharine.Expression, error) { return decodeExression(l), nil } -func (c Saccharine2Lambda) Encode(s saccharine.Expression) (lambda.Expression, error) { +func Saccharine2Lambda(s saccharine.Expression) (lambda.Expression, error) { return encodeExpression(s), nil } - -var _ codec.Codec[saccharine.Expression, lambda.Expression] = (*Saccharine2Lambda)(nil) diff --git a/pkg/lambda/marshaler.go b/pkg/lambda/codec.go similarity index 84% rename from pkg/lambda/marshaler.go rename to pkg/lambda/codec.go index 6ee2c79..04cd83c 100644 --- a/pkg/lambda/marshaler.go +++ b/pkg/lambda/codec.go @@ -16,4 +16,4 @@ func (m Marshaler) Encode(e Expression) (string, error) { return e.String(), nil } -var _ codec.Marshaler[Expression] = (*Marshaler)(nil) +var _ codec.Codec[Expression] = (*Marshaler)(nil) diff --git a/pkg/saccharine/marshaler.go b/pkg/saccharine/codec.go similarity index 89% rename from pkg/saccharine/marshaler.go rename to pkg/saccharine/codec.go index bc5c3dc..bbdb2c4 100644 --- a/pkg/saccharine/marshaler.go +++ b/pkg/saccharine/codec.go @@ -21,4 +21,4 @@ func (m Marshaler) Encode(e Expression) (string, error) { return stringifyExpression(e), nil } -var _ codec.Marshaler[Expression] = (*Marshaler)(nil) +var _ codec.Codec[Expression] = (*Marshaler)(nil)