From 628f91ffc4c5682fed2d354bcaf5070f3bdb6284 Mon Sep 17 00:00:00 2001 From: Mathijs van den Worm Date: Fri, 20 May 2022 13:39:34 +0200 Subject: [PATCH] Allow types to determine how to decode themselves --- mapstructure.go | 11 +++++++++++ mapstructure_examples_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/mapstructure.go b/mapstructure.go index 7581806a..6244568a 100644 --- a/mapstructure.go +++ b/mapstructure.go @@ -453,6 +453,13 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e return nil } + if outVal.CanAddr() { + v := outVal.Addr() + if u, ok := v.Interface().(decoder); ok { + return u.Decode(input) + } + } + if d.config.DecodeHook != nil { // We have a DecodeHook, so let's pre-process the input. var err error @@ -1540,3 +1547,7 @@ func dereferencePtrToStructIfNeeded(v reflect.Value, tagName string) reflect.Val } return v } + +type decoder interface { + Decode(interface{}) error +} diff --git a/mapstructure_examples_test.go b/mapstructure_examples_test.go index 2413b694..5541bc47 100644 --- a/mapstructure_examples_test.go +++ b/mapstructure_examples_test.go @@ -254,3 +254,32 @@ func ExampleDecode_omitempty() { // Output: // &map[Age:0 FirstName:Somebody] } + +type Someone struct { + Name string +} + +func (p *Someone) Decode(v interface{}) error { + if name, ok := v.(string); ok { + p.Name = name + return nil + } + return fmt.Errorf("undecipherable name") +} + +func ExampleDecode_custom_decoder_type() { + type Profile struct { + Friends []Someone + } + input := map[string]interface{}{ + "friends": []string{"Mitchell"}, + } + var result Profile + err := Decode(input, &result) + if err != nil { + panic(err) + } + fmt.Printf("%#v", result) + // Output: + // mapstructure.Profile{Friends:[]mapstructure.Someone{mapstructure.Someone{Name:"Mitchell"}}} +}