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)
- [Chapter 2](./chapter_2.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`].
[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.
- Changed version must behave the same way.
- Changed version must behave the same way as the original.
Consider the following code:
```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:
- `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 {

View File

@ -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

View File

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