Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion arazzo/arazzo.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func Unmarshal(ctx context.Context, doc io.Reader, opts ...Option[unmarshalOptio
}

arazzo := &Arazzo{}
if err := marshaller.PopulateModel(*c, arazzo); err != nil {
if err := marshaller.Populate(*c, arazzo); err != nil {
return nil, nil, err
}

Expand Down
6 changes: 3 additions & 3 deletions arazzo/criterion/criterion.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,8 @@ func (c CriterionTypeUnion) GetVersion() CriterionTypeVersion {
return c.ExpressionType.Version
}

func (c *CriterionTypeUnion) FromCore(cr any) error {
coreCriterionTypeUnion, ok := cr.(core.CriterionTypeUnion)
func (c *CriterionTypeUnion) Populate(source any) error {
coreCriterionTypeUnion, ok := source.(core.CriterionTypeUnion)
if !ok {
return fmt.Errorf("expected core.CriterionTypeUnion, got %T", c)
}
Expand All @@ -147,7 +147,7 @@ func (c *CriterionTypeUnion) FromCore(cr any) error {
c.Type = &typ
} else if coreCriterionTypeUnion.ExpressionType != nil {
c.ExpressionType = &CriterionExpressionType{}
if err := marshaller.PopulateModel(*coreCriterionTypeUnion.ExpressionType, c.ExpressionType); err != nil {
if err := marshaller.Populate(*coreCriterionTypeUnion.ExpressionType, c.ExpressionType); err != nil {
return err
}
}
Expand Down
2 changes: 1 addition & 1 deletion extensions/extensions.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func UnmarshalExtensionModel[H any, L any](ctx context.Context, e *Extensions, e

var mV H

if err := marshaller.PopulateModel(*c, &mV); err != nil {
if err := marshaller.Populate(*c, &mV); err != nil {
return err
}
*m = mV
Expand Down
2 changes: 1 addition & 1 deletion extensions/extensions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func getTestModelWithExtensions(ctx context.Context, t *testing.T, data string)
require.NoError(t, err)

m := &ModelWithExtensions{}
err = marshaller.PopulateModel(c, m)
err = marshaller.Populate(c, m)
require.NoError(t, err)

return m
Expand Down
4 changes: 2 additions & 2 deletions marshaller/extensions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ primitiveField: hello
type TestExtensionModel struct {
marshaller.CoreModel
PrimitiveField marshaller.Node[string] `key:"primitiveField"`
Extensions marshaller.Extensions `key:"extensions"`
Extensions Extensions `key:"extensions"`
}

func Test_Extensions_SyncExtensions_Success(t *testing.T) {
Expand Down Expand Up @@ -74,7 +74,7 @@ func Test_Extensions_SyncExtensions_Success(t *testing.T) {

type TestExtensionUnmarshalError struct {
marshaller.CoreModel
Extensions marshaller.Extensions `key:"extensions"`
Extensions Extensions `key:"extensions"`
}

func Test_Extensions_UnmarshalError_Coverage(t *testing.T) {
Expand Down
69 changes: 20 additions & 49 deletions marshaller/populator.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import (
"reflect"
)

type ModelFromCore interface {
FromCore(c any) error
type Populator interface {
Populate(source any) error
}

func PopulateModel(source any, target any) error {
func Populate(source any, target any) error {
t := reflect.ValueOf(target)

if t.Kind() == reflect.Ptr && t.IsNil() {
Expand Down Expand Up @@ -125,12 +125,8 @@ func populateValue(source any, target reflect.Value) error {
target = target.Addr()
}

if value.Kind() == reflect.Ptr {
value = value.Elem()
}

if target.Type().Implements(reflect.TypeOf((*ModelFromCore)(nil)).Elem()) {
return target.Interface().(ModelFromCore).FromCore(value.Interface())
if target.Type().Implements(reflect.TypeOf((*Populator)(nil)).Elem()) {
return target.Interface().(Populator).Populate(value.Interface())
}

// Check if target implements CoreSetter interface
Expand All @@ -143,58 +139,33 @@ func populateValue(source any, target reflect.Value) error {
return nil
}

if target.Type().Implements(reflect.TypeOf((*SequencedMap)(nil)).Elem()) {
return populateSequencedMap(value, target)
}

target = target.Elem()

switch value.Kind() {
valueDerefed := value
if value.Kind() == reflect.Ptr {
valueDerefed = value.Elem()
}

switch valueDerefed.Kind() {
case reflect.Slice, reflect.Array:
if value.IsNil() {
if valueDerefed.IsNil() {
return nil
}

target.Set(reflect.MakeSlice(target.Type(), value.Len(), value.Len()))
target.Set(reflect.MakeSlice(target.Type(), valueDerefed.Len(), valueDerefed.Len()))

for i := 0; i < value.Len(); i++ {
if err := populateValue(value.Index(i).Interface(), target.Index(i)); err != nil {
for i := 0; i < valueDerefed.Len(); i++ {
if err := populateValue(valueDerefed.Index(i).Interface(), target.Index(i)); err != nil {
return err
}
}
default:
if value.Type().AssignableTo(target.Type()) {
target.Set(value)
} else if value.CanConvert(target.Type()) {
target.Set(value.Convert(target.Type()))
if valueDerefed.Type().AssignableTo(target.Type()) {
target.Set(valueDerefed)
} else if valueDerefed.CanConvert(target.Type()) {
target.Set(valueDerefed.Convert(target.Type()))
} else {
return fmt.Errorf("cannot convert %v to %v", value.Type(), target.Type())
}
}

return nil
}

func populateSequencedMap(source reflect.Value, target reflect.Value) error {
sm, ok := source.Addr().Interface().(SequencedMap)
if !ok {
return fmt.Errorf("expected source to be SequencedMap, got %s", source.Type())
}

tm, ok := target.Interface().(SequencedMap)
if !ok {
return fmt.Errorf("expected target to be SequencedMap, got %s", target.Type())
}

tm.Init()

for key, value := range sm.AllUntyped() {
targetValue := reflect.New(tm.GetValueType()).Elem()
if err := populateValue(value, targetValue); err != nil {
return err
}
if err := tm.SetUntyped(key, targetValue.Interface()); err != nil {
return err
return fmt.Errorf("cannot convert %v to %v", valueDerefed.Type(), target.Type())
}
}

Expand Down
18 changes: 9 additions & 9 deletions marshaller/populator_bare_slice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

// To trigger the slice/array case in populateValue, we need:
// 1. A target that does NOT implement ModelFromCore, CoreSetter, or SequencedMap
// 1. A target that does NOT implement Populator, CoreSetter, or SequencedMap
// 2. A source that is a slice or array
// 3. The target to be a pointer that after target.Elem() can accept the slice/array

Expand All @@ -28,15 +28,15 @@ func Test_PopulateValue_BareSliceTarget_Success(t *testing.T) {

target := &BareSliceTarget{}

err := marshaller.PopulateModel(source, target)
err := marshaller.Populate(source, target)
require.NoError(t, err)

assert.Equal(t, []string{"bare1", "bare2", "bare3"}, target.SimpleSlice)
assert.Equal(t, [3]int{10, 20, 30}, target.SimpleArray)
}

// Try with an even simpler case: directly pass slice values
// This creates a scenario where populateValue would be called recursively
// This creates a scenario where populateValue would be called recursively
// with slice source and pointer target

type ContainerWithSliceField struct {
Expand All @@ -51,7 +51,7 @@ func Test_PopulateValue_ContainerWithSlice_Success(t *testing.T) {

target := &ContainerWithSliceField{}

err := marshaller.PopulateModel(source, target)
err := marshaller.Populate(source, target)
require.NoError(t, err)

assert.Equal(t, []string{"container1", "container2"}, target.SliceField)
Expand All @@ -66,15 +66,15 @@ type PointerSliceTarget struct {
func Test_PopulateValue_PointerSliceTarget_Success(t *testing.T) {
sourceSlice := []string{"ptr1", "ptr2"}
sourceArray := [2]int{100, 200}

source := PointerSliceTarget{
SlicePtr: &sourceSlice,
ArrayPtr: &sourceArray,
}

target := &PointerSliceTarget{}

err := marshaller.PopulateModel(source, target)
err := marshaller.Populate(source, target)
require.NoError(t, err)

require.NotNil(t, target.SlicePtr)
Expand All @@ -101,7 +101,7 @@ func Test_PopulateValue_EmbeddedSliceStruct_Success(t *testing.T) {

target := &EmbeddedSliceStruct{}

err := marshaller.PopulateModel(source, target)
err := marshaller.Populate(source, target)
require.NoError(t, err)

assert.Equal(t, []string{"embedded1", "embedded2"}, target.Inner.Data)
Expand All @@ -119,8 +119,8 @@ func Test_PopulateValue_JustSlice_Success(t *testing.T) {

target := &JustSlice{}

err := marshaller.PopulateModel(source, target)
err := marshaller.Populate(source, target)
require.NoError(t, err)

assert.Equal(t, []string{"just1", "just2"}, target.Data)
}
}
20 changes: 10 additions & 10 deletions marshaller/populator_comprehensive_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func Test_PopulateModel_SimpleStructToStruct(t *testing.T) {

target := &Target{}

err := marshaller.PopulateModel(source, target)
err := marshaller.Populate(source, target)
require.NoError(t, err)
assert.Equal(t, "test", target.StringField)
assert.Equal(t, 42, target.IntField)
Expand All @@ -49,7 +49,7 @@ func Test_PopulateModel_WithSlices(t *testing.T) {

target := &Target{}

err := marshaller.PopulateModel(source, target)
err := marshaller.Populate(source, target)
require.NoError(t, err)
assert.Equal(t, []string{"a", "b", "c"}, target.SliceField)
}
Expand All @@ -70,7 +70,7 @@ func Test_PopulateModel_WithNilSlice(t *testing.T) {

target := &Target{}

err := marshaller.PopulateModel(source, target)
err := marshaller.Populate(source, target)
require.NoError(t, err)
assert.Nil(t, target.SliceField)
}
Expand All @@ -91,7 +91,7 @@ func Test_PopulateModel_TypeConversion(t *testing.T) {

target := &Target{}

err := marshaller.PopulateModel(source, target)
err := marshaller.Populate(source, target)
// This might fail due to type incompatibility - that's expected
if err != nil {
assert.Contains(t, err.Error(), "cannot convert")
Expand All @@ -117,7 +117,7 @@ func Test_PopulateModel_WithPointers(t *testing.T) {

target := &Target{}

err := marshaller.PopulateModel(source, target)
err := marshaller.Populate(source, target)
require.NoError(t, err)
require.NotNil(t, target.PtrField)
assert.Equal(t, "test-value", *target.PtrField)
Expand All @@ -139,7 +139,7 @@ func Test_PopulateModel_WithNilPointer(t *testing.T) {

target := &Target{}

err := marshaller.PopulateModel(source, target)
err := marshaller.Populate(source, target)
require.NoError(t, err)
assert.Nil(t, target.PtrField)
}
Expand All @@ -153,7 +153,7 @@ func Test_PopulateModel_NonStructSource_Error(t *testing.T) {
source := "not-a-struct"
target := &Target{}

err := marshaller.PopulateModel(source, target)
err := marshaller.Populate(source, target)
require.Error(t, err)
assert.Contains(t, err.Error(), "cannot convert")
}
Expand All @@ -174,7 +174,7 @@ func Test_PopulateModel_IncompatibleTypes_Error(t *testing.T) {

target := &Target{}

err := marshaller.PopulateModel(source, target)
err := marshaller.Populate(source, target)
require.Error(t, err)
assert.Contains(t, err.Error(), "cannot convert")
}
Expand Down Expand Up @@ -202,9 +202,9 @@ func Test_PopulateModel_NestedSlices(t *testing.T) {

target := &Target{}

err := marshaller.PopulateModel(source, target)
err := marshaller.Populate(source, target)
require.NoError(t, err)
require.Len(t, target.NestedSlice, 2)
assert.Equal(t, "first", target.NestedSlice[0].Value)
assert.Equal(t, "second", target.NestedSlice[1].Value)
}
}
Loading