engine: autogroup, traits, graph: Extend autogroup API

This extends the autogrouping API so that a child can easily get a
reference to the parent that it is autogrouped in. This can simplify the
API for some resources when it makes sense to allow them access to the
parent handle. Use sparingly and intelligently!
This commit is contained in:
James Shubin
2024-03-20 17:37:45 -04:00
parent 6347e275d3
commit 8a78907977
5 changed files with 29 additions and 4 deletions

View File

@@ -54,7 +54,8 @@ type GroupableRes interface {
// grouping. This usually needs to be unique to your resource. // grouping. This usually needs to be unique to your resource.
GroupCmp(res GroupableRes) error GroupCmp(res GroupableRes) error
// GroupRes groups resource argument (res) into self. // GroupRes groups resource argument (res) into self. Callers of this
// method should probably also run SetParent.
GroupRes(res GroupableRes) error GroupRes(res GroupableRes) error
// IsGrouped determines if we are grouped. // IsGrouped determines if we are grouped.
@@ -66,8 +67,15 @@ type GroupableRes interface {
// GetGroup returns everyone grouped inside me. // GetGroup returns everyone grouped inside me.
GetGroup() []GroupableRes // return everyone grouped inside me GetGroup() []GroupableRes // return everyone grouped inside me
// SetGroup sets the grouped resources into me. // SetGroup sets the grouped resources into me. Callers of this method
// should probably also run SetParent.
SetGroup([]GroupableRes) SetGroup([]GroupableRes)
// Parent returns the parent groupable resource that I am inside of.
Parent() GroupableRes
// SetParent tells a particular grouped resource who their parent is.
SetParent(res GroupableRes)
} }
// AutoGroupMeta provides some parameters specific to automatic grouping. // AutoGroupMeta provides some parameters specific to automatic grouping.

View File

@@ -93,6 +93,7 @@ func ResCopy(r CopyableRes) (CopyableRes, error) {
if !ok { if !ok {
return nil, fmt.Errorf("resource wasn't groupable") return nil, fmt.Errorf("resource wasn't groupable")
} }
g2.SetParent(dst) // store who my parent is
grouped = append(grouped, g2) grouped = append(grouped, g2)
} }
dst.SetGroup(grouped) dst.SetGroup(grouped)

View File

@@ -121,6 +121,7 @@ func (obj *wrappedGrouper) VertexMerge(v1, v2 pgraph.Vertex) (v pgraph.Vertex, e
if err = r1.GroupRes(r2); err != nil { // GroupRes skips stupid groupings if err = r1.GroupRes(r2); err != nil { // GroupRes skips stupid groupings
return // return early on error return // return early on error
} }
r2.SetParent(r1) // store who my parent is
// merging two resources into one should yield the sum of their semas // merging two resources into one should yield the sum of their semas
if semas := r2.MetaParams().Sema; len(semas) > 0 { if semas := r2.MetaParams().Sema; len(semas) > 0 {

View File

@@ -202,6 +202,8 @@ func (obj *testGrouper) VertexMerge(v1, v2 pgraph.Vertex) (v pgraph.Vertex, err
if err := r1.GroupRes(r2); err != nil { // group them first if err := r1.GroupRes(r2); err != nil { // group them first
return nil, err return nil, err
} }
r2.SetParent(r1) // store who my parent is
// HACK: update the name so it matches full list of self+grouped // HACK: update the name so it matches full list of self+grouped
res := v1.(engine.GroupableRes) res := v1.(engine.GroupableRes)
names := strings.Split(res.Name(), ",") // load in stored names names := strings.Split(res.Name(), ",") // load in stored names

View File

@@ -45,6 +45,7 @@ type Groupable struct {
isGrouped bool // am i contained within a group? isGrouped bool // am i contained within a group?
grouped []engine.GroupableRes // list of any grouped resources grouped []engine.GroupableRes // list of any grouped resources
parent engine.GroupableRes // resource i am grouped inside of
// Bug5819 works around issue https://github.com/golang/go/issues/5819 // Bug5819 works around issue https://github.com/golang/go/issues/5819
Bug5819 interface{} // XXX: workaround Bug5819 interface{} // XXX: workaround
@@ -74,7 +75,8 @@ func (obj *Groupable) GroupCmp(res engine.GroupableRes) error {
return fmt.Errorf("the default grouping compare is not nil") return fmt.Errorf("the default grouping compare is not nil")
} }
// GroupRes groups resource argument (res) into self. // GroupRes groups resource argument (res) into self. Callers of this method
// should probably also run SetParent.
func (obj *Groupable) GroupRes(res engine.GroupableRes) error { func (obj *Groupable) GroupRes(res engine.GroupableRes) error {
if l := len(res.GetGroup()); l > 0 { if l := len(res.GetGroup()); l > 0 {
return fmt.Errorf("the `%s` resource already contains %d grouped resources", res, l) return fmt.Errorf("the `%s` resource already contains %d grouped resources", res, l)
@@ -103,7 +105,18 @@ func (obj *Groupable) GetGroup() []engine.GroupableRes {
return obj.grouped return obj.grouped
} }
// SetGroup sets the grouped resources into me. // SetGroup sets the grouped resources into me. Callers of this method should
// probably also run SetParent.
func (obj *Groupable) SetGroup(grouped []engine.GroupableRes) { func (obj *Groupable) SetGroup(grouped []engine.GroupableRes) {
obj.grouped = grouped obj.grouped = grouped
} }
// Parent returns the parent groupable resource that I am inside of.
func (obj *Groupable) Parent() engine.GroupableRes {
return obj.parent
}
// SetParent tells a particular grouped resource who their parent is.
func (obj *Groupable) SetParent(res engine.GroupableRes) {
obj.parent = res
}