Skip to content

Commit b8fdd10

Browse files
authored
fix: add Send and Sync bounds for Buffered (#18)
1 parent 16b3dc2 commit b8fdd10

File tree

5 files changed

+48
-10
lines changed

5 files changed

+48
-10
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ follows <https://www.conventionalcommits.org/en/v1.0.0/> to track changes.
4343

4444
[#17]: https://github.com/loichyan/dynify/pull/17
4545

46+
### Fixed
47+
48+
- Add `Send` and `Sync` bounds for `Buffered` ([#18])
49+
50+
[#18]: https://github.com/loichyan/dynify/pull/18
51+
4652
## [0.1.1] - 2025-08-28
4753

4854
The major update since the previous release is the introduction of the

examples/async_sendable.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::future::Future;
2+
use std::mem::MaybeUninit;
23

3-
use dynify::PinDynify;
4+
use dynify::Dynify;
45

56
#[trait_variant::make(Send)]
67
#[dynify::dynify]
@@ -9,7 +10,12 @@ trait Client {
910
}
1011

1112
async fn make_request(client: &(dyn Sync + DynClient)) {
12-
client.request("http://magic/coffee/shop").pin_boxed().await;
13+
let mut stack = [MaybeUninit::<u8>::uninit(); 16];
14+
let mut heap = Vec::<MaybeUninit<u8>>::new();
15+
client
16+
.request("http://magic/coffee/shop")
17+
.init2(&mut stack, &mut heap)
18+
.await;
1319
}
1420

1521
fn poll_future(fut: impl Send + Future<Output = ()>) {

src/container.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ pub unsafe trait PinEmplace<T: ?Sized>: Emplace<T> {
109109
///
110110
/// **Tips**: `Buffered<T: Future>` implements `Future`, so you can simply write
111111
/// `async_hello().init(&mut stack).await` in practice.
112-
pub struct Buffered<'a, T: ?Sized>(NonNull<T>, PhantomData<&'a mut [u8]>);
112+
pub struct Buffered<'a, T: ?Sized>(NonNull<T>, PhantomData<&'a mut T>);
113113
impl<'a, T: ?Sized> Buffered<'a, T> {
114114
/// Constructs a new instance with the provided pointer.
115115
///
@@ -214,6 +214,11 @@ impl<'a> Buffered<'a, dyn Any + Send + Sync> {
214214
}
215215
}
216216

217+
// SAFETY: Since we hold a exclusive reference to `T`, it's okay to inherit the
218+
// `Send` and `Sync` bounds.
219+
unsafe impl<T: ?Sized + Send> Send for Buffered<'_, T> {}
220+
unsafe impl<T: ?Sized + Sync> Sync for Buffered<'_, T> {}
221+
217222
// Pretend `Buffered` owns the value of `T` rather than just a pointer to it.
218223
// This, along with the `Buffered::project*` APIs, makes it easy to obtain a
219224
// pinned reference to `T` in safe Rust. But the downside is that this prevents
@@ -275,7 +280,7 @@ impl fmt::Display for OutOfCapacity {
275280
}
276281
}
277282

278-
unsafe impl<'a, T: ?Sized, const N: usize> Emplace<T> for &'a mut MaybeUninit<[u8; N]> {
283+
unsafe impl<'a, T: 'a + ?Sized, const N: usize> Emplace<T> for &'a mut MaybeUninit<[u8; N]> {
279284
type Ptr = Buffered<'a, T>;
280285
type Err = OutOfCapacity;
281286

@@ -287,7 +292,7 @@ unsafe impl<'a, T: ?Sized, const N: usize> Emplace<T> for &'a mut MaybeUninit<[u
287292
uninit_slice.emplace(constructor)
288293
}
289294
}
290-
unsafe impl<'a, T: ?Sized, const N: usize> Emplace<T> for &'a mut [MaybeUninit<u8>; N] {
295+
unsafe impl<'a, T: 'a + ?Sized, const N: usize> Emplace<T> for &'a mut [MaybeUninit<u8>; N] {
291296
type Ptr = Buffered<'a, T>;
292297
type Err = OutOfCapacity;
293298

@@ -298,7 +303,7 @@ unsafe impl<'a, T: ?Sized, const N: usize> Emplace<T> for &'a mut [MaybeUninit<u
298303
self.as_mut_slice().emplace(constructor)
299304
}
300305
}
301-
unsafe impl<'a, T: ?Sized> Emplace<T> for &'a mut [MaybeUninit<u8>] {
306+
unsafe impl<'a, T: 'a + ?Sized> Emplace<T> for &'a mut [MaybeUninit<u8>] {
302307
type Ptr = Buffered<'a, T>;
303308
type Err = OutOfCapacity;
304309

@@ -393,7 +398,7 @@ mod __alloc {
393398

394399
// TODO: pinned vector?
395400
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
396-
unsafe impl<'a, T: ?Sized> Emplace<T> for &'a mut Vec<MaybeUninit<u8>> {
401+
unsafe impl<'a, T: 'a + ?Sized> Emplace<T> for &'a mut Vec<MaybeUninit<u8>> {
397402
type Ptr = Buffered<'a, T>;
398403
type Err = Infallible;
399404

@@ -446,7 +451,7 @@ mod __smallvec {
446451
unsafe impl<'a, A, T> Emplace<T> for &'a mut SmallVec<A>
447452
where
448453
A: Array<Item = MaybeUninit<u8>>,
449-
T: ?Sized,
454+
T: 'a + ?Sized,
450455
{
451456
type Ptr = Buffered<'a, T>;
452457
type Err = Infallible;

src/container_tests.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,24 @@ fn unpin_buffered() {
120120
let _: &mut Buffered<usize> = Pin::into_inner(val);
121121
}
122122

123+
#[test]
124+
fn send_buffered() {
125+
let mut stack = newstk::<16>();
126+
let init = from_closure(|slot| slot.write(123));
127+
let val: Buffered<usize> = init.init(&mut stack);
128+
fn ensure_send(_: impl Send) {}
129+
ensure_send(val);
130+
}
131+
132+
#[test]
133+
fn sync_buffered() {
134+
let mut stack = newstk::<16>();
135+
let init = from_closure(|slot| slot.write(123));
136+
let val: Buffered<usize> = init.init(&mut stack);
137+
fn ensure_sync(_: impl Sync) {}
138+
ensure_sync(val);
139+
}
140+
123141
#[test]
124142
fn project_buffered() {
125143
let mut stack = newstk::<16>();

src/dynify.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ illustrated below, you can combine `#[dynify]` with
121121
[trait-variant](https://crates.io/crates/trait-variant) to achieve this:
122122

123123
```rust
124-
# use dynify::{PinDynify, dynify};
124+
# use dynify::{Dynify, dynify};
125+
# use std::mem::MaybeUninit;
125126
// You can also use `#(make(SendClient: Send))`. However, in this case, you can
126127
// no longer specify a name in `#[dynify]` because `#[trait_variant::make]`
127128
// will generate two traits, which leads to conflicting trait definitions.
@@ -133,8 +134,10 @@ trait Client {
133134
fn run_client(
134135
client: &(dyn DynClient + Sync),
135136
) -> impl '_ + std::future::Future<Output = ()> + Send {
137+
let mut stack = [MaybeUninit::<u8>::uninit(); 16];
138+
let mut heap = Vec::<MaybeUninit<u8>>::new();
136139
async move {
137-
client.request("http://magic/request").pin_boxed().await;
140+
client.request("http://magic/request").init2(&mut stack, &mut heap).await;
138141
}
139142
}
140143
```

0 commit comments

Comments
 (0)