Something went wrong. Try again.
🦀🚀 Abstract over `Send` and `!Send` traits crates.io/crates/future_form
Something went wrong. Try again.
5.3 kB · 199 lines
Rust
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200#![allow(missing_docs, clippy::missing_const_for_fn, clippy::future_not_send)]
use core::task::Poll;
use future_form::{FutureForm, Local, Sendable, future_form};use future_form_ffi::poll_once::PollOnce;use futures::future::{BoxFuture, LocalBoxFuture};
// -- Direct usage (no macro) -------------------------------------------------
#[test]fn test_sendable_poll_once_from_future() { let mut fut = Sendable::from_future(async { 42u32 }); assert_eq!(fut.poll_once(), Poll::Ready(42));}
#[test]fn test_local_poll_once_from_future() { let mut fut = Local::from_future(async { 42u32 }); assert_eq!(fut.poll_once(), Poll::Ready(42));}
#[test]fn test_sendable_poll_once_ready() { let mut fut: BoxFuture<'_, u32> = Sendable::ready(42); assert_eq!(fut.poll_once(), Poll::Ready(42));}
#[test]fn test_local_poll_once_ready() { let mut fut: LocalBoxFuture<'_, u32> = Local::ready(42); assert_eq!(fut.poll_once(), Poll::Ready(42));}
#[test]fn test_sendable_poll_once_multi_step() { use core::sync::atomic::{AtomicU32, Ordering}; use std::sync::Arc;
let shared = Arc::new(AtomicU32::new(0)); let shared2 = Arc::clone(&shared);
let mut fut = Sendable::from_future(core::future::poll_fn(move |_cx| { let val = shared2.load(Ordering::Acquire); if val > 0 { Poll::Ready(val) } else { Poll::Pending } }));
// First poll: value is 0, future is pending assert_eq!(fut.poll_once(), Poll::Pending);
// Host fulfills the effect shared.store(99, Ordering::Release);
// Second poll: value available assert_eq!(fut.poll_once(), Poll::Ready(99));}
#[test]fn test_local_poll_once_with_non_send() { use std::rc::Rc;
let data = Rc::new(42u32); let mut fut = Local::from_future(async move { *data }); assert_eq!(fut.poll_once(), Poll::Ready(42));}
// -- BoxFuture/LocalBoxFuture still implement Future -------------------------
#[tokio::test]async fn test_sendable_future_await() { let fut = Sendable::from_future(async { 42u32 }); assert_eq!(fut.await, 42);}
#[tokio::test]async fn test_local_future_await() { let fut = Local::from_future(async { 42u32 }); assert_eq!(fut.await, 42);}
// -- Macro-generated impls with poll_once ------------------------------------
trait Stepper<K: FutureForm> { fn step(&self) -> K::Future<'_, u32>;}
struct StepperImpl { val: u32,}
#[future_form(Sendable, Local)]impl<K: FutureForm> Stepper<K> for StepperImpl { fn step(&self) -> K::Future<'_, u32> { let val = self.val; K::from_future(async move { val + 1 }) }}
#[test]fn test_macro_sendable_poll_once() { let s = StepperImpl { val: 41 }; let mut fut = <StepperImpl as Stepper<Sendable>>::step(&s); assert_eq!(fut.poll_once(), Poll::Ready(42));}
#[test]fn test_macro_local_poll_once() { let s = StepperImpl { val: 41 }; let mut fut = <StepperImpl as Stepper<Local>>::step(&s); assert_eq!(fut.poll_once(), Poll::Ready(42));}
// -- Conditional bounds with poll_once ---------------------------------------
trait HostWithBounds<K: FutureForm, T: Clone> { fn wrap(&self, val: T) -> K::Future<'_, T>;}
struct BoundsImpl;
#[future_form(Sendable where T: Send, Local)]impl<K: FutureForm, T: Clone + 'static> HostWithBounds<K, T> for BoundsImpl { fn wrap(&self, val: T) -> K::Future<'_, T> { K::from_future(async move { val }) }}
#[test]fn test_sendable_conditional_bounds_poll_once() { let b = BoundsImpl; let mut fut = <BoundsImpl as HostWithBounds<Sendable, String>>::wrap(&b, "hi".into()); assert_eq!(fut.poll_once(), Poll::Ready("hi".to_string()));}
#[test]fn test_local_conditional_bounds_poll_once() { use std::rc::Rc;
let b = BoundsImpl; let val = Rc::new(42u32); let mut fut = <BoundsImpl as HostWithBounds<Local, Rc<u32>>>::wrap(&b, val); assert_eq!(fut.poll_once(), Poll::Ready(Rc::new(42)));}
// -- Generic consumer with poll_once -----------------------------------------
async fn generic_step<K: FutureForm>(s: &StepperImpl) -> u32where StepperImpl: Stepper<K>,{ Stepper::<K>::step(s).await}
#[tokio::test]async fn test_generic_consumer_sendable() { let s = StepperImpl { val: 41 }; assert_eq!(generic_step::<Sendable>(&s).await, 42);}
#[tokio::test]async fn test_generic_consumer_local() { let s = StepperImpl { val: 41 }; assert_eq!(generic_step::<Local>(&s).await, 42);}
// -- K::ready with poll_once -------------------------------------------------
trait ReadyStepper<K: FutureForm> { fn cached(&self) -> K::Future<'_, u32>;}
struct ReadyImpl { val: u32,}
#[future_form(Sendable, Local)]impl<K: FutureForm> ReadyStepper<K> for ReadyImpl { fn cached(&self) -> K::Future<'_, u32> { K::ready(self.val) }}
#[test]fn test_macro_sendable_ready_poll_once() { let r = ReadyImpl { val: 42 }; let mut fut = <ReadyImpl as ReadyStepper<Sendable>>::cached(&r); assert_eq!(fut.poll_once(), Poll::Ready(42));}
#[test]fn test_macro_local_ready_poll_once() { let r = ReadyImpl { val: 42 }; let mut fut = <ReadyImpl as ReadyStepper<Local>>::cached(&r); assert_eq!(fut.poll_once(), Poll::Ready(42));}