use crate::prelude::Result;
use blaze_proc::docfg;
use std::{
any::Any,
marker::PhantomData,
panic::{catch_unwind, UnwindSafe},
};
pub trait Consumer {
type Output;
unsafe fn consume(self) -> Result<Self::Output>;
}
impl<T, F: FnOnce() -> Result<T>> Consumer for F {
type Output = T;
#[inline(always)]
unsafe fn consume(self) -> Result<T> {
(self)()
}
}
impl<T: ?Sized> Consumer for PhantomData<T> {
type Output = ();
#[inline(always)]
unsafe fn consume(self) -> Result<Self::Output> {
Ok(())
}
}
impl<T> Consumer for Result<T> {
type Output = T;
#[inline(always)]
unsafe fn consume(self) -> Result<T> {
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[repr(transparent)]
pub struct Specific<'a, C: 'a>(C, PhantomData<&'a mut &'a ()>);
impl<C> Specific<'_, C> {
#[inline(always)]
pub fn new(c: C) -> Self {
Self(c, PhantomData)
}
}
impl<'a, C: 'a + Consumer> Consumer for Specific<'a, C> {
type Output = C::Output;
#[inline(always)]
unsafe fn consume(self) -> Result<Self::Output> {
self.0.consume()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Noop;
impl Consumer for Noop {
type Output = ();
#[inline(always)]
unsafe fn consume(self) -> Result<Self::Output> {
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct Map<T, C, F>(pub(crate) C, pub(crate) F, PhantomData<T>);
impl<T, U, C: Consumer<Output = T>, F: FnOnce(T) -> U> Map<T, C, F> {
#[inline(always)]
pub const fn new(consumer: C, f: F) -> Self {
Self(consumer, f, PhantomData)
}
}
impl<T, U, C: Consumer<Output = T>, F: FnOnce(T) -> U> Consumer for Map<T, C, F> {
type Output = U;
#[inline(always)]
unsafe fn consume(self) -> Result<U> {
let v = self.0.consume()?;
return Ok((self.1)(v));
}
}
#[derive(Debug, Clone)]
pub struct TryMap<T, C, F>(pub(crate) C, pub(crate) F, PhantomData<T>);
impl<T, U, C: Consumer<Output = T>, F: FnOnce(T) -> Result<U>> TryMap<T, C, F> {
#[inline(always)]
pub const fn new(consumer: C, f: F) -> Self {
Self(consumer, f, PhantomData)
}
}
impl<T, U, C: Consumer<Output = T>, F: FnOnce(T) -> Result<U>> Consumer for TryMap<T, C, F> {
type Output = U;
#[inline(always)]
unsafe fn consume(self) -> Result<U> {
let v = self.0.consume()?;
return (self.1)(v);
}
}
#[derive(Debug, Clone)]
#[repr(transparent)]
pub struct CatchUnwind<C: UnwindSafe>(pub(super) C);
impl<C: Consumer + UnwindSafe> Consumer for CatchUnwind<C> {
type Output = ::core::result::Result<C::Output, Box<dyn Any + Send>>;
#[inline(always)]
unsafe fn consume(self) -> Result<Self::Output> {
return match catch_unwind(|| self.0.consume()) {
Ok(Ok(x)) => Ok(Ok(x)),
Ok(Err(e)) => Err(e),
Err(e) => Ok(Err(e)),
};
}
}
#[derive(Debug, Clone)]
#[repr(transparent)]
pub struct FlattenResult<C>(pub(super) C);
impl<T, C: Consumer<Output = Result<T>>> Consumer for FlattenResult<C> {
type Output = T;
#[inline(always)]
unsafe fn consume(self) -> Result<T> {
self.0.consume().and_then(core::convert::identity)
}
}
#[derive(Debug, Clone)]
pub struct Inspect<C, F>(pub(super) C, pub(super) F);
impl<C: Consumer, F: FnOnce(&C::Output)> Consumer for Inspect<C, F> {
type Output = C::Output;
#[inline(always)]
unsafe fn consume(self) -> Result<C::Output> {
let v = self.0.consume()?;
(self.1)(&v);
return Ok(v);
}
}
#[docfg(feature = "cl1_1")]
pub type Flatten<C> = FlattenScoped<'static, C>;
#[docfg(feature = "cl1_1")]
pub struct FlattenScoped<'a, C>(pub(super) super::ScopedCallbackHandle<'a, Result<C>>);
#[cfg(feature = "cl1_1")]
impl<C: Consumer> Consumer for FlattenScoped<'_, C> {
type Output = C::Output;
#[inline]
unsafe fn consume(mut self) -> Result<Self::Output> {
loop {
match self.0.try_join_unwrap() {
Ok(Ok(c)) => return c.consume(),
Ok(Err(e)) => return Err(e),
Err(e) => {
self.0 = e;
core::hint::spin_loop()
}
}
}
}
}
#[docfg(feature = "cl1_1")]
#[derive(Debug, Clone)]
pub struct JoinAll<C>(pub(super) Vec<C>);
#[cfg(feature = "cl1_1")]
impl<C: Consumer> Consumer for JoinAll<C> {
type Output = Vec<C::Output>;
#[inline]
unsafe fn consume(self) -> Result<Vec<C::Output>> {
let iter = self.0.into_iter().map(|x| x.consume());
return crate::try_collect(iter);
}
}
#[derive(Debug, Clone)]
pub struct Taking<Prev, T> {
pub(super) prev: Prev,
pub(super) _take: T,
}
impl<T, Prev: Consumer> Consumer for Taking<Prev, T> {
type Output = Prev::Output;
#[inline]
unsafe fn consume(self) -> Result<Self::Output> {
self.prev.consume()
}
}