Diffstat (limited to 'src/effect.rs')
| -rw-r--r-- | src/effect.rs | 199 |
1 files changed, 117 insertions, 82 deletions
diff --git a/src/effect.rs b/src/effect.rs index dd8b971..bb54166 100644 --- a/src/effect.rs +++ b/src/effect.rs @@ -1,110 +1,145 @@ -use crate::{any::AnyTrait, hkt, type_class}; - -pub trait AsObj<'a, 'ctx: 'a> { - fn as_obj(&self) -> &dyn AnyTrait<'ctx>; - fn as_obj_mut(&mut self) -> &mut dyn AnyTrait<'ctx>; - fn into_obj(self) -> &'a mut dyn AnyTrait<'ctx>; -} - -impl<'a, 'ctx: 'a> AsObj<'a, 'ctx> for &'a mut (dyn AnyTrait<'ctx> + 'a) { - fn as_obj(&self) -> &dyn AnyTrait<'ctx> { - *self +use core::{ + marker::PhantomData, + pin::pin, + ptr, + task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, +}; + +use crate::{higher_ranked_trait, higher_ranked_type}; + +higher_ranked_trait! { + pub type class SendFuture['ctx, Output]: [for<'lt> core::future::Future<Output = Output> + Send + 'lt] + where { + Output: Send, } - - fn as_obj_mut(&mut self) -> &mut dyn AnyTrait<'ctx> { - *self - } - - fn into_obj(self) -> &'a mut dyn AnyTrait<'ctx> { - self + for where { + Output: 'lt, } } -impl<'a, 'ctx: 'a> AsObj<'a, 'ctx> for &'a mut (dyn AnyTrait<'ctx> + Send + 'a) { - fn as_obj(&self) -> &dyn AnyTrait<'ctx> { - *self - } - - fn as_obj_mut(&mut self) -> &mut dyn AnyTrait<'ctx> { - *self - } - - fn into_obj(self) -> &'a mut dyn AnyTrait<'ctx> { - self +/// Trait for effects. +pub trait Effect<'ctx>: 'static { + type Future<T: Send>: SendFuture::Trait<'ctx, T>; + + fn wrap<'a, F>(future: F) -> SendFuture::T<'a, 'ctx, Self::Future<F::Output>, F::Output> + where + F: core::future::Future + Send + 'a, + <F as core::future::Future>::Output: Send; + + #[cfg(feature = "alloc")] + #[inline] + fn wrap_boxed<'a, F>( + future: core::pin::Pin<Box<F>>, + ) -> SendFuture::T<'a, 'ctx, Self::Future<F::Output>, F::Output> + where + F: core::future::Future + Send + 'a, + <F as core::future::Future>::Output: Send, + { + Self::wrap(future) } } -type_class!(for<'lt, 'ctx> pub as_obj: AsObj<'lt, 'ctx>); -type_class!(for<'lt, 'ctx> pub any_t); +pub type Future<'a, 'ctx, T, E> = SendFuture::T<'a, 'ctx, <E as Effect<'ctx>>::Future<T>, T>; -pub trait EffectAnyTrait<'ctx>: 'static { - /// The `dyn AnyTrait<'ctx>` for the effect. - /// - /// this allows adding extra bounds to the trait object. - type AnyTrait: as_obj::Hkt<'ctx>; +pub struct Blocking<B = Spin> { + _marker: PhantomData<fn() -> B>, } -/// Trait for effects. -pub trait Effect<'ctx, T>: EffectAnyTrait<'ctx> { - /// The type functions return for this effect. - /// - /// This type should resolve into a `T`. - type Yield: any_t::Hkt<'ctx>; +pub trait BlockOn: 'static { + fn block_on<F>(future: F) -> F::Output + where + F: core::future::Future + Send, + <F as core::future::Future>::Output: Send; } -pub type Yield<'a, 'ctx, T, E> = any_t::T<'a, 'ctx, <E as Effect<'ctx, T>>::Yield>; - -pub enum SyncEffect {} - -hkt!((as_obj): for<'a, 'ctx> pub AnyTraitSendObj => &'a mut (dyn AnyTrait<'ctx> + Send + 'a)); -hkt!((as_obj): for<'a, 'ctx> pub AnyTraitObj => &'a mut (dyn AnyTrait<'ctx> + 'a)); - -hkt!((any_t): for<'a, 'ctx> pub SyncYield[T] => T); - -impl<'ctx, T> Effect<'ctx, T> for SyncEffect { - type Yield = SyncYield<'ctx, T>; +/// [`BlockOn`] implementer that just spins on the future. +/// +/// This is useful for futures that are alwayd ready. +pub enum Spin {} + +impl BlockOn for Spin { + #[inline(always)] + fn block_on<F>(future: F) -> F::Output + where + F: core::future::Future + Send, + { + let waker = noop(); + let mut context = Context::from_waker(&waker); + + let mut future = pin!(future); + loop { + if let Poll::Ready(value) = future.as_mut().poll(&mut context) { + return value; + } + } + } } -impl<'ctx> EffectAnyTrait<'ctx> for SyncEffect { - type AnyTrait = AnyTraitObj<'ctx>; +#[inline] +pub fn noop() -> Waker { + const VTABLE: &'static RawWakerVTable = &RawWakerVTable::new( + // Cloning just returns a new no-op raw waker + |_| RAW, + // `wake` does nothing + |_| {}, + // `wake_by_ref` does nothing + |_| {}, + // Dropping does nothing as we don't allocate anything + |_| {}, + ); + const RAW: RawWaker = RawWaker::new(ptr::null(), &VTABLE); + unsafe { Waker::from_raw(RAW) } } -#[cfg(feature = "alloc")] -hkt!((any_t): for<'a, 'ctx> pub AsyncSendYield[T] => - core::pin::Pin< - Box<dyn core::future::Future<Output = T> + Send + 'a>, - > -); +higher_ranked_type! { + pub type ReadyFuture['ctx, Output]: (SendFuture)[Output] + where { + Output: Send, + } = for<'lt> core::future::Ready<Output> +} -#[cfg(feature = "alloc")] -pub enum AsyncSendEffect {} +impl<'ctx, B: BlockOn> Effect<'ctx> for Blocking<B> { + type Future<T: Send> = ReadyFuture<'ctx, T>; -#[cfg(feature = "alloc")] -impl<'ctx, T> Effect<'ctx, T> for AsyncSendEffect { - type Yield = AsyncSendYield<'ctx, T>; + fn wrap<'a, F>(future: F) -> SendFuture::T<'a, 'ctx, Self::Future<F::Output>, F::Output> + where + F: core::future::Future + Send + 'a, + <F as core::future::Future>::Output: Send, + { + core::future::ready(B::block_on(future)) + } } #[cfg(feature = "alloc")] -impl<'ctx> EffectAnyTrait<'ctx> for AsyncSendEffect { - type AnyTrait = AnyTraitSendObj<'ctx>; +higher_ranked_type! { + pub type BoxFuture['ctx, Output]: (SendFuture)[Output] + where { + Output: Send, + } = for<'lt> core::pin::Pin<Box<dyn core::future::Future<Output = Output> + Send + 'lt>> } #[cfg(feature = "alloc")] -hkt!((any_t): for<'a, 'ctx> pub AsyncYield[T] => - core::pin::Pin< - Box<dyn core::future::Future<Output = T> + 'a>, - > -); - -#[cfg(feature = "alloc")] -pub enum AsyncEffect {} +pub enum Async {} #[cfg(feature = "alloc")] -impl<'ctx, T> Effect<'ctx, T> for AsyncEffect { - type Yield = AsyncYield<'ctx, T>; -} +impl<'ctx> Effect<'ctx> for Async { + type Future<T: Send> = BoxFuture<'ctx, T>; + + fn wrap<'a, F>(future: F) -> SendFuture::T<'a, 'ctx, Self::Future<F::Output>, F::Output> + where + F: core::future::Future + Send + 'a, + <F as core::future::Future>::Output: Send, + { + Box::pin(future) + } -#[cfg(feature = "alloc")] -impl<'ctx> EffectAnyTrait<'ctx> for AsyncEffect { - type AnyTrait = AnyTraitObj<'ctx>; + fn wrap_boxed<'a, F>( + future: core::pin::Pin<Box<F>>, + ) -> SendFuture::T<'a, 'ctx, Self::Future<F::Output>, F::Output> + where + F: core::future::Future + Send + 'a, + <F as core::future::Future>::Output: Send, + { + future + } } |