Skip to content
Open
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
127 changes: 90 additions & 37 deletions container.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,41 +57,9 @@ func New() Container {
}
}

// Connect a component, optionally identified by id.
func (container Container) Connect(val interface{}, id ...string) {
ptr := false
rv := reflect.ValueOf(val)
rt := rv.Type()
nam := ""
_, file, no, _ := runtime.Caller(container.callerSkip + 1)

if len(id) > 0 {
nam = id[0]
}

comp := component{
id: nam,
value: rv,
declaredAt: file + ":" + strconv.Itoa(no),
}

if rt.Kind() == reflect.Ptr {
rt = rt.Elem()
rv = rv.Elem()
comp.value = rv
ptr = true
}

if gr, ok := container.components[rt]; ok {
if comp, ok := gr.find(nam); ok {
panic(duplicateError{previous: comp})
}
}
func dependinces(container Container, rt reflect.Type, rv reflect.Value) []dependency {

if rt.Kind() != reflect.Struct {
container.components[rt] = append(container.components[rt], comp)
return
}
dependinces := make([]dependency, 0)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


for i := 0; i < rt.NumField(); i++ {
sf := rt.Field(i)
Expand Down Expand Up @@ -121,15 +89,17 @@ func (container Container) Connect(val interface{}, id ...string) {
impl = idAndImpl[1]
}

comp.dependencies = append(comp.dependencies, dependency{
dependinces = append(dependinces, dependency{
id: id,
name: sf.Name,
index: i,
typ: depRt,
impl: impl,
})

} else if (sf.Type.Kind() == reflect.Ptr || sf.Type.Kind() == reflect.Interface) && rv.Field(i).IsNil() {
panic(tagMissingError{field: sf})
// Is this required
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trying to use an external library where wire:"-" can't be added, so is more of a question :)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is for validation purpose, to ensure all dependency is properly added and connected.

Hmm, I never consider the case where external library might have nil pointer or interface.
How if we add another variant of Connect function that allows bypassing this check?

// panic(tagMissingError{field: sf})
} else if sf.Type.Kind() == reflect.Struct {
// check forgotten tag only for struct.
if _, exist := container.components[sf.Type]; exist {
Expand All @@ -138,6 +108,47 @@ func (container Container) Connect(val interface{}, id ...string) {
}
}

return dependinces
}

// Connect a component, optionally identified by id.
func (container Container) Connect(val interface{}, id ...string) {
ptr := false
rv := reflect.ValueOf(val)
rt := rv.Type()
nam := ""
_, file, no, _ := runtime.Caller(container.callerSkip + 1)

if len(id) > 0 {
nam = id[0]
}

comp := component{
id: nam,
value: rv,
declaredAt: file + ":" + strconv.Itoa(no),
}

if rt.Kind() == reflect.Ptr {
rt = rt.Elem()
rv = rv.Elem()
comp.value = rv
ptr = true
}

if gr, ok := container.components[rt]; ok {
if comp, ok := gr.find(nam); ok {
panic(duplicateError{previous: comp})
}
}

if rt.Kind() != reflect.Struct {
container.components[rt] = append(container.components[rt], comp)
return
}

comp.dependencies = dependinces(container, rt, rv)

if len(comp.dependencies) != 0 && !ptr {
panic(incompletedError{})
}
Expand Down Expand Up @@ -173,6 +184,18 @@ func (container Container) Resolve(out interface{}, id ...string) {
panic(notAddressableError{id: nam, paramType: rt, component: comp})
}
} else {

if rt.Kind() == reflect.Interface {
for _, group := range container.components {
if v, e := group.find(nam); e {
if v.value.Addr().Type().Implements(rt) {
reflect.Indirect(rv).Set(v.value)
return
}
}
}
}

if gr, ok := container.components[rt]; ok {
rv.Set(gr.get(nam).value)
return
Expand All @@ -183,7 +206,37 @@ func (container Container) Resolve(out interface{}, id ...string) {
}

// Apply wiring to all components.
func (container Container) Apply() {
func (container Container) Apply(to ...interface{}) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interesting, this allows components added directly in apply function right?


if len(to) > 0 {

rv := reflect.ValueOf(to[0])
rt := rv.Type()
_, file, no, _ := runtime.Caller(container.callerSkip + 1)

comp := component{
id: "",
value: rv,
declaredAt: file + ":" + strconv.Itoa(no),
}

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

comp.dependencies = dependinces(
container,
rt,
rv,
)

container.fill(comp)

return
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need to return here? this will cause other components that connected using Connect to be not added right?

}

for _, gr := range container.components {
for _, comp := range gr {
container.fill(comp)
Expand Down