debug: Expose list of components to frontend
This commit is contained in:
parent
e17ab90269
commit
e5cd57cb7d
14 changed files with 307 additions and 14 deletions
27
internal/dis/component/control/info/components.go
Normal file
27
internal/dis/component/control/info/components.go
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
package info
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/control/static"
|
||||||
|
"github.com/FAU-CDI/wisski-distillery/pkg/lazy"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed "html/components.html"
|
||||||
|
var componentsTemplateString string
|
||||||
|
var componentsTemplate = static.AssetsComponentsIndex.MustParse(componentsTemplateString)
|
||||||
|
|
||||||
|
type componentsPageContext struct {
|
||||||
|
Time time.Time
|
||||||
|
|
||||||
|
Analytics lazy.PoolAnalytics
|
||||||
|
}
|
||||||
|
|
||||||
|
func (info *Info) componentsPageAPI(r *http.Request) (cp componentsPageContext, err error) {
|
||||||
|
cp.Analytics = *info.Analytics
|
||||||
|
cp.Time = time.Now().UTC()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
143
internal/dis/component/control/info/html/components.html
Normal file
143
internal/dis/component/control/info/html/components.html
Normal file
|
|
@ -0,0 +1,143 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Distillery Control Page - Components Page</title>
|
||||||
|
{{ CSS }}
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<h1 id="top">Distillery Control Page - Components Page</h1>
|
||||||
|
<small>Generated at <code class="date">{{ .Time.Format "2006-01-02T15:04:05Z07:00" }}</code></small>
|
||||||
|
<p>
|
||||||
|
<a class="pure-button" href="/dis/index">Control</a> >
|
||||||
|
<a class="pure-button pure-button-primary" href="/dis/components">Components</a>
|
||||||
|
</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<div class="pure-g">
|
||||||
|
<div class="pure-u-1-1">
|
||||||
|
<h2 id="components">Components</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ range $name, $comp := .Analytics.Components }}
|
||||||
|
<div class="pure-u-1-1" id="{{ $name }}">
|
||||||
|
<div class="padding">
|
||||||
|
|
||||||
|
<div class="overflow">
|
||||||
|
<table class="pure-table pure-table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th colspan="3">
|
||||||
|
{{ $name }}
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{ range .Groups }}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
Implements
|
||||||
|
</td>
|
||||||
|
<td colspan="2">
|
||||||
|
<code><a href="#{{.}}">{{ . }}</a></code><br />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{ end }}
|
||||||
|
{{ range $name, $comp := .CFields }}
|
||||||
|
<tr>
|
||||||
|
<td>Component Pointer</td>
|
||||||
|
<td>
|
||||||
|
<code>{{ $name }}</code>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<code><a href="#{{ $comp }}">{{ $comp }}</a></code>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{ end }}
|
||||||
|
{{ range $name, $iface := .IFields }}
|
||||||
|
<tr>
|
||||||
|
<td>Interface Slice</td>
|
||||||
|
<td>
|
||||||
|
<code>{{ $name }}</code>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<code><a href="#{{ $iface }}">[]{{ $iface }}</a></code>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{ end }}
|
||||||
|
{{ range $name, $sig := $comp.Methods }}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
Method
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<code>{{ $name }}</code>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<code>{{ $sig }}</code>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{ end }}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<div class="pure-u-1-1">
|
||||||
|
<h2 id="interfaces">Interfaces</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ range $name, $group := .Analytics.Groups }}
|
||||||
|
<div class="pure-u-1-1" id="{{ $name }}">
|
||||||
|
<div class="padding">
|
||||||
|
|
||||||
|
<div class="overflow">
|
||||||
|
<table class="pure-table pure-table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th colspan="3">
|
||||||
|
{{ $name }}
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{ range $name, $sig := $group.Methods }}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
Method
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<code>{{ $name }}</code>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<code>{{ $sig }}</code>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{ end }}
|
||||||
|
{{ range $group.Components }}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
Implemented By
|
||||||
|
</td>
|
||||||
|
<td colspan="2">
|
||||||
|
<code><a href="#{{.}}">{{ . }}</a></code>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{ end }}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
</main>
|
||||||
|
|
||||||
|
{{ JS }}
|
||||||
|
</body>
|
||||||
|
|
@ -13,6 +13,9 @@
|
||||||
<p>
|
<p>
|
||||||
<a class="pure-button pure-button-primary" href="/dis/index">Control</a>
|
<a class="pure-button pure-button-primary" href="/dis/index">Control</a>
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
<a class="pure-button" href="/dis/components">Components</a>
|
||||||
|
</p>
|
||||||
</header>
|
</header>
|
||||||
<main>
|
<main>
|
||||||
<div class="pure-g">
|
<div class="pure-g">
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,15 @@ import (
|
||||||
|
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/instances"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/instances"
|
||||||
"github.com/FAU-CDI/wisski-distillery/pkg/httpx"
|
"github.com/FAU-CDI/wisski-distillery/pkg/httpx"
|
||||||
|
"github.com/FAU-CDI/wisski-distillery/pkg/lazy"
|
||||||
"github.com/tkw1536/goprogram/stream"
|
"github.com/tkw1536/goprogram/stream"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Info struct {
|
type Info struct {
|
||||||
component.Base
|
component.Base
|
||||||
|
|
||||||
|
Analytics *lazy.PoolAnalytics
|
||||||
|
|
||||||
Exporter *exporter.Exporter
|
Exporter *exporter.Exporter
|
||||||
Instances *instances.Instances
|
Instances *instances.Instances
|
||||||
SnapshotsLog *logger.Logger
|
SnapshotsLog *logger.Logger
|
||||||
|
|
@ -41,6 +44,12 @@ func (info *Info) Handler(route string, context context.Context, io stream.IOStr
|
||||||
Template: indexTemplate,
|
Template: indexTemplate,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// add a handler for the component page
|
||||||
|
mux.Handle(route+"components", httpx.HTMLHandler[componentsPageContext]{
|
||||||
|
Handler: info.componentsPageAPI,
|
||||||
|
Template: componentsTemplate,
|
||||||
|
})
|
||||||
|
|
||||||
// add a handler for the instance page
|
// add a handler for the instance page
|
||||||
mux.Handle(route+"instance/", httpx.HTMLHandler[instancePageContext]{
|
mux.Handle(route+"instance/", httpx.HTMLHandler[instancePageContext]{
|
||||||
Handler: info.instancePageAPI,
|
Handler: info.instancePageAPI,
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ type Assets struct {
|
||||||
Styles string // <link> tags inserted by the asset
|
Styles string // <link> tags inserted by the asset
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:generate node build.mjs HomeHome ControlIndex ControlInstance
|
//go:generate node build.mjs HomeHome ComponentsIndex ControlIndex ControlInstance
|
||||||
|
|
||||||
// MustParse parses a new template from the given source
|
// MustParse parses a new template from the given source
|
||||||
// and registers the Asset functions to it.
|
// and registers the Asset functions to it.
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,12 @@ var AssetsHomeHome = Assets{
|
||||||
Styles: `<link rel="stylesheet" href="/static/HomeHome.a75f04fa.css"><link rel="stylesheet" href="/static/HomeHome.38d394c2.css">`,
|
Styles: `<link rel="stylesheet" href="/static/HomeHome.a75f04fa.css"><link rel="stylesheet" href="/static/HomeHome.38d394c2.css">`,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AssetsComponentsIndex contains assets for the 'ComponentsIndex' entrypoint.
|
||||||
|
var AssetsComponentsIndex = Assets{
|
||||||
|
Scripts: `<script type="module" src="/static/HomeHome.38d394c2.js"></script><script src="/static/HomeHome.38d394c2.js" nomodule="" defer></script><script type="module" src="/static/ComponentsIndex.38d394c2.js"></script><script src="/static/ComponentsIndex.38d394c2.js" nomodule="" defer></script>`,
|
||||||
|
Styles: `<link rel="stylesheet" href="/static/HomeHome.a75f04fa.css"><link rel="stylesheet" href="/static/ComponentsIndex.38d394c2.css">`,
|
||||||
|
}
|
||||||
|
|
||||||
// AssetsControlIndex contains assets for the 'ControlIndex' entrypoint.
|
// AssetsControlIndex contains assets for the 'ControlIndex' entrypoint.
|
||||||
var AssetsControlIndex = Assets{
|
var AssetsControlIndex = Assets{
|
||||||
Scripts: `<script type="module" src="/static/HomeHome.38d394c2.js"></script><script src="/static/HomeHome.38d394c2.js" nomodule="" defer></script><script type="module" src="/static/ControlIndex.cfbf936d.js"></script><script src="/static/ControlIndex.613b02c2.js" nomodule="" defer></script>`,
|
Scripts: `<script type="module" src="/static/HomeHome.38d394c2.js"></script><script src="/static/HomeHome.38d394c2.js" nomodule="" defer></script><script type="module" src="/static/ControlIndex.cfbf936d.js"></script><script src="/static/ControlIndex.613b02c2.js" nomodule="" defer></script>`,
|
||||||
|
|
|
||||||
0
internal/dis/component/control/static/dist/ComponentsIndex.38d394c2.css
vendored
Normal file
0
internal/dis/component/control/static/dist/ComponentsIndex.38d394c2.css
vendored
Normal file
0
internal/dis/component/control/static/dist/ComponentsIndex.38d394c2.js
vendored
Normal file
0
internal/dis/component/control/static/dist/ComponentsIndex.38d394c2.js
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
// nothing for now
|
||||||
|
|
@ -137,6 +137,8 @@ func (dis *Distillery) allComponents() []initFunc {
|
||||||
manual(func(resolver *resolver.Resolver) {
|
manual(func(resolver *resolver.Resolver) {
|
||||||
resolver.RefreshInterval = time.Minute
|
resolver.RefreshInterval = time.Minute
|
||||||
}),
|
}),
|
||||||
auto[*info.Info],
|
manual(func(info *info.Info) {
|
||||||
|
info.Analytics = &dis.pool.Analytics
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ package lazy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Pool represents a pool of laziliy initialized and potentially referencing Component instances.
|
// Pool represents a pool of laziliy initialized and potentially referencing Component instances.
|
||||||
|
|
@ -19,6 +18,9 @@ type Pool[Component any, InitParams any] struct {
|
||||||
// Init is called on every component to be initialized.
|
// Init is called on every component to be initialized.
|
||||||
Init func(Component, InitParams) Component
|
Init func(Component, InitParams) Component
|
||||||
|
|
||||||
|
// Analytics are written on the first retrieval operation on this Pool
|
||||||
|
Analytics PoolAnalytics
|
||||||
|
|
||||||
all Lazy[[]Component]
|
all Lazy[[]Component]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -37,12 +39,16 @@ func (p *Pool[Component, InitParams]) All(Params InitParams, All func(context *P
|
||||||
}
|
}
|
||||||
return p.Init(c, Params)
|
return p.Init(c, Params)
|
||||||
},
|
},
|
||||||
cache: make(map[string]Component),
|
metaCache: make(map[reflect.Type]meta[Component]),
|
||||||
|
cache: make(map[string]Component),
|
||||||
}
|
}
|
||||||
|
|
||||||
// and process them all
|
// and process them all
|
||||||
all := context.all(context)
|
all := context.all(context)
|
||||||
context.Process(all)
|
context.process(all)
|
||||||
|
|
||||||
|
// write out analytics
|
||||||
|
context.anal(&p.Analytics)
|
||||||
return all
|
return all
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -56,7 +62,7 @@ type PoolContext[Component any] struct {
|
||||||
|
|
||||||
// function to return all components
|
// function to return all components
|
||||||
|
|
||||||
metaCache sync.Map // Map[string]meta[Component]
|
metaCache map[reflect.Type]meta[Component]
|
||||||
cache map[string]Component // cached components
|
cache map[string]Component // cached components
|
||||||
queue []delayedInit[Component] // init queue
|
queue []delayedInit[Component] // init queue
|
||||||
}
|
}
|
||||||
|
|
@ -67,7 +73,7 @@ type delayedInit[Component any] struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process processes all components in the queue
|
// Process processes all components in the queue
|
||||||
func (p *PoolContext[Component]) Process(all []Component) {
|
func (p *PoolContext[Component]) process(all []Component) {
|
||||||
index := 0
|
index := 0
|
||||||
for len(p.queue) > index {
|
for len(p.queue) > index {
|
||||||
p.queue[index].Run(all)
|
p.queue[index].Run(all)
|
||||||
|
|
@ -97,7 +103,7 @@ func (di *delayedInit[Component]) Run(all []Component) {
|
||||||
// The init function may be nil, indicating that no additional initialization is required.
|
// The init function may be nil, indicating that no additional initialization is required.
|
||||||
func Make[Component any, ConcreteComponent any](context *PoolContext[Component], init func(component ConcreteComponent)) ConcreteComponent {
|
func Make[Component any, ConcreteComponent any](context *PoolContext[Component], init func(component ConcreteComponent)) ConcreteComponent {
|
||||||
// get a description of the type
|
// get a description of the type
|
||||||
cd := getMeta[Component, ConcreteComponent](&context.metaCache)
|
cd := getMeta[Component, ConcreteComponent](context.metaCache)
|
||||||
|
|
||||||
// if an instance already exists, return it!
|
// if an instance already exists, return it!
|
||||||
if instance, ok := context.cache[cd.Name]; ok {
|
if instance, ok := context.cache[cd.Name]; ok {
|
||||||
|
|
|
||||||
93
pkg/lazy/pool_anal.go
Normal file
93
pkg/lazy/pool_anal.go
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
package lazy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/tkw1536/goprogram/lib/collection"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PoolAnalytics struct {
|
||||||
|
Components map[string]*PoolAnalyticsComponent
|
||||||
|
Groups map[string]*PoolAnalyticsGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
type PoolAnalyticsComponent struct {
|
||||||
|
Type string // Type name
|
||||||
|
Groups []string // groups this is contained in
|
||||||
|
|
||||||
|
CFields map[string]string // fields with type C for which C implements component
|
||||||
|
IFields map[string]string // fields []I where I is an interface that implements component
|
||||||
|
|
||||||
|
Methods map[string]string // Method signatures of type
|
||||||
|
}
|
||||||
|
type PoolAnalyticsGroup struct {
|
||||||
|
Type string // Type name
|
||||||
|
Components []string // Components of this Type
|
||||||
|
|
||||||
|
Methods map[string]string // Method signatures of this interface
|
||||||
|
}
|
||||||
|
|
||||||
|
// anal writes analytics about this context to anal
|
||||||
|
func (context *PoolContext[Component]) anal(anal *PoolAnalytics) {
|
||||||
|
anal.Components = make(map[string]*PoolAnalyticsComponent, len(context.metaCache))
|
||||||
|
anal.Groups = make(map[string]*PoolAnalyticsGroup)
|
||||||
|
|
||||||
|
// collect all the pointers, and setup the anal.Components map!
|
||||||
|
tpPointers := make([]reflect.Type, 0, len(context.metaCache))
|
||||||
|
for _, meta := range context.metaCache {
|
||||||
|
tp := reflect.PointerTo(meta.Elem)
|
||||||
|
tpPointers = append(tpPointers, tp)
|
||||||
|
|
||||||
|
mcount := tp.NumMethod()
|
||||||
|
|
||||||
|
anal.Components[meta.Name] = &PoolAnalyticsComponent{
|
||||||
|
Groups: make([]string, 0),
|
||||||
|
Methods: make(map[string]string, mcount),
|
||||||
|
}
|
||||||
|
for i := 0; i < mcount; i++ {
|
||||||
|
method := tp.Method(i)
|
||||||
|
anal.Components[meta.Name].Methods[method.Name] = method.Type.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// take all of the components out of the cache
|
||||||
|
for _, meta := range context.metaCache {
|
||||||
|
anal.Components[meta.Name].Type = meta.Name
|
||||||
|
anal.Components[meta.Name].CFields = collection.MapValues(meta.CFields, func(key string, tp reflect.Type) string {
|
||||||
|
return nameOf(tp.Elem())
|
||||||
|
})
|
||||||
|
|
||||||
|
anal.Components[meta.Name].IFields = collection.MapValues(meta.IFields, func(key string, iface reflect.Type) string {
|
||||||
|
name := nameOf(iface)
|
||||||
|
|
||||||
|
if _, ok := anal.Groups[name]; !ok {
|
||||||
|
types := collection.FilterClone(tpPointers, func(tp reflect.Type) bool {
|
||||||
|
return tp.AssignableTo(iface)
|
||||||
|
})
|
||||||
|
|
||||||
|
anal.Groups[name] = &PoolAnalyticsGroup{
|
||||||
|
Type: name,
|
||||||
|
Components: collection.MapSlice(types, func(tp reflect.Type) string {
|
||||||
|
cname := nameOf(tp.Elem())
|
||||||
|
anal.Components[cname].Groups = append(anal.Components[cname].Groups, name)
|
||||||
|
return cname
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
mcount := iface.NumMethod()
|
||||||
|
anal.Groups[name].Methods = make(map[string]string, mcount)
|
||||||
|
for i := 0; i < mcount; i++ {
|
||||||
|
method := iface.Method(i)
|
||||||
|
anal.Groups[name].Methods[method.Name] = method.Type.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return name
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, comp := range anal.Components {
|
||||||
|
slices.Sort(comp.Groups)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,19 +2,18 @@ package lazy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/tkw1536/goprogram/lib/collection"
|
"github.com/tkw1536/goprogram/lib/collection"
|
||||||
"github.com/tkw1536/goprogram/lib/reflectx"
|
"github.com/tkw1536/goprogram/lib/reflectx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// getMeta gets the component belonging to a component type
|
// getMeta gets the component belonging to a component type
|
||||||
func getMeta[Component any, ConcreteComponent any](metaCache *sync.Map) meta[Component] {
|
func getMeta[Component any, ConcreteComponent any](cache map[reflect.Type]meta[Component]) meta[Component] {
|
||||||
tp := reflectx.TypeOf[ConcreteComponent]()
|
tp := reflectx.TypeOf[ConcreteComponent]()
|
||||||
|
|
||||||
// we already have a m => return it
|
// we already have a m => return it
|
||||||
if m, ok := metaCache.Load(tp); ok {
|
if m, ok := cache[tp]; ok {
|
||||||
return m.(meta[Component])
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a new m
|
// create a new m
|
||||||
|
|
@ -22,7 +21,7 @@ func getMeta[Component any, ConcreteComponent any](metaCache *sync.Map) meta[Com
|
||||||
m.init(tp)
|
m.init(tp)
|
||||||
|
|
||||||
// store it in the cache
|
// store it in the cache
|
||||||
metaCache.Store(tp, m)
|
cache[tp] = m
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -43,8 +42,8 @@ func (m *meta[Component]) init(tp reflect.Type) {
|
||||||
panic("GetMeta: Type (" + tp.String() + ") must be backed by a pointer to slice")
|
panic("GetMeta: Type (" + tp.String() + ") must be backed by a pointer to slice")
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Name = tp.Elem().PkgPath() + "." + tp.Elem().Name()
|
|
||||||
m.Elem = tp.Elem()
|
m.Elem = tp.Elem()
|
||||||
|
m.Name = nameOf(m.Elem)
|
||||||
|
|
||||||
m.CFields = make(map[string]reflect.Type)
|
m.CFields = make(map[string]reflect.Type)
|
||||||
m.IFields = make(map[string]reflect.Type)
|
m.IFields = make(map[string]reflect.Type)
|
||||||
|
|
@ -69,6 +68,10 @@ func (m *meta[Component]) init(tp reflect.Type) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func nameOf(tp reflect.Type) string {
|
||||||
|
return tp.PkgPath() + "." + tp.Name()
|
||||||
|
}
|
||||||
|
|
||||||
// New creates a new ComponentDescription
|
// New creates a new ComponentDescription
|
||||||
func (m meta[Component]) New() Component {
|
func (m meta[Component]) New() Component {
|
||||||
return reflect.New(m.Elem).Interface().(Component)
|
return reflect.New(m.Elem).Interface().(Component)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue