From 12e3d9fcc4cd1c2e97f0687646c68986d05744ff Mon Sep 17 00:00:00 2001 From: scott Date: Sat, 27 May 2023 19:14:13 -0400 Subject: [PATCH] Implement WithAlloc variants for EachListItem and ExtractList --- .../k8s.io/apimachinery/pkg/api/meta/help.go | 23 ++++++++++++++++++- .../meta/v1/unstructured/unstructured_list.go | 7 +++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/staging/src/k8s.io/apimachinery/pkg/api/meta/help.go b/staging/src/k8s.io/apimachinery/pkg/api/meta/help.go index dff943bfaee..73f160886cd 100644 --- a/staging/src/k8s.io/apimachinery/pkg/api/meta/help.go +++ b/staging/src/k8s.io/apimachinery/pkg/api/meta/help.go @@ -160,8 +160,19 @@ func eachListItem(obj runtime.Object, fn func(runtime.Object) error, allocNew bo for i := 0; i < len; i++ { raw := items.Index(i) if takeAddr { - raw = raw.Addr() + if allocNew { + // shallow copy to avoid retaining a reference to the original list item + itemCopy := reflect.New(raw.Type()) + // assign to itemCopy and type-assert + itemCopy.Elem().Set(raw) + // reflect.New will guarantee that itemCopy must be a pointer. + raw = itemCopy + } else { + raw = raw.Addr() + } } + // raw must be a pointer or an interface + // allocate a pointer is cheap switch item := raw.Interface().(type) { case *runtime.RawExtension: if err := fn(item.Object); err != nil { @@ -228,6 +239,16 @@ func extractList(obj runtime.Object, allocNew bool) ([]runtime.Object, error) { } case raw.Type().Implements(objectType): list[i] = raw.Interface().(runtime.Object) + case allocNew: + // shallow copy to avoid retaining a reference to the original list item + itemCopy := reflect.New(raw.Type()) + // assign to itemCopy and type-assert + itemCopy.Elem().Set(raw) + var ok bool + // reflect.New will guarantee that itemCopy must be a pointer. + if list[i], ok = itemCopy.Interface().(runtime.Object); !ok { + return nil, fmt.Errorf("%v: item[%v]: Expected object, got %#v(%s)", obj, i, raw.Interface(), raw.Kind()) + } default: var found bool if list[i], found = raw.Addr().Interface().(runtime.Object); !found { diff --git a/staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructured_list.go b/staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructured_list.go index 6b237d00f03..82beda2a29c 100644 --- a/staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructured_list.go +++ b/staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructured_list.go @@ -53,7 +53,12 @@ func (u *UnstructuredList) EachListItem(fn func(runtime.Object) error) error { } func (u *UnstructuredList) EachListItemWithAlloc(fn func(runtime.Object) error) error { - return u.EachListItem(fn) + for i := range u.Items { + if err := fn(&Unstructured{Object: u.Items[i].Object}); err != nil { + return err + } + } + return nil } // NewEmptyInstance returns a new instance of the concrete type containing only kind/apiVersion and no other data.