Diffstat (limited to 'src/effect.rs')
-rw-r--r--src/effect.rs199
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
+ }
}