goose: add interface binding

An interface binding instructs goose that a concrete type should be used
to satisfy a dependency on an interface type. goose could determine this
implicitly, but having an explicit directive makes the provider author's
intent clear and allows different concrete types to satisfy different
smaller interfaces.

Reviewed-by: Tuo Shan <shantuo@google.com>
This commit is contained in:
Ross Light
2018-04-02 14:08:17 -07:00
parent 73d4c0f0fc
commit 1380f96c06
21 changed files with 383 additions and 46 deletions

View File

@@ -0,0 +1,26 @@
package main
import (
"fmt"
_ "foo"
)
func main() {
fmt.Println(injectFooer().Foo())
}
type Bar string
func (b *Bar) Foo() string {
return string(*b)
}
//goose:provide
func provideBar() *Bar {
b := new(Bar)
*b = "Hello, World!"
return b
}
//goose:bind provideBar "foo".Fooer *Bar

View File

@@ -0,0 +1,9 @@
//+build gooseinject
package main
import "foo"
//goose:use provideBar
func injectFooer() foo.Fooer

View File

@@ -0,0 +1,5 @@
package foo
type Fooer interface {
Foo() string
}

View File

@@ -0,0 +1 @@
Hello, World!

View File

@@ -0,0 +1 @@
bar

View File

@@ -0,0 +1,26 @@
package main
import "fmt"
func main() {
fmt.Println(injectFooer().Foo())
}
type Fooer interface {
Foo() string
}
type Bar string
func (b *Bar) Foo() string {
return string(*b)
}
//goose:provide
func provideBar() *Bar {
b := new(Bar)
*b = "Hello, World!"
return b
}
//goose:bind provideBar Fooer *Bar

View File

@@ -0,0 +1,7 @@
//+build gooseinject
package main
//goose:use provideBar
func injectFooer() Fooer

View File

@@ -0,0 +1 @@
Hello, World!

View File

@@ -0,0 +1 @@
foo

View File

@@ -0,0 +1,50 @@
// This test verifies that the concrete type is provided only once, even if an
// interface additionally depends on it.
package main
import (
"fmt"
"sync"
)
func main() {
injectFooBar()
fmt.Println(provideBarCalls)
}
type Fooer interface {
Foo() string
}
type Bar string
type FooBar struct {
Fooer Fooer
Bar *Bar
}
func (b *Bar) Foo() string {
return string(*b)
}
//goose:provide
//goose:bind provideBar Fooer *Bar
func provideBar() *Bar {
mu.Lock()
provideBarCalls++
mu.Unlock()
b := new(Bar)
*b = "Hello, World!"
return b
}
var (
mu sync.Mutex
provideBarCalls int
)
//goose:provide
func provideFooBar(fooer Fooer, bar *Bar) FooBar {
return FooBar{fooer, bar}
}

View File

@@ -0,0 +1,8 @@
//+build gooseinject
package main
//goose:use provideBar
//goose:use provideFooBar
func injectFooBar() FooBar

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1 @@
foo

View File

@@ -0,0 +1,22 @@
package main
import "fmt"
func main() {
fmt.Println(injectFooer().Foo())
}
type Fooer interface {
Foo() string
}
type Bar string
func (b Bar) Foo() string {
return string(b)
}
//goose:provide
func provideBar() Bar {
return "Hello, World!"
}

View File

@@ -0,0 +1,7 @@
//+build gooseinject
package main
//goose:use provideBar
func injectFooer() Fooer

View File

@@ -0,0 +1 @@
ERROR

View File

@@ -0,0 +1 @@
foo