Skip to content

Commit 1467f95

Browse files
authored
Add consumer and provider chapters (#4)
* Add custom syntax highlighting theme * Write consumer chapter * Add provider chapter * Update GitHub links
1 parent b58d8c2 commit 1467f95

File tree

5 files changed

+267
-9
lines changed

5 files changed

+267
-9
lines changed

book.toml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,3 @@ edition = "2021"
1010

1111
[build]
1212
create-missing = false
13-
14-
15-
[output.html]
16-
default-theme = "rust"

content/consumer.md

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,62 @@
1+
# Consumer
12

2-
# Consumer
3+
In CGP, a _consumer_ is a piece of code that consumes certain functionalities from a context.
4+
There are several ways which a consumer may consume a functionality. At its most basic,
5+
if a consumer has access to the _concrete_ type of a context, it can access any methods
6+
defined by an `impl` block of that context.
7+
8+
```rust
9+
struct Person { name: String }
10+
11+
impl Person {
12+
fn name(&self) -> &str {
13+
&self.name
14+
}
15+
}
16+
17+
fn greet(person: &Person) {
18+
println!("Hello, {}!", person.name());
19+
}
20+
```
21+
22+
in the above example, we have a `greet` function that prints a greeting to a person using
23+
the method `Person::name`. In other words, we say that the `greet` function is a _consumer_
24+
to the `Person::name` method.
25+
26+
## Context-Generic Consumers
27+
28+
The `greet` function in our previous example can only work with the `Person` struct. However,
29+
if we inspect the implementation of `greet`, we can see that it is possible to generalize
30+
`greet` to work with _any_ type that has a name.
31+
32+
To generalize `greet`, we first need to define a _trait_ that acts as an _interface_ for getting
33+
a name:
34+
35+
```rust
36+
trait HasName {
37+
fn name(&self) -> &str;
38+
}
39+
40+
fn greet<Context>(context: &Context)
41+
where
42+
Context: HasName
43+
{
44+
println!("Hello, {}", context.name());
45+
}
46+
```
47+
48+
In the example above, we define a `HasName` trait that provides a `name` method. We then redefine
49+
`greet` to work generically with any `Context` type, with the `where` clause requiring `Context` to
50+
implement `HasName`. Inside the function body, we call the `name` method, and print out the greeting
51+
of that name.
52+
53+
Notice that in this example, we are able to implement `greet` _before_ we have any concrete implementation
54+
of `HasName`. Compared to before, `greet` is now _decoupled_ from the `Person` type, thus making
55+
our code more modular.
56+
57+
In CGP, this new version of `greet` is considered a _context-generic_ consumer, as it is able to _generically_
58+
consume the `HasName::name` method from any `Context` type that implements `HasName`.
59+
60+
The concept of context-generic consumer is not unique to CGP. In fact, it is already commonly used
61+
in most of the Rust code that uses traits. However, we make an effort to study this concept, so that
62+
we can further generalize the concept in the later chapters of this book.

content/introduction.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ such as the similarity and differences of context-generic programming as compare
4040

4141
## Contribution
4242

43-
This book is open sourced under the MIT license on [GitHub](https://github.com/contextgeneric/context-generic-programming-patterns).
43+
This book is open sourced under the MIT license on [GitHub](https://github.com/contextgeneric/cgp-patterns).
4444

45-
Anyone is welcome to contribute by submitting [pull requests](https://github.com/contextgeneric/context-generic-programming-patterns/pulls)
45+
Anyone is welcome to contribute by submitting [pull requests](https://github.com/contextgeneric/cgp-patterns/pulls)
4646
for grammatical correction, content improvement, or adding new design patterns.
4747

48-
A [GitHub Discussions](https://github.com/contextgeneric/context-generic-programming-patterns/discussions) forum is available for readers
48+
A [GitHub Discussions](https://github.com/contextgeneric/cgp-patterns/discussions) forum is available for readers
4949
to ask questions or have discussions for topics covered in this book.

content/provider.md

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,79 @@
1+
# Provider
12

2-
# Provider
3+
In CGP, a _provider_ is a piece of code that _implements_ certain functionality
4+
for a context. At its most basic, a provider is consist of an `impl` block for
5+
a trait.
6+
7+
```rust
8+
trait HasName {
9+
fn name(&self) -> &str;
10+
}
11+
12+
struct Person { name: String }
13+
14+
impl HasName for Person {
15+
fn name(&self) -> &str {
16+
&self.name
17+
}
18+
}
19+
```
20+
21+
In the above example, we implement the `HasName` for the `Person` struct.
22+
The block `impl HasName for Person` is a _provider_ of the `HasName` trait
23+
for the `Person` context.
24+
25+
Similar to the concept of a consumer, the use of provider is common in any
26+
Rust code that implements a trait. However, compared to cosumers, there
27+
are limitations on how providers can be defined in Rust.
28+
29+
For this example, the `impl` block is a _context-specific_ provider for the
30+
`Person` context. Furthermore, due to the restrictions of Rust's trait system,
31+
there can be at most one provider of `HasName` for the `Person` context.
32+
Another common restriction is that the provider has to be defined in the same
33+
crate as either the trait or the context.
34+
35+
The asymetry between what can be done with a provider, as compared to a consumer,
36+
is often a source of complexity in many Rust programs. As we will learn in later chapters,
37+
one of the goals of CGP is to break this asymetry, and make it easy to implement
38+
_context-generic providers_.
39+
40+
## Providers as Consumers
41+
42+
Although we have providers and consumers as distinct concepts, it is common to
43+
have code that serve as _both_ providers and consumers.
44+
45+
```rust
46+
# trait HasName {
47+
# fn name(&self) -> &str;
48+
# }
49+
#
50+
# struct Person { name: String }
51+
#
52+
# impl HasName for Person {
53+
# fn name(&self) -> &str {
54+
# &self.name
55+
# }
56+
# }
57+
#
58+
trait CanGreet {
59+
fn greet(&self);
60+
}
61+
62+
impl CanGreet for Person {
63+
fn greet(&self) {
64+
println!("Hello, {}!", self.name());
65+
}
66+
}
67+
```
68+
69+
The example above shows a new `CanGreet` trait, which provides a `greet` method.
70+
We then implement `CanGreet` for `Person`, with the `greet` implementation using
71+
`self.name()` to print out the name to be greeted.
72+
73+
Here, the block `impl CanGreet for Person` is a provider of `CanGreet` for the `Person`
74+
context. At the same time, it is also the _consumer_ of `HasName` for the `Person` context.
75+
In terms of genericity, the example code is _context-specific_ to the `Person` context for both
76+
the consumer and provider side.
77+
78+
As we will see in later chapters, a powerful idea introduced by CGP is that a piece of code
79+
can have _multiple spectrums_ of genericity on the consumer and provider sides.

theme/highlight.css

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*!
2+
Theme: GitHub
3+
Description: Light theme as seen on github.com
4+
Author: github.com
5+
Maintainer: @Hirse
6+
Updated: 2021-05-15
7+
8+
Outdated base version: https://github.com/primer/github-syntax-light
9+
Current colors taken from GitHub's CSS
10+
*/
11+
12+
.hljs {
13+
color: #24292e;
14+
background: #ffffff;
15+
}
16+
17+
.hljs-doctag,
18+
.hljs-keyword,
19+
.hljs-meta .hljs-keyword,
20+
.hljs-template-tag,
21+
.hljs-template-variable,
22+
.hljs-type,
23+
.hljs-variable.language_ {
24+
/* prettylights-syntax-keyword */
25+
color: #d73a49;
26+
}
27+
28+
.hljs-title,
29+
.hljs-title.class_,
30+
.hljs-title.class_.inherited__,
31+
.hljs-title.function_ {
32+
/* prettylights-syntax-entity */
33+
color: #6f42c1;
34+
}
35+
36+
.hljs-attr,
37+
.hljs-attribute,
38+
.hljs-literal,
39+
.hljs-meta,
40+
.hljs-number,
41+
.hljs-operator,
42+
.hljs-variable,
43+
.hljs-selector-attr,
44+
.hljs-selector-class,
45+
.hljs-selector-id {
46+
/* prettylights-syntax-constant */
47+
color: #005cc5;
48+
}
49+
50+
.hljs-regexp,
51+
.hljs-string,
52+
.hljs-meta .hljs-string {
53+
/* prettylights-syntax-string */
54+
color: #032f62;
55+
}
56+
57+
.hljs-built_in,
58+
.hljs-symbol {
59+
/* prettylights-syntax-variable */
60+
color: #e36209;
61+
}
62+
63+
.hljs-comment,
64+
.hljs-code,
65+
.hljs-formula {
66+
/* prettylights-syntax-comment */
67+
color: #6a737d;
68+
}
69+
70+
.hljs-name,
71+
.hljs-quote,
72+
.hljs-selector-tag,
73+
.hljs-selector-pseudo {
74+
/* prettylights-syntax-entity-tag */
75+
color: #22863a;
76+
}
77+
78+
.hljs-subst {
79+
/* prettylights-syntax-storage-modifier-import */
80+
color: #24292e;
81+
}
82+
83+
.hljs-section {
84+
/* prettylights-syntax-markup-heading */
85+
color: #005cc5;
86+
font-weight: bold;
87+
}
88+
89+
.hljs-bullet {
90+
/* prettylights-syntax-markup-list */
91+
color: #735c0f;
92+
}
93+
94+
.hljs-emphasis {
95+
/* prettylights-syntax-markup-italic */
96+
color: #24292e;
97+
font-style: italic;
98+
}
99+
100+
.hljs-strong {
101+
/* prettylights-syntax-markup-bold */
102+
color: #24292e;
103+
font-weight: bold;
104+
}
105+
106+
.hljs-addition {
107+
/* prettylights-syntax-markup-inserted */
108+
color: #22863a;
109+
background-color: #f0fff4;
110+
}
111+
112+
.hljs-deletion {
113+
/* prettylights-syntax-markup-deleted */
114+
color: #b31d28;
115+
background-color: #ffeef0;
116+
}
117+
118+
.hljs-char.escape_,
119+
.hljs-link,
120+
.hljs-params,
121+
.hljs-property,
122+
.hljs-punctuation,
123+
.hljs-tag {
124+
/* purposely ignored */
125+
}

0 commit comments

Comments
 (0)