internal/component: Move Pool into lazy package

This commit is contained in:
Tom Wiesing 2022-10-17 13:08:42 +02:00
parent bcfd0765b0
commit 7c3c84e116
No known key found for this signature in database
8 changed files with 261 additions and 139 deletions

View file

@ -1,65 +1,34 @@
package component
import (
"reflect"
"sync"
"github.com/FAU-CDI/wisski-distillery/pkg/lazy"
)
// Pool holds a pool of components and provides factilities to create and access them.
// See [Pool.All], [ExportComponents] and [ExportComponent].
type Pool struct {
all lazy.Lazy[[]Component] // all components
type ComponentPool struct {
pool lazy.Pool[Component, Core]
poolInit sync.Once
}
// All initializes or returns all components stored in this pool.
//
// The All function should return an array of calls to [Make] with the provided context.
// Multiple calls to the this method return the same return value.
func (p *Pool) All(All func(context *PoolContext) []Component) []Component {
return p.all.Get(func() []Component {
// create a new context
context := &PoolContext{
all: All,
cache: make(map[string]Component),
func (pool *ComponentPool) init() {
pool.poolInit.Do(func() {
pool.pool.Init = func(component Component, core Core) Component {
component.getBase().Core = core
return component
}
// and process them all
all := context.all(context)
context.process(all)
return all
})
}
// PoolContext is a context used during [Make].
// It should not be initialized by a user.
type PoolContext struct {
all func(context *PoolContext) []Component // function to return all components
type ComponentPoolContext = *lazy.PoolContext[Component]
type ComponentAllFunc = func(context ComponentPoolContext) []Component
cache map[string]Component // cached components
queue []delayedInit // init queue
func (pool *ComponentPool) All(core Core, init func(context ComponentPoolContext) []Component) []Component {
pool.init()
return pool.pool.All(core, init)
}
type delayedInit struct {
meta meta
value reflect.Value
}
func (di delayedInit) Do(all []Component) {
di.meta.InitComponent(di.value, all)
}
// process processes the queue in this process
func (p *PoolContext) process(all []Component) {
index := 0
for len(p.queue) > index {
p.queue[index].Do(all)
index++
}
p.queue = nil
}
// Make creates or returns a cached component of the given Context.
// MakeComponent creates or returns a cached component of the given Context.
//
// Components are initialized by first calling the init function.
// Then all component-like fields of fields are filled with their appropriate components.
@ -74,74 +43,24 @@ func (p *PoolContext) process(all []Component) {
// Furthermore, the init function may not cause other components to be initialized.
//
// The init function may be nil, indicating that no additional initialization is required.
func Make[C Component](context *PoolContext, core Core, init func(component C)) C {
// get a description of the type
cd := getMeta[C]()
// if an instance already exists, return it!
if instance, ok := context.cache[cd.Name]; ok {
return instance.(C)
}
// make sure that we have an array of components
if context.cache == nil {
context.cache = make(map[string]Component)
}
// create a fresh (empty) instance
context.cache[cd.Name] = cd.New()
instance := context.cache[cd.Name].(C)
// do the core and self-initialization
instance.getBase().Core = core
if init != nil {
init(instance)
}
if cd.NeedsInitComponent() {
context.queue = append(context.queue, delayedInit{
meta: cd,
value: reflect.ValueOf(instance),
})
}
return instance
func MakeComponent[C Component](context ComponentPoolContext, core Core, init func(component C)) C {
return lazy.Make(context, init)
}
//
// PUBLIC FUNCTIONS
//
// ExportComponents exports all components that are a C from the pool.
//
// All should be the function of the core that initializes all components.
// All should only make calls to [InitComponent].
func ExportComponents[C Component](p *Pool, All func(context *PoolContext) []Component) []C {
components := p.All(All)
results := make([]C, 0, len(components))
for _, comp := range components {
if cc, ok := comp.(C); ok {
results = append(results, cc)
}
}
return results
func ExportComponents[C Component](pool *ComponentPool, core Core, All ComponentAllFunc) []C {
pool.init()
return lazy.ExportComponents[Component, Core, C](&pool.pool, core, All)
}
// ExportComponent exports the first component that is a C from the pool.
//
// All should be the function of the core that initializes all components.
// All should only make calls to [InitComponent].
func ExportComponent[C Component](p *Pool, All func(context *PoolContext) []Component) C {
components := p.All(All)
for _, comp := range components {
if cc, ok := comp.(C); ok {
return cc
}
}
var c C
return c
func ExportComponent[C Component](pool *ComponentPool, core Core, All ComponentAllFunc) C {
pool.init()
return lazy.ExportComponent[Component, Core, C](&pool.pool, core, All)
}