diff --git a/CHANGELOG.md b/CHANGELOG.md index c9b26f0..8c51ae1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,12 @@ follows to track changes. [#17]: https://github.com/loichyan/dynify/pull/17 +### Fixed + +- Add `Send` and `Sync` bounds for `Buffered` ([#18]) + +[#18]: https://github.com/loichyan/dynify/pull/18 + ## [0.1.1] - 2025-08-28 The major update since the previous release is the introduction of the diff --git a/examples/async_sendable.rs b/examples/async_sendable.rs index a5baaa6..1733974 100644 --- a/examples/async_sendable.rs +++ b/examples/async_sendable.rs @@ -1,6 +1,7 @@ use std::future::Future; +use std::mem::MaybeUninit; -use dynify::PinDynify; +use dynify::Dynify; #[trait_variant::make(Send)] #[dynify::dynify] @@ -9,7 +10,12 @@ trait Client { } async fn make_request(client: &(dyn Sync + DynClient)) { - client.request("http://magic/coffee/shop").pin_boxed().await; + let mut stack = [MaybeUninit::::uninit(); 16]; + let mut heap = Vec::>::new(); + client + .request("http://magic/coffee/shop") + .init2(&mut stack, &mut heap) + .await; } fn poll_future(fut: impl Send + Future) { diff --git a/src/container.rs b/src/container.rs index 463f768..459f459 100644 --- a/src/container.rs +++ b/src/container.rs @@ -109,7 +109,7 @@ pub unsafe trait PinEmplace: Emplace { /// /// **Tips**: `Buffered` implements `Future`, so you can simply write /// `async_hello().init(&mut stack).await` in practice. -pub struct Buffered<'a, T: ?Sized>(NonNull, PhantomData<&'a mut [u8]>); +pub struct Buffered<'a, T: ?Sized>(NonNull, PhantomData<&'a mut T>); impl<'a, T: ?Sized> Buffered<'a, T> { /// Constructs a new instance with the provided pointer. /// @@ -214,6 +214,11 @@ impl<'a> Buffered<'a, dyn Any + Send + Sync> { } } +// SAFETY: Since we hold a exclusive reference to `T`, it's okay to inherit the +// `Send` and `Sync` bounds. +unsafe impl Send for Buffered<'_, T> {} +unsafe impl Sync for Buffered<'_, T> {} + // Pretend `Buffered` owns the value of `T` rather than just a pointer to it. // This, along with the `Buffered::project*` APIs, makes it easy to obtain a // pinned reference to `T` in safe Rust. But the downside is that this prevents @@ -275,7 +280,7 @@ impl fmt::Display for OutOfCapacity { } } -unsafe impl<'a, T: ?Sized, const N: usize> Emplace for &'a mut MaybeUninit<[u8; N]> { +unsafe impl<'a, T: 'a + ?Sized, const N: usize> Emplace for &'a mut MaybeUninit<[u8; N]> { type Ptr = Buffered<'a, T>; type Err = OutOfCapacity; @@ -287,7 +292,7 @@ unsafe impl<'a, T: ?Sized, const N: usize> Emplace for &'a mut MaybeUninit<[u uninit_slice.emplace(constructor) } } -unsafe impl<'a, T: ?Sized, const N: usize> Emplace for &'a mut [MaybeUninit; N] { +unsafe impl<'a, T: 'a + ?Sized, const N: usize> Emplace for &'a mut [MaybeUninit; N] { type Ptr = Buffered<'a, T>; type Err = OutOfCapacity; @@ -298,7 +303,7 @@ unsafe impl<'a, T: ?Sized, const N: usize> Emplace for &'a mut [MaybeUninit Emplace for &'a mut [MaybeUninit] { +unsafe impl<'a, T: 'a + ?Sized> Emplace for &'a mut [MaybeUninit] { type Ptr = Buffered<'a, T>; type Err = OutOfCapacity; @@ -393,7 +398,7 @@ mod __alloc { // TODO: pinned vector? #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] - unsafe impl<'a, T: ?Sized> Emplace for &'a mut Vec> { + unsafe impl<'a, T: 'a + ?Sized> Emplace for &'a mut Vec> { type Ptr = Buffered<'a, T>; type Err = Infallible; @@ -446,7 +451,7 @@ mod __smallvec { unsafe impl<'a, A, T> Emplace for &'a mut SmallVec where A: Array>, - T: ?Sized, + T: 'a + ?Sized, { type Ptr = Buffered<'a, T>; type Err = Infallible; diff --git a/src/container_tests.rs b/src/container_tests.rs index ad27ad0..e100690 100644 --- a/src/container_tests.rs +++ b/src/container_tests.rs @@ -120,6 +120,24 @@ fn unpin_buffered() { let _: &mut Buffered = Pin::into_inner(val); } +#[test] +fn send_buffered() { + let mut stack = newstk::<16>(); + let init = from_closure(|slot| slot.write(123)); + let val: Buffered = init.init(&mut stack); + fn ensure_send(_: impl Send) {} + ensure_send(val); +} + +#[test] +fn sync_buffered() { + let mut stack = newstk::<16>(); + let init = from_closure(|slot| slot.write(123)); + let val: Buffered = init.init(&mut stack); + fn ensure_sync(_: impl Sync) {} + ensure_sync(val); +} + #[test] fn project_buffered() { let mut stack = newstk::<16>(); diff --git a/src/dynify.md b/src/dynify.md index 43a3834..666fe01 100644 --- a/src/dynify.md +++ b/src/dynify.md @@ -121,7 +121,8 @@ illustrated below, you can combine `#[dynify]` with [trait-variant](https://crates.io/crates/trait-variant) to achieve this: ```rust -# use dynify::{PinDynify, dynify}; +# use dynify::{Dynify, dynify}; +# use std::mem::MaybeUninit; // You can also use `#(make(SendClient: Send))`. However, in this case, you can // no longer specify a name in `#[dynify]` because `#[trait_variant::make]` // will generate two traits, which leads to conflicting trait definitions. @@ -133,8 +134,10 @@ trait Client { fn run_client( client: &(dyn DynClient + Sync), ) -> impl '_ + std::future::Future + Send { + let mut stack = [MaybeUninit::::uninit(); 16]; + let mut heap = Vec::>::new(); async move { - client.request("http://magic/request").pin_boxed().await; + client.request("http://magic/request").init2(&mut stack, &mut heap).await; } } ```