-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 285b4f2
Showing
13 changed files
with
337 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# https://editorconfig.org/ | ||
|
||
root = true | ||
|
||
[*] | ||
indent_style = space | ||
indent_size = 4 | ||
end_of_line = lf | ||
charset = utf-8 | ||
trim_trailing_whitespace = true | ||
insert_final_newline = true | ||
|
||
[*.yml] | ||
indent_size = 2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
/target | ||
**/*.rs.bk |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
fmt: | ||
# Use a third-party repo since the official repo doesn't include tags. | ||
# https://github.com/rust-lang-nursery/docker-rust-nightly/issues/3 | ||
image: instrumentisto/rust:nightly-2019-08-15 | ||
before_script: | ||
- rustup component add rustfmt-preview | ||
script: | ||
- cargo fmt -- --check | ||
|
||
check: | ||
image: rust:1.37 | ||
before_script: | ||
- rustup component add clippy | ||
script: | ||
- cargo clippy --all-targets --features strict | ||
|
||
test: | ||
image: rust:1.37 | ||
script: | ||
- cargo test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
fail_fast: true | ||
|
||
repos: | ||
- repo: local | ||
hooks: | ||
- id: fmt | ||
name: fmt | ||
language: system | ||
files: '[.]rs$' | ||
entry: rustup run nightly-2019-08-15 rustfmt | ||
|
||
- id: check | ||
name: check | ||
language: system | ||
files: '[.]rs$' | ||
entry: cargo clippy --all-targets --features strict | ||
pass_filenames: false | ||
|
||
- id: test | ||
name: test | ||
language: system | ||
files: '[.]rs$' | ||
entry: cargo test | ||
pass_filenames: false |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
[package] | ||
name = "genawaiter" | ||
version = "0.0.0" | ||
authors = ["John Simon <john@whatisaph.one>"] | ||
edition = "2018" | ||
|
||
[dependencies] | ||
|
||
[features] | ||
strict = [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# nirvana-rust | ||
|
||
An opinionated [Rust] project starter. There are many like it, but this one is mine. | ||
|
||
[Rust]: https://www.rust-lang.org/ | ||
|
||
## Development | ||
|
||
### Install prerequisites | ||
|
||
- [Rust] | ||
- [pre-commit] | ||
|
||
[pre-commit]: https://pre-commit.com/ | ||
|
||
### Install the pre-commit hook | ||
|
||
```sh | ||
pre-commit install | ||
``` | ||
|
||
This installs a Git hook that runs a quick sanity check before every commit. | ||
|
||
### Run the app | ||
|
||
```sh | ||
cargo run | ||
``` | ||
|
||
### Run the tests | ||
|
||
```sh | ||
cargo test | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# https://github.com/rust-lang/rustfmt/blob/master/Configurations.md | ||
|
||
edition = "2018" | ||
error_on_line_overflow = true | ||
error_on_unformatted = true | ||
force_multiline_blocks = true | ||
format_code_in_doc_comments = true | ||
format_macro_matchers = true | ||
format_strings = true | ||
imports_layout = "HorizontalVertical" | ||
max_width = 88 | ||
merge_imports = true | ||
newline_style = "Unix" | ||
overflow_delimited_expr = true | ||
report_fixme = "Unnumbered" | ||
report_todo = "Unnumbered" | ||
use_field_init_shorthand = true | ||
version = "Two" | ||
wrap_comments = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
use crate::{waker, GeneratorState}; | ||
use std::{ | ||
cell::RefCell, | ||
future::Future, | ||
pin::Pin, | ||
rc::Rc, | ||
task::{Context, Poll}, | ||
}; | ||
|
||
type Airlock<Y> = Rc<RefCell<Option<Y>>>; | ||
|
||
pub fn advance<Y, R>( | ||
future: Pin<&mut impl Future<Output = R>>, | ||
airlock: &Airlock<Y>, | ||
) -> GeneratorState<Y, R> { | ||
let waker = waker::create(); | ||
let mut cx = Context::from_waker(&waker); | ||
|
||
match future.poll(&mut cx) { | ||
Poll::Pending => { | ||
let value = airlock.borrow_mut().take().unwrap(); | ||
GeneratorState::Yielded(value) | ||
} | ||
Poll::Ready(value) => GeneratorState::Complete(value), | ||
} | ||
} | ||
|
||
pub struct Co<Y> { | ||
pub(crate) airlock: Airlock<Y>, | ||
} | ||
|
||
impl<Y> Co<Y> { | ||
pub fn yield_(&self, value: Y) -> impl Future<Output = ()> + '_ { | ||
*self.airlock.borrow_mut() = Some(value); | ||
Barrier { | ||
airlock: &self.airlock, | ||
} | ||
} | ||
} | ||
|
||
pub struct Barrier<'y, Y> { | ||
airlock: &'y Airlock<Y>, | ||
} | ||
|
||
impl<'y, Y> Future for Barrier<'y, Y> { | ||
type Output = (); | ||
|
||
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> { | ||
if self.airlock.borrow().is_none() { | ||
// If there is no value in the airlock, resume the generator so it produces | ||
// one. | ||
Poll::Ready(()) | ||
} else { | ||
// If there is a value, pause the generator so we can yield the value to the | ||
// caller. | ||
Poll::Pending | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#![feature(async_await, async_closure)] | ||
#![warn(future_incompatible, rust_2018_compatibility, rust_2018_idioms, unused)] | ||
#![warn(clippy::pedantic)] | ||
// #![warn(clippy::cargo)] | ||
#![cfg_attr(feature = "strict", deny(warnings))] | ||
|
||
pub use crate::{ | ||
engine::Co, | ||
safe_rc::Generator as SafeRcGenerator, | ||
state::GeneratorState, | ||
}; | ||
|
||
mod engine; | ||
mod safe_rc; | ||
mod state; | ||
mod waker; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
use crate::{engine::advance, Co, GeneratorState}; | ||
use std::{cell::RefCell, future::Future, pin::Pin, rc::Rc}; | ||
|
||
pub struct Generator<Y, F: Future> { | ||
airlock: Rc<RefCell<Option<Y>>>, | ||
future: Pin<Box<F>>, | ||
} | ||
|
||
impl<Y, F: Future> Generator<Y, F> { | ||
pub fn new(start: impl FnOnce(Co<Y>) -> F) -> Self { | ||
let airlock = Rc::new(RefCell::new(None)); | ||
let future = { | ||
let airlock = airlock.clone(); | ||
Box::pin(start(Co { airlock })) | ||
}; | ||
Self { airlock, future } | ||
} | ||
|
||
pub fn resume(&mut self) -> GeneratorState<Y, F::Output> { | ||
advance(self.future.as_mut(), &self.airlock) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use crate::{safe_rc::Generator, Co, GeneratorState}; | ||
use std::future::Future; | ||
|
||
async fn simple_producer(c: Co<i32>) -> &'static str { | ||
c.yield_(10).await; | ||
"done" | ||
} | ||
|
||
#[test] | ||
fn function() { | ||
let mut gen = Generator::new(simple_producer); | ||
assert_eq!(gen.resume(), GeneratorState::Yielded(10)); | ||
assert_eq!(gen.resume(), GeneratorState::Complete("done")); | ||
} | ||
|
||
#[test] | ||
fn simple_closure() { | ||
async fn gen(i: i32, co: Co<i32>) -> &'static str { | ||
co.yield_(i * 2).await; | ||
"done" | ||
} | ||
|
||
let mut gen = Generator::new(|co| gen(5, co)); | ||
assert_eq!(gen.resume(), GeneratorState::Yielded(10)); | ||
assert_eq!(gen.resume(), GeneratorState::Complete("done")); | ||
} | ||
|
||
#[test] | ||
fn async_closure() { | ||
let mut gen = Generator::new(async move |co| { | ||
co.yield_(10).await; | ||
"done" | ||
}); | ||
assert_eq!(gen.resume(), GeneratorState::Yielded(10)); | ||
assert_eq!(gen.resume(), GeneratorState::Complete("done")); | ||
} | ||
|
||
#[test] | ||
fn pinned() { | ||
#[inline(never)] | ||
async fn produce(addrs: &mut Vec<*const i32>, co: Co<i32>) -> &'static str { | ||
use std::cell::Cell; | ||
|
||
let sentinel: Cell<i32> = Cell::new(0x8001); | ||
let sentinel_ref: &Cell<i32> = &sentinel; | ||
|
||
assert_eq!(sentinel.get(), 0x8001); | ||
sentinel_ref.set(0x8002); | ||
assert_eq!(sentinel.get(), 0x8002); | ||
addrs.push(sentinel.as_ptr()); | ||
|
||
co.yield_(10).await; | ||
|
||
assert_eq!(sentinel.get(), 0x8002); | ||
sentinel_ref.set(0x8003); | ||
assert_eq!(sentinel.get(), 0x8003); | ||
addrs.push(sentinel.as_ptr()); | ||
|
||
co.yield_(20).await; | ||
|
||
assert_eq!(sentinel.get(), 0x8003); | ||
sentinel_ref.set(0x8004); | ||
assert_eq!(sentinel.get(), 0x8004); | ||
addrs.push(sentinel.as_ptr()); | ||
|
||
"done" | ||
} | ||
|
||
fn create_generator( | ||
addrs: &mut Vec<*const i32>, | ||
) -> Generator<i32, impl Future<Output = &'static str> + '_> { | ||
let mut gen = Generator::new(move |co| produce(addrs, co)); | ||
assert_eq!(gen.resume(), GeneratorState::Yielded(10)); | ||
gen | ||
} | ||
|
||
let mut addrs = Vec::new(); | ||
let mut gen = create_generator(&mut addrs); | ||
|
||
assert_eq!(gen.resume(), GeneratorState::Yielded(20)); | ||
assert_eq!(gen.resume(), GeneratorState::Complete("done")); | ||
drop(gen); | ||
|
||
assert!(addrs.iter().all(|&p| p == addrs[0])); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
#[cfg_attr(test, derive(PartialEq, Debug))] | ||
#[allow(clippy::module_name_repetitions)] | ||
pub enum GeneratorState<Y, R> { | ||
Yielded(Y), | ||
Complete(R), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
use std::{ | ||
ptr, | ||
task::{RawWaker, RawWakerVTable, Waker}, | ||
}; | ||
|
||
pub fn create() -> Waker { | ||
unsafe { Waker::from_raw(RAW_WAKER) } | ||
} | ||
|
||
const VTABLE: RawWakerVTable = RawWakerVTable::new( | ||
/* clone */ |_| panic!(), | ||
/* wake */ |_| {}, | ||
/* wake_by_ref */ |_| {}, | ||
/* drop */ |_| {}, | ||
); | ||
|
||
const RAW_WAKER: RawWaker = RawWaker::new(ptr::null(), &VTABLE); |