In cilium/cilium we have a few custom cell.DecodeHooks for unmarshalling values into custom types: https://github.com/cilium/cilium/blob/main/pkg/hive/hive.go#L105-L132
Unfortunately, this requires centralizing the configuration of how to handle the custom types and they run after the default hooks: https://github.com/cilium/hive/blob/main/cell/config.go#L126
I propose we add an interface to give types the ability to define their own method of unmarshalling:
type MapstructureUnmarshaler interface {
UnmarshalMapstructure(any) error
}
Then, we could define a new mapstructure.DecodeHookFunc:
func MapstructureUnmarshalerHook() mapstructure.DecodeHookFunc {
// Loosely adapted from the json.Unmarshal implementation.
// Specifically, the indirect() function:
// https://cs.opensource.google/go/go/+/refs/tags/go1.21.6:src/encoding/json/decode.go;l=426
return func(from, to reflect.Value) (interface{}, error) {
// If v is a named type and is addressable,
// start with its address, so that if the type has pointer methods,
// we find them.
if to.Kind() != reflect.Pointer && to.CanAddr() {
to = to.Addr()
}
// Still not a pointer, so no point in continuing
if to.Kind() != reflect.Pointer {
return from.Interface(), nil
}
// In order for the UnmarshalMapstructure to assign to 'to', then it needs
// to be non-nil
if to.IsNil() {
to.Set(reflect.New(to.Type().Elem()))
}
// convert to the interface, if it's not the desired interface, return the
// value unchanged
u, ok := to.Interface().(MapstructureUnmarshaler)
if !ok {
return from.Interface(), nil
}
// unmarshal "from" into 'to' using
if err := u.UnmarshalMapstructure(from.Interface()); err != nil {
return nil, err
}
return u, nil
}
}
This would enable removing the hooks here: https://github.com/cilium/cilium/blob/main/pkg/hive/hive.go#L105-L132 and instead the logic could be implemented as methods on the types themselves. In the case of protobuf types, it would require a wrapper type to implement the method on, but I think that's acceptable.
In cilium/cilium we have a few custom
cell.DecodeHooksfor unmarshalling values into custom types: https://github.com/cilium/cilium/blob/main/pkg/hive/hive.go#L105-L132Unfortunately, this requires centralizing the configuration of how to handle the custom types and they run after the default hooks: https://github.com/cilium/hive/blob/main/cell/config.go#L126
I propose we add an interface to give types the ability to define their own method of unmarshalling:
Then, we could define a new
mapstructure.DecodeHookFunc:This would enable removing the hooks here: https://github.com/cilium/cilium/blob/main/pkg/hive/hive.go#L105-L132 and instead the logic could be implemented as methods on the types themselves. In the case of protobuf types, it would require a wrapper type to implement the method on, but I think that's acceptable.