Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

If interface value is not addressable, make copy and set #196

Merged
merged 1 commit into from Jun 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
29 changes: 28 additions & 1 deletion mapstructure.go
Expand Up @@ -463,7 +463,34 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e
// value to "data" of that type.
func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value) error {
if val.IsValid() && val.Elem().IsValid() {
return d.decode(name, data, val.Elem())
elem := val.Elem()

// If we can't address this element, then its not writable. Instead,
// we make a copy of the value (which is a pointer and therefore
// writable), decode into that, and replace the whole value.
copied := false
if !elem.CanAddr() {
copied = true

// Make *T
copy := reflect.New(elem.Type())

// *T = elem
copy.Elem().Set(elem)

// Set elem so we decode into it
elem = copy
}

// Decode. If we have an error then return. We also return right
// away if we're not a copy because that means we decoded directly.
if err := d.decode(name, data, elem); err != nil || !copied {
return err
}

// If we're a copy, we need to set te final result
val.Set(elem.Elem())
return nil
}

dataVal := reflect.ValueOf(data)
Expand Down
22 changes: 22 additions & 0 deletions mapstructure_test.go
Expand Up @@ -375,6 +375,28 @@ func TestBasic_interfaceStruct(t *testing.T) {
}
}

// Issue 187
func TestBasic_interfaceStructNonPtr(t *testing.T) {
t.Parallel()

input := map[string]interface{}{
"vstring": "foo",
}

var iface interface{} = Basic{}
err := Decode(input, &iface)
if err != nil {
t.Fatalf("got an err: %s", err)
}

expected := Basic{
Vstring: "foo",
}
if !reflect.DeepEqual(iface, expected) {
t.Fatalf("bad: %#v", iface)
}
}

func TestDecode_BasicSquash(t *testing.T) {
t.Parallel()

Expand Down