Provider
In CGP, a provider is a piece of code that implements certain functionality
for a context. At its most basic, a provider is consist of an impl
block for
a trait.
#![allow(unused)] fn main() { trait HasName { fn name(&self) -> &str; } struct Person { name: String } impl HasName for Person { fn name(&self) -> &str { &self.name } } }
In the above example, we implement the HasName
for the Person
struct.
The block impl HasName for Person
is a provider of the HasName
trait
for the Person
context.
Similar to the concept of a consumer, the use of provider is common in any Rust code that implements a trait. However, compared to cosumers, there are limitations on how providers can be defined in Rust.
For this example, the impl
block is a context-specific provider for the
Person
context. Furthermore, due to the restrictions of Rust's trait system,
there can be at most one provider of HasName
for the Person
context.
Another common restriction is that the provider has to be defined in the same
crate as either the trait or the context.
The asymetry between what can be done with a provider, as compared to a consumer, is often a source of complexity in many Rust programs. As we will learn in later chapters, one of the goals of CGP is to break this asymetry, and make it easy to implement context-generic providers.
Providers as Consumers
Although we have providers and consumers as distinct concepts, it is common to have code that serve as both providers and consumers.
#![allow(unused)] fn main() { trait HasName { fn name(&self) -> &str; } struct Person { name: String } impl HasName for Person { fn name(&self) -> &str { &self.name } } trait CanGreet { fn greet(&self); } impl CanGreet for Person { fn greet(&self) { println!("Hello, {}!", self.name()); } } }
The example above shows a new CanGreet
trait, which provides a greet
method.
We then implement CanGreet
for Person
, with the greet
implementation using
self.name()
to print out the name to be greeted.
Here, the block impl CanGreet for Person
is a provider of CanGreet
for the Person
context. At the same time, it is also the consumer of HasName
for the Person
context.
In terms of genericity, the example code is context-specific to the Person
context for both
the consumer and provider side.
As we will see in later chapters, a powerful idea introduced by CGP is that a piece of code can have multiple spectrums of genericity on the consumer and provider sides.