diff options
author | 2023-12-12 14:13:26 -0800 | |
---|---|---|
committer | 2023-12-14 16:12:20 -0800 | |
commit | 3c0a83d19f56061bc9f621372cc7a5245d1204f6 (patch) | |
tree | 4aad30e3db38c504452ba34eb531565f0b71b7f0 /android/provider.go | |
parent | e8eeec913f4c8cd00cfa30afc064b229fcdf0a51 (diff) |
Use generics for providers API
Using generics for the providers API allows a type to be associated
with a ProviderKey, resulting in a type-safe API without that doesn't
require runtime type assertions by every caller.
Unfortunately, Go does not allow generic types in methods, only in
functions [1]. This prevents a type-safe API on ModuleContext, and
requires moving the API to be functions that take a ModuleContext as
a parameter.
This CL creates the new API, but doesn't convert all of the callers.
[1] https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md#no-parameterized-methods)
Bug: 316410648
Test: builds
Change-Id: I3e30d68b966b730efd968166a38a25cc144bd6de
Diffstat (limited to 'android/provider.go')
-rw-r--r-- | android/provider.go | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/android/provider.go b/android/provider.go new file mode 100644 index 000000000..b2cc7c06d --- /dev/null +++ b/android/provider.go @@ -0,0 +1,120 @@ +package android + +import ( + "github.com/google/blueprint" +) + +// OtherModuleProviderContext is a helper interface that is a subset of ModuleContext, BottomUpMutatorContext, or +// TopDownMutatorContext for use in OtherModuleProvider. +type OtherModuleProviderContext interface { + otherModuleProvider(m blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) +} + +var _ OtherModuleProviderContext = BaseModuleContext(nil) +var _ OtherModuleProviderContext = ModuleContext(nil) +var _ OtherModuleProviderContext = BottomUpMutatorContext(nil) +var _ OtherModuleProviderContext = TopDownMutatorContext(nil) + +// OtherModuleProvider reads the provider for the given module. If the provider has been set the value is +// returned and the boolean is true. If it has not been set the zero value of the provider's type is returned +// and the boolean is false. The value returned may be a deep copy of the value originally passed to SetProvider. +// +// OtherModuleProviderContext is a helper interface that accepts ModuleContext, BottomUpMutatorContext, or +// TopDownMutatorContext. +func OtherModuleProvider[K any](ctx OtherModuleProviderContext, module blueprint.Module, provider blueprint.ProviderKey[K]) (K, bool) { + value, ok := ctx.otherModuleProvider(module, provider) + if !ok { + var k K + return k, false + } + return value.(K), ok +} + +// ModuleProviderContext is a helper interface that is a subset of ModuleContext, BottomUpMutatorContext, or +// TopDownMutatorContext for use in ModuleProvider. +type ModuleProviderContext interface { + provider(provider blueprint.AnyProviderKey) (any, bool) +} + +var _ ModuleProviderContext = BaseModuleContext(nil) +var _ ModuleProviderContext = ModuleContext(nil) +var _ ModuleProviderContext = BottomUpMutatorContext(nil) +var _ ModuleProviderContext = TopDownMutatorContext(nil) + +// ModuleProvider reads the provider for the current module. If the provider has been set the value is +// returned and the boolean is true. If it has not been set the zero value of the provider's type is returned +// and the boolean is false. The value returned may be a deep copy of the value originally passed to SetProvider. +// +// ModuleProviderContext is a helper interface that accepts ModuleContext, BottomUpMutatorContext, or +// TopDownMutatorContext. +func ModuleProvider[K any](ctx ModuleProviderContext, provider blueprint.ProviderKey[K]) (K, bool) { + value, ok := ctx.provider(provider) + if !ok { + var k K + return k, false + } + return value.(K), ok +} + +type SingletonModuleProviderContext interface { + moduleProvider(blueprint.Module, blueprint.AnyProviderKey) (any, bool) +} + +var _ SingletonModuleProviderContext = SingletonContext(nil) +var _ SingletonModuleProviderContext = (*TestContext)(nil) + +// SingletonModuleProvider wraps blueprint.SingletonModuleProvider to provide a type-safe method to retrieve the value +// of the given provider from a module using a SingletonContext. If the provider has not been set the first return +// value will be the zero value of the provider's type, and the second return value will be false. If the provider has +// been set the second return value will be true. +func SingletonModuleProvider[K any](ctx SingletonModuleProviderContext, module blueprint.Module, provider blueprint.ProviderKey[K]) (K, bool) { + value, ok := ctx.moduleProvider(module, provider) + if !ok { + var k K + return k, false + } + return value.(K), ok +} + +// SetProviderContext is a helper interface that is a subset of ModuleContext, BottomUpMutatorContext, or +// TopDownMutatorContext for use in SetProvider. +type SetProviderContext interface { + SetProvider(provider blueprint.AnyProviderKey, value any) +} + +var _ SetProviderContext = BaseModuleContext(nil) +var _ SetProviderContext = ModuleContext(nil) +var _ SetProviderContext = BottomUpMutatorContext(nil) +var _ SetProviderContext = TopDownMutatorContext(nil) + +// SetProvider sets the value for a provider for the current module. It panics if not called +// during the appropriate mutator or GenerateBuildActions pass for the provider, if the value +// is not of the appropriate type, or if the value has already been set. The value should not +// be modified after being passed to SetProvider. +// +// SetProviderContext is a helper interface that accepts ModuleContext, BottomUpMutatorContext, or +// TopDownMutatorContext. +func SetProvider[K any](ctx SetProviderContext, provider blueprint.ProviderKey[K], value K) { + ctx.SetProvider(provider, value) +} + +var _ OtherModuleProviderContext = (*otherModuleProviderAdaptor)(nil) + +// An OtherModuleProviderFunc can be passed to NewOtherModuleProviderAdaptor to create an OtherModuleProviderContext +// for use in tests. +type OtherModuleProviderFunc func(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) + +type otherModuleProviderAdaptor struct { + otherModuleProviderFunc OtherModuleProviderFunc +} + +func (p *otherModuleProviderAdaptor) otherModuleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) { + return p.otherModuleProviderFunc(module, provider) +} + +// NewOtherModuleProviderAdaptor returns an OtherModuleProviderContext that proxies calls to otherModuleProvider to +// the provided OtherModuleProviderFunc. It can be used in tests to unit test methods that need to call +// android.OtherModuleProvider. +func NewOtherModuleProviderAdaptor(otherModuleProviderFunc OtherModuleProviderFunc) OtherModuleProviderContext { + return &otherModuleProviderAdaptor{otherModuleProviderFunc} +} |