Skip to content

Commit f002280

Browse files
jwong101rosefromthedead
authored andcommitted
fix unsound functions by returning !Unpin coroutines
1 parent 72e1bd0 commit f002280

File tree

1 file changed

+21
-32
lines changed

1 file changed

+21
-32
lines changed

src/lib.rs

Lines changed: 21 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub mod macro_impl;
5353
use core::{
5454
future::Future,
5555
ops::{ControlFlow, Coroutine, CoroutineState},
56-
pin::Pin,
56+
pin::pin,
5757
};
5858
use frunk::{
5959
coproduct::{CNil, CoprodInjector, CoprodUninjector, CoproductEmbedder, CoproductSubsetter},
@@ -76,7 +76,7 @@ pub fn run<F, R>(mut f: F) -> R
7676
where
7777
F: Coroutine<Coproduct<Begin, CNil>, Yield = CNil, Return = R>,
7878
{
79-
let pinned = core::pin::pin!(f);
79+
let pinned = pin!(f);
8080
match pinned.resume(Coproduct::Inl(Begin)) {
8181
CoroutineState::Yielded(never) => match never {},
8282
CoroutineState::Complete(ret) => ret,
@@ -108,14 +108,13 @@ impl<E: Effect> EffectGroup for E {
108108
/// Create a new effectful computation by applying a "pure" function to the return value of an
109109
/// existing computation.
110110
pub fn map<E, I, T, U>(
111-
mut g: impl Coroutine<I, Yield = E, Return = T>,
111+
g: impl Coroutine<I, Yield = E, Return = T>,
112112
f: impl FnOnce(T) -> U,
113113
) -> impl Coroutine<I, Yield = E, Return = U> {
114-
move |mut injs: I| {
114+
static move |mut injs: I| {
115+
let mut pinned = pin!(g);
115116
loop {
116-
// safety: see handle_group()
117-
let pinned = unsafe { Pin::new_unchecked(&mut g) };
118-
match pinned.resume(injs) {
117+
match pinned.as_mut().resume(injs) {
119118
CoroutineState::Yielded(effs) => injs = yield effs,
120119
CoroutineState::Complete(ret) => return f(ret),
121120
}
@@ -196,7 +195,7 @@ pub fn handle_group<
196195
BeginIndex,
197196
EmbedIndices,
198197
>(
199-
mut g: G,
198+
g: G,
200199
mut handler: impl FnMut(Es) -> ControlFlow<R, Is>,
201200
) -> impl Coroutine<PostIs, Yield = PostEs, Return = R>
202201
where
@@ -208,14 +207,11 @@ where
208207
PostIs: CoproductEmbedder<PreIs, EmbedIndices>,
209208
G: Coroutine<PreIs, Yield = PreEs, Return = R>,
210209
{
211-
move |_begin: PostIs| {
210+
static move |_begin: PostIs| {
212211
let mut injection = PreIs::inject(Begin);
212+
let mut pinned = pin!(g);
213213
loop {
214-
// safety: im 90% sure that since we are inside Coroutine::resume which takes
215-
// Pin<&mut self>, all locals in this function are effectively pinned and this call is
216-
// simply projecting that
217-
let pinned = unsafe { Pin::new_unchecked(&mut g) };
218-
match pinned.resume(injection) {
214+
match pinned.as_mut().resume(injection) {
219215
CoroutineState::Yielded(effs) => match effs.subset() {
220216
Ok(effs) => match handler(effs) {
221217
ControlFlow::Continue(injs) => injection = injs.embed(),
@@ -238,18 +234,16 @@ where
238234
/// because it is impossible to construct a computation that is both asynchronous and effectful.
239235
///
240236
/// For more flexible interactions with Futures, see [`effects::future`].
241-
pub async fn handle_async<Eff, G, Fut>(mut g: G, mut handler: impl FnMut(Eff) -> Fut) -> G::Return
237+
pub async fn handle_async<Eff, G, Fut>(g: G, mut handler: impl FnMut(Eff) -> Fut) -> G::Return
242238
where
243239
Eff: Effect,
244240
G: Coroutine<Coprod!(Tagged<Eff::Injection, Eff>, Begin), Yield = Coprod!(Eff)>,
245241
Fut: Future<Output = ControlFlow<G::Return, Eff::Injection>>,
246242
{
247243
let mut injs = Coproduct::inject(Begin);
244+
let mut pinned = pin!(g);
248245
loop {
249-
// safety: see handle_group() - remember that futures are pinned in the same way as
250-
// coroutines
251-
let pinned = unsafe { Pin::new_unchecked(&mut g) };
252-
match pinned.resume(injs) {
246+
match pinned.as_mut().resume(injs) {
253247
CoroutineState::Yielded(effs) => {
254248
let eff = match effs {
255249
Coproduct::Inl(v) => v,
@@ -285,11 +279,9 @@ where
285279
Fut: Future<Output = ControlFlow<G::Return, Is>>,
286280
{
287281
let mut injs = Is::inject(Begin);
282+
let mut pinned = pin!(g);
288283
loop {
289-
// safety: see handle_group() - remember that futures are pinned in the same way as
290-
// coroutines
291-
let pinned = unsafe { Pin::new_unchecked(&mut g) };
292-
match pinned.resume(injs) {
284+
match pinned.as_mut().resume(injs) {
293285
CoroutineState::Yielded(effs) => match handler(effs).await {
294286
ControlFlow::Continue(new_injs) => injs = new_injs,
295287
ControlFlow::Break(ret) => return ret,
@@ -329,7 +321,7 @@ pub fn transform<
329321
EmbedIndices2,
330322
EmbedIndices3,
331323
>(
332-
mut g: G1,
324+
g: G1,
333325
mut handler: impl FnMut(E) -> H,
334326
) -> impl Coroutine<PostIs, Yield = PostEs, Return = R>
335327
where
@@ -350,21 +342,18 @@ where
350342
> + CoproductSubsetter<HandlerIs, SubsetIndices2>,
351343
G1: Coroutine<PreIs, Yield = PreEs, Return = R>,
352344
{
353-
move |_begin: PostIs| {
345+
static move |_begin: PostIs| {
354346
let mut injection = PreIs::inject(Begin);
347+
let mut pinned = pin!(g);
355348
loop {
356-
// safety: see handle_group()
357-
let pinned = unsafe { Pin::new_unchecked(&mut g) };
358-
match pinned.resume(injection) {
349+
match pinned.as_mut().resume(injection) {
359350
CoroutineState::Yielded(effs) => match effs.uninject() {
360351
// the effect we are handling
361352
Ok(eff) => {
362-
let mut handling = handler(eff);
353+
let mut handling = pin!(handler(eff));
363354
let mut handler_inj = HandlerIs::inject(Begin);
364355
'run_handler: loop {
365-
// safety: same again
366-
let pinned = unsafe { Pin::new_unchecked(&mut handling) };
367-
match pinned.resume(handler_inj) {
356+
match handling.as_mut().resume(handler_inj) {
368357
CoroutineState::Yielded(effs) => {
369358
handler_inj = PostIs::subset(yield effs.embed()).ok().unwrap();
370359
},

0 commit comments

Comments
 (0)