Skip to content

Instantly share code, notes, and snippets.

@cynecx
Created February 18, 2020 21:33
Show Gist options
  • Select an option

  • Save cynecx/8f1abf1729468c73b7192108b26ff612 to your computer and use it in GitHub Desktop.

Select an option

Save cynecx/8f1abf1729468c73b7192108b26ff612 to your computer and use it in GitHub Desktop.
Quasi self-referential generator
// In the future when Rust supports Rust#69268,
// it might be possible to write 100% safe self-referencial structs with the help of generators.
#![feature(generic_associated_types)]
#![allow(incomplete_features)]
use core::marker::{PhantomData, PhantomPinned};
use core::pin::Pin;
use core::ptr;
pub enum GeneratorState<Y, R> {
Yielded(Y),
Complete(R),
}
pub trait Generator<R> {
type Yield<'a>;
type Return;
fn resume<'a, 'b>(
self: Pin<&'a mut Self>,
arg: R,
) -> GeneratorState<Self::Yield<'a>, Self::Return>;
}
struct TestGen {
owned: String,
cursor: (*const u8, usize),
_pinned: PhantomPinned,
}
impl TestGen {
fn new(owned: String) -> Pin<Box<Self>> {
Box::pin(TestGen {
owned,
cursor: (ptr::null(), 0),
_pinned: PhantomPinned,
})
}
}
enum Action {
Renew(fn(&mut String) -> &str),
Borrow,
}
impl Generator<Action> for TestGen {
type Yield<'a> = &'a str;
type Return = ();
fn resume<'a>(
self: Pin<&'a mut Self>,
arg: Action,
) -> GeneratorState<Self::Yield<'a>, Self::Return> {
let mut arg = arg;
let g = unsafe { Pin::get_unchecked_mut(self) };
loop {
match arg {
Action::Borrow => {
assert!(!g.cursor.0.is_null());
let slice = {
let p = ptr::slice_from_raw_parts(g.cursor.0, g.cursor.1);
unsafe { core::str::from_utf8_unchecked(&*p) }
};
return GeneratorState::Yielded(slice);
}
Action::Renew(renew) => {
let r = renew(&mut g.owned);
g.cursor = (r.as_ptr(), r.len());
arg = Action::Borrow;
},
}
}
}
}
fn main() {
let mut gen = TestGen::new("Hello World!".to_owned());
let msg = gen.as_mut().resume(Action::Renew(|x: &mut String| &x[6..]));
if let GeneratorState::Yielded(msg) = &msg {
println!("{}", msg);
}
let msg = gen.as_mut().resume(Action::Renew(|x: &mut String| &x[..]));
if let GeneratorState::Yielded(msg) = &msg {
println!("{}", msg);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment