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() {