mapstructure icon indicating copy to clipboard operation
mapstructure copied to clipboard

Proposal: add generic Unmarshaler interface

Open andig opened this issue 3 years ago • 1 comments

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.

andig avatar Sep 02 '22 12:09 andig

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

Dragomir-Ivanov avatar Sep 02 '22 12:09 Dragomir-Ivanov