Consumer

In CGP, a consumer is a piece of code that consumes certain functionalities from a context. There are several ways which a consumer may consume a functionality. At its most basic, if a consumer has access to the concrete type of a context, it can access any methods defined by an impl block of that context.

#![allow(unused)]
fn main() {
struct Person { name: String }

impl Person {
    fn name(&self) -> &str {
        &self.name
    }
}

fn greet(person: &Person) {
    println!("Hello, {}!", person.name());
}
}

in the above example, we have a greet function that prints a greeting to a person using the method Person::name. In other words, we say that the greet function is a consumer to the Person::name method.

Context-Generic Consumers

The greet function in our previous example can only work with the Person struct. However, if we inspect the implementation of greet, we can see that it is possible to generalize greet to work with any type that has a name.

To generalize greet, we first need to define a trait that acts as an interface for getting a name:

#![allow(unused)]
fn main() {
trait HasName {
    fn name(&self) -> &str;
}

fn greet<Context>(context: &Context)
where
    Context: HasName
{
    println!("Hello, {}", context.name());
}
}

In the example above, we define a HasName trait that provides a name method. We then redefine greet to work generically with any Context type, with the where clause requiring Context to implement HasName. Inside the function body, we call the name method, and print out the greeting of that name.

Notice that in this example, we are able to implement greet before we have any concrete implementation of HasName. Compared to before, greet is now decoupled from the Person type, thus making our code more modular.

In CGP, this new version of greet is considered a context-generic consumer, as it is able to generically consume the HasName::name method from any Context type that implements HasName.

The concept of context-generic consumer is not unique to CGP. In fact, it is already commonly used in most of the Rust code that uses traits. However, we make an effort to study this concept, so that we can further generalize the concept in the later chapters of this book.