Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 20 additions & 7 deletions futures-util/src/compat/compat01as03.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use futures_core::{future::Future as Future03, stream::Stream as Stream03, task
#[cfg(feature = "sink")]
use futures_sink::Sink as Sink03;
use std::boxed::Box;
use std::cell::UnsafeCell;
use std::pin::Pin;
use std::task::Context;

Expand Down Expand Up @@ -319,33 +320,45 @@ where
}
}

struct NotifyWaker(task03::Waker);
#[repr(transparent)]
struct NotifyWaker(UnsafeCell<task03::Waker>);

#[derive(Clone)]
struct WakerToHandle<'a>(&'a task03::Waker);

impl From<WakerToHandle<'_>> for NotifyHandle01 {
fn from(handle: WakerToHandle<'_>) -> Self {
let ptr = Box::new(NotifyWaker(handle.0.clone()));
let waker_ptr: Box<task03::Waker> = Box::new(handle.0.clone());
// NotifyWaker is a transparent (pointer compatible) wrapper for
// task03::Waker (and wrapping in UnsafeCell is fine).
let ptr: *mut NotifyWaker = Box::into_raw(waker_ptr) as *mut NotifyWaker;

unsafe { Self::new(Box::into_raw(ptr)) }
unsafe { Self::new(ptr) }
}
}

impl Notify01 for NotifyWaker {
fn notify(&self, _: usize) {
self.0.wake_by_ref();
unsafe { &*self.0.get() }.wake_by_ref();
}
}

unsafe impl Send for NotifyWaker {}
unsafe impl Sync for NotifyWaker {}

unsafe impl UnsafeNotify01 for NotifyWaker {
unsafe fn clone_raw(&self) -> NotifyHandle01 {
WakerToHandle(&self.0).into()
WakerToHandle(unsafe { &*self.0.get() }).into()
}

unsafe fn drop_raw(&self) {
let ptr: *const dyn UnsafeNotify01 = self;
drop(unsafe { Box::from_raw(ptr as *mut dyn UnsafeNotify01) });
/* UnsafeNotify01::drop_raw says this should receive `*mut Self`,
* but that isn't dyn compatible.
* miri is unhappy when a `*mut` is created from a `&` reference,
* so need to go through `UnsafeCell`.
*/
let waker: *mut task03::Waker = self.0.get();
drop(unsafe { Box::from_raw(waker) });
}
}

Expand Down
14 changes: 14 additions & 0 deletions futures/tests/compat_miri.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#![cfg(feature = "compat")]
use futures::compat::Future01CompatExt;
use futures::executor::block_on;
use futures::future::TryFutureExt;

#[test]
// from https://github.com/rust-lang/futures-rs/issues/2514
fn miri_compat_two_way() {
let fut = async { Ok(()) as Result<(), ()> };
let fut = Box::pin(fut);
let fut = fut.compat(); // 03as01
let fut = fut.compat(); // 01as03
block_on(fut).unwrap();
}
Loading