mitchellh / mapstructure

Go library for decoding generic map values into native Go structures and vice versa.
https://gist.github.com/mitchellh/90029601268e59a29e64e55bab1c5bdc
MIT License
7.93k stars 677 forks source link

Proposal: add generic Unmarshaler interface #304

Open andig opened 2 years ago

andig commented 2 years ago

I've just had the requirement, to provide specific unmarshaling of some structures without modifying the unmarshaler configuration. I already have WeaklyTypedInput and DecodeHook/ComposeDecodeHookFunc.

I'd like to propose implementing an UnmarshallerHookFunc DecodeHookFunc. UnmarshallerHookFunc would be called whenever the target implements mapstructure.Unmarshaler:

type Unmarshaler interface {
    UnmarshalMapStructure(f reflect.Type, data interface{}) error
}

Here's an example usage case. ValueDefinition can be supplied as simple string or as map and both will be decoded into an ValueDefinition.

type ValueDefinition struct {
    Value string
    Scale float64
}

var _ util.MapStructureUnmarshaler = (*ValueDefinition)(nil)

func (v *ValueDefinition) UnmarshalMapStructure(f reflect.Type, data interface{}) error {
    switch f.Kind() {
    case reflect.String:
        *v = ValueDefinition{Value: data.(string)}
        return nil

    case reflect.Map:
        var cc struct {
            Value string
            Scale float64
        }

        err := util.DecodeOther(data, &cc)
        if err == nil {
            *v = ValueDefinition{
                Value: cc.Value,
                Scale: cc.Scale,
            }
        }

        return err

    default:
        return fmt.Errorf("invalid kind: %s", f.Kind())
    }
}

If that sounds interesting I'd be happy to provide a PR.

Dragomir-Ivanov commented 2 years ago

Hi @andig , you may find this project useful. https://github.com/worldline-go/struct2