diff --git a/src/SUMMARY.md b/src/SUMMARY.md
index 8c73d37..d70be04 100644
--- a/src/SUMMARY.md
+++ b/src/SUMMARY.md
@@ -10,3 +10,4 @@
- [RcChars](./exercises/rcchars.md)
- [Chapter 2](./chapter_2.md)
- [AnyStr](./exercises/anystr.md)
+ - [Mode](./exercises/mode.md)
diff --git a/src/chapter_2.md b/src/chapter_2.md
index 7ebb596..207a608 100644
--- a/src/chapter_2.md
+++ b/src/chapter_2.md
@@ -1 +1 @@
-# Chapter 2
+# Chapter 2: Missing Requirements
diff --git a/src/exercises/anystr.md b/src/exercises/anystr.md
index 2445608..645e7b1 100644
--- a/src/exercises/anystr.md
+++ b/src/exercises/anystr.md
@@ -1,3 +1,5 @@
+# `AnyStr`?
+
Create something similar to [Python's `typing.AnyStr`].
[Python's `typing.AnyStr`]: https://docs.python.org/3/library/typing.html#typing.AnyStr
diff --git a/src/exercises/bool_stream.md b/src/exercises/bool_stream.md
index 7988ab1..b138d99 100644
--- a/src/exercises/bool_stream.md
+++ b/src/exercises/bool_stream.md
@@ -1,6 +1,8 @@
-Make `test_covariance` compile by making `BoolStream<'a>` covariant `'a`. Restrictions:
+# Introducing variance to objects
+
+Make `test_covariance` compile by making `BoolStream<'a>` covariant over `'a`. Restrictions:
- Can only change implementation details of `BoolStream` and its methods and add extra items outside of what's given, i.e. no signature/test change.
-- Changed version must behave the same way.
+- Changed version must behave the same way as the original.
Consider the following code:
```rust,compile_fail
diff --git a/src/exercises/mode.md b/src/exercises/mode.md
new file mode 100644
index 0000000..c142798
--- /dev/null
+++ b/src/exercises/mode.md
@@ -0,0 +1,72 @@
+# Parsing modes
+Merge implementations of `ConsumesStream` and `Deterministic` for tuple.
+
+It's recommended to first solve [this exercise](./multiple_blanket.md).
+
+```rust
+trait Stream: Sized {
+ /// Try to read `n` bytes. Consumes the stream on failure.
+ fn read_n(
+ self,
+ n: usize,
+ ok: impl FnOnce(&[u8]) -> A,
+ err: impl FnOnce(&[u8]) -> E,
+ ) -> Result<(A, Self), E>;
+
+ /// Read all bytes, consuming the stream.
+ fn read_all(self, ok: impl FnOnce(&[u8]) -> A) -> A;
+}
+
+trait Parsable: Sized {
+ type Error;
+}
+
+/// Can parse any length of data.
+trait ConsumesStream: Parsable {
+ /// Try to parse the value. Can handle EOF, can ask for all data the stream has.
+ fn parse(stream: impl Stream) -> Result;
+
+ /// Push extra data into the value.
+ fn extend(self, data: &[u8]) -> Result;
+}
+
+/// Whether the parsing is terminated, is only determined by the data already parsed.
+trait Deterministic: Parsable {
+ /// Returns the stream, as it shouldn't succeed on unexpected EOF.
+ fn parse(stream: S) -> Result<(Self, S), Self::Error>;
+
+ /// Always fail on extra data.
+ fn fail(data: &[u8]) -> Self::Error;
+}
+
+enum Either {
+ Left(L),
+ Right(R),
+}
+
+impl Parsable for (A, B) {
+ type Error = Either;
+}
+
+impl ConsumesStream for (A, B) {
+ fn parse(stream: impl Stream) -> Result {
+ let (a, stream) = A::parse(stream).map_err(Either::Left)?;
+ B::parse(stream).map_err(Either::Right).map(|b| (a, b))
+ }
+
+ fn extend(self, data: &[u8]) -> Result {
+ self.1.extend(data).map_err(Either::Right).map(|b| (self.0, b))
+ }
+}
+
+impl Deterministic for (A, B) {
+ fn parse(stream: S) -> Result<(Self, S), Self::Error> {
+ let (a, stream) = A::parse(stream).map_err(Either::Left)?;
+ B::parse(stream).map_err(Either::Right).map(|(b, stream)| ((a, b), stream))
+ }
+
+ fn fail(data: &[u8]) -> Self::Error {
+ Either::Right(B::fail(data))
+ }
+}
+```
diff --git a/src/exercises/multiple_blanket.md b/src/exercises/multiple_blanket.md
index f324528..84b687d 100644
--- a/src/exercises/multiple_blanket.md
+++ b/src/exercises/multiple_blanket.md
@@ -1,13 +1,14 @@
+# Blanket, blanket, blanket
Make this compile with the following restrictions:
-- `A1` doesn't know about/depend on `A2`.
-- `A2` doesn't know about/depend on `A1`.
-- `A1` doesn't know about/depend on `A`.
-- `A2` doesn't know about/depend on `A`.
+- **Can't edit definitions of `A`, `test`, `tes1`, `test2`; can only add code outside of those items.**
- **Some types are `A1` but not `A2`.**
- **Some types are `A2` but not `A1`.**
- Some types are `A` but not `A2`.
- Some types are `A` but not `A1`.
-- **Can't edit definitions of `A`, `test`, `tes1`, `test2`; can only add code outside of those items.**
+- `A1` doesn't know about/depend on `A2`.
+- `A2` doesn't know about/depend on `A1`.
+- `A1` doesn't know about/depend on `A`.
+- `A2` doesn't know about/depend on `A`.
```rust
trait A {
diff --git a/src/exercises/rcchars.md b/src/exercises/rcchars.md
index 4f93c57..c51ee7a 100644
--- a/src/exercises/rcchars.md
+++ b/src/exercises/rcchars.md
@@ -1,3 +1,5 @@
+# Owned [`Chars`]
+
[`Chars`] but keeping a strong reference ([`Rc`]) to the string.
[`Chars`]: https://doc.rust-lang.org/std/str/struct.Chars.html
@@ -41,10 +43,10 @@
```
## Solutions
-- [Solution] used in rattlescript.
+- [Implementation] used in rattlescript.
- [Same solution] but with some extra comments.
- [Another solution].
-[Solution]: https://github.com/HavenSelph/rattlescript/blob/f8bafb8b063b9bf056efb1ea14188db0624d981c/src/interpreter/value.rs#L21-L50
+[Implementation]: https://github.com/HavenSelph/rattlescript/blob/f8bafb8b063b9bf056efb1ea14188db0624d981c/src/interpreter/value.rs#L21-L50
[Same solution]: https://gist.github.com/timotheyca/7e46c9734653b2fcbe826ea4d13b9aa0
[Another solution]: https://gist.github.com/timotheyca/bc419e0997d6f7ea5722fd2823a78c62
diff --git a/src/overview.md b/src/overview.md
index d5f27ae..37a19d9 100644
--- a/src/overview.md
+++ b/src/overview.md
@@ -1,13 +1,13 @@
# Exercises
-Random Rust exercises.
+Random Rust exercises. Mostly typesystem-oriented.
-**Warning: this is a live-edited website, errors and accidental spoilers are to be expected.**
+**Warning if you're viewing this not on github.io: this is a live-edited website, errors and accidental spoilers are to be expected.**
# Solutions
-Currently solutions are mostly provided in a non-human-readable form in the page source.
-Those are mostly intended for testing that the exercise is even possible to solve.
+Presently, solutions are often provided in a non-human-readable (compacted+misformatted) form as hidden code.
+Those are intended for testing that the exercise is even possible to solve.
```rust
# /*
fn fix_me() { // Greyed out because the solution changes this line.
@@ -19,7 +19,7 @@ fn do_not_change_this() {
fixed_name()
}
```
-Some exercises may not include have the replaced parts greyed out:
+Some exercises may not have the replaced parts greyed out:
```rust
# mod __ {
fn fix_me() {