parsing modes

This commit is contained in:
AF 2023-08-01 00:51:46 +00:00
parent 3b5bbb50d5
commit 7b33b0aa4a
8 changed files with 95 additions and 15 deletions

View File

@ -10,3 +10,4 @@
- [RcChars](./exercises/rcchars.md) - [RcChars](./exercises/rcchars.md)
- [Chapter 2](./chapter_2.md) - [Chapter 2](./chapter_2.md)
- [AnyStr](./exercises/anystr.md) - [AnyStr](./exercises/anystr.md)
- [Mode](./exercises/mode.md)

View File

@ -1 +1 @@
# Chapter 2 # Chapter 2: Missing Requirements

View File

@ -1,3 +1,5 @@
# `AnyStr`?
Create something similar to [Python's `typing.AnyStr`]. Create something similar to [Python's `typing.AnyStr`].
[Python's `typing.AnyStr`]: https://docs.python.org/3/library/typing.html#typing.AnyStr [Python's `typing.AnyStr`]: https://docs.python.org/3/library/typing.html#typing.AnyStr

View File

@ -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. - 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: Consider the following code:
```rust,compile_fail ```rust,compile_fail

72
src/exercises/mode.md Normal file
View File

@ -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<A, E>(
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<A>(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<Self, Self::Error>;
/// Push extra data into the value.
fn extend(self, data: &[u8]) -> Result<Self, Self::Error>;
}
/// 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<S: Stream>(stream: S) -> Result<(Self, S), Self::Error>;
/// Always fail on extra data.
fn fail(data: &[u8]) -> Self::Error;
}
enum Either<L, R> {
Left(L),
Right(R),
}
impl<A: Parsable, B: Parsable> Parsable for (A, B) {
type Error = Either<A::Error, B::Error>;
}
impl<A: Deterministic, B: ConsumesStream> ConsumesStream for (A, B) {
fn parse(stream: impl Stream) -> Result<Self, Self::Error> {
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, Self::Error> {
self.1.extend(data).map_err(Either::Right).map(|b| (self.0, b))
}
}
impl<A: Deterministic, B: Deterministic> Deterministic for (A, B) {
fn parse<S: Stream>(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))
}
}
```

View File

@ -1,13 +1,14 @@
# Blanket, blanket, blanket
Make this compile with the following restrictions: Make this compile with the following restrictions:
- `A1` doesn't know about/depend on `A2`. - **Can't edit definitions of `A`, `test`, `tes1`, `test2`; can only add code outside of those items.**
- `A2` doesn't know about/depend on `A1`.
- `A1` doesn't know about/depend on `A`.
- `A2` doesn't know about/depend on `A`.
- **Some types are `A1` but not `A2`.** - **Some types are `A1` but not `A2`.**
- **Some types are `A2` but not `A1`.** - **Some types are `A2` but not `A1`.**
- Some types are `A` but not `A2`. - Some types are `A` but not `A2`.
- Some types are `A` but not `A1`. - 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 ```rust
trait A { trait A {

View File

@ -1,3 +1,5 @@
# Owned [`Chars`]
[`Chars`] but keeping a strong reference ([`Rc`]) to the string. [`Chars`] but keeping a strong reference ([`Rc`]) to the string.
[`Chars`]: https://doc.rust-lang.org/std/str/struct.Chars.html [`Chars`]: https://doc.rust-lang.org/std/str/struct.Chars.html
@ -41,10 +43,10 @@
``` ```
## Solutions ## Solutions
- [Solution] used in rattlescript. - [Implementation] used in rattlescript.
- [Same solution] but with some extra comments. - [Same solution] but with some extra comments.
- [Another solution]. - [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 [Same solution]: https://gist.github.com/timotheyca/7e46c9734653b2fcbe826ea4d13b9aa0
[Another solution]: https://gist.github.com/timotheyca/bc419e0997d6f7ea5722fd2823a78c62 [Another solution]: https://gist.github.com/timotheyca/bc419e0997d6f7ea5722fd2823a78c62

View File

@ -1,13 +1,13 @@
# Exercises # 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 # Solutions
Currently solutions are mostly provided in a non-human-readable form in the page source. Presently, solutions are often provided in a non-human-readable (compacted+misformatted) form as hidden code.
Those are mostly intended for testing that the exercise is even possible to solve. Those are intended for testing that the exercise is even possible to solve.
```rust ```rust
# /* # /*
fn fix_me() { // Greyed out because the solution changes this line. fn fix_me() { // Greyed out because the solution changes this line.
@ -19,7 +19,7 @@ fn do_not_change_this() {
fixed_name() fixed_name()
} }
``` ```
Some exercises may not include have the replaced parts greyed out: Some exercises may not have the replaced parts greyed out:
```rust ```rust
# mod __ { # mod __ {
fn fix_me() { fn fix_me() {