Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion bson/default_value_decoders.go
Original file line number Diff line number Diff line change
Expand Up @@ -1351,14 +1351,17 @@ func decodeDefault(dc DecodeContext, vr ValueReader, val reflect.Value) ([]refle
}

var elem reflect.Value
if vDecoder == nil {
if vDecoder == nil && idx < val.Len() {
elem = val.Index(idx).Elem()
switch {
case elem.Kind() != reflect.Ptr || elem.IsNil():
valueDecoder, err := dc.LookupDecoder(elem.Type())
if err != nil {
return nil, err
}
if !elem.CanSet() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is really nuanced. Can we add a comment here noting why we do this? "If an element is unsettable and allocated, it must be overwritten."

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also suggest making the following changes to make this more readable:

isInterfaceSlice := eType.Kind() == reflect.Interface && val.Len() > 0

// If this is not an interface slice with pre-populated elements, we can look
// up the decoder for eType once.
var vDecoder ValueDecoder
if !isInterfaceSlice {
	vDecoder, err = dc.LookupDecoder(eType)
	if err != nil {
		return nil, err
	}
}

for {
	// ...
	if isInterfaceSlice && idx < val.Len() {
		// Decode into an existing interface{} slot.
		
		// ...
	} else {
		// For non-interface slices, or if we've exhuasted the pre-populated
		// slots, we create a fresh value.
		if vDecoder == nil {
			// ...
		}

		//...
	}
}

elem = reflect.New(elem.Type()).Elem()
}
err = valueDecoder.DecodeValue(dc, vr, elem)
if err != nil {
return nil, newDecodeError(strconv.Itoa(idx), err)
Expand All @@ -1380,6 +1383,12 @@ func decodeDefault(dc DecodeContext, vr ValueReader, val reflect.Value) ([]refle
}
}
} else {
if vDecoder == nil {
vDecoder, err = dc.LookupDecoder(eType)
if err != nil {
return nil, err
}
}
elem, err = decodeTypeOrValueWithInfo(vDecoder, dc, vr, eType)
if err != nil {
return nil, newDecodeError(strconv.Itoa(idx), err)
Expand Down
Loading