use std::future::Future;
#[allow(dead_code)]
#[derive(Debug)]
pub(crate) struct FromRuntime<B, A, T>(MaybeAsync<B, A, T>);
impl<B, A, T> FromRuntime<B, A, T> {
#[cfg(feature = "blocking")]
#[inline(always)]
pub(crate) fn std(value: B) -> Self {
Self(MaybeAsync::Blocking(value))
}
#[cfg(feature = "async-std")]
#[inline(always)]
pub(crate) fn async_std(value: A) -> Self {
Self(MaybeAsync::Async(Async::AsyncStd(value)))
}
#[cfg(feature = "tokio")]
#[inline(always)]
pub(crate) fn tokio(value: T) -> Self {
Self(MaybeAsync::Async(Async::Tokio(value)))
}
}
impl<X> FromRuntime<X, X, X> {
pub(crate) fn into_inner(self) -> X {
match self.0 {
MaybeAsync::Blocking(value) => value,
MaybeAsync::Async(value) => match value {
Async::AsyncStd(value) => value,
Async::Tokio(value) => value,
},
}
}
}
#[allow(dead_code)]
#[derive(Debug)]
enum MaybeAsync<B, A, T> {
Blocking(B),
Async(Async<A, T>),
}
#[allow(dead_code)]
#[derive(Debug)]
enum Async<A, T> {
AsyncStd(A),
Tokio(T),
}
#[allow(non_snake_case)]
#[cfg(not(any(feature = "blocking", feature = "async-std", feature = "tokio")))]
macro_rules! FromRuntime {
{
"std" => $blocking:ty,
"async-std" => $async_std:ty,
"tokio" => $tokio:ty,
} => {
$crate::runtime::FromRuntime::<(), (), ()>
};
}
#[allow(non_snake_case)]
#[cfg(all(feature = "blocking", feature = "async-std", feature = "tokio"))]
macro_rules! FromRuntime {
{
"std" => $blocking:ty,
"async-std" => $async_std:ty,
"tokio" => $tokio:ty,
} => {
$crate::runtime::FromRuntime<$blocking, $async_std, $tokio>
};
}
#[allow(non_snake_case)]
#[cfg(all(feature = "blocking", feature = "async-std", not(feature = "tokio")))]
macro_rules! FromRuntime {
{
"std" => $blocking:ty,
"async-std" => $async_std:ty,
"tokio" => $tokio:ty,
} => {
$crate::runtime::FromRuntime<$blocking, $async_std, ()>
};
}
#[allow(non_snake_case)]
#[cfg(all(feature = "tokio", feature = "async-std", not(feature = "blocking")))]
macro_rules! FromRuntime {
{
"std" => $blocking:ty,
"async-std" => $async_std:ty,
"tokio" => $tokio:ty,
} => {
$crate::runtime::FromRuntime<(), $async_std, $tokio>
};
}
#[allow(non_snake_case)]
#[cfg(all(feature = "blocking", feature = "tokio", not(feature = "async-std")))]
macro_rules! FromRuntime {
{
"std" => $blocking:ty,
"async-std" => $async_std:ty,
"tokio" => $tokio:ty,
} => {
$crate::runtime::FromRuntime<$blocking, (), $tokio>
};
}
#[allow(non_snake_case)]
#[cfg(all(
feature = "blocking",
not(any(feature = "async-std", feature = "tokio"))
))]
macro_rules! FromRuntime {
{
"std" => $blocking:ty,
"async-std" => $async_std:ty,
"tokio" => $tokio:ty,
} => {
$crate::runtime::FromRuntime<$blocking, (), ()>
};
}
#[allow(non_snake_case)]
#[cfg(all(
feature = "async-std",
not(any(feature = "blocking", feature = "tokio"))
))]
macro_rules! FromRuntime {
{
"std" => $blocking:ty,
"async-std" => $async_std:ty,
"tokio" => $tokio:ty,
} => {
$crate::runtime::FromRuntime<(), $async_std, ()>
};
}
#[allow(non_snake_case)]
#[cfg(all(
feature = "tokio",
not(any(feature = "blocking", feature = "async-std"))
))]
macro_rules! FromRuntime {
{
"std" => $blocking:ty,
"async-std" => $async_std:ty,
"tokio" => $tokio:ty,
} => {
$crate::runtime::FromRuntime<(), (), $tokio>
};
}
impl<B, A, T> FromRuntime<B, A, T> {
#[allow(unused_variables)]
pub fn apply<Ret, BFn, TFn, AFn>(&self, blocking: BFn, async_std: AFn, tokio: TFn) -> Ret
where
AFn: FnOnce(&A) -> Ret,
BFn: FnOnce(&B) -> Ret,
TFn: FnOnce(&T) -> Ret,
{
match &self.0 {
#[cfg(feature = "blocking")]
MaybeAsync::Blocking(value) => (blocking)(value),
#[cfg(not(feature = "blocking"))]
MaybeAsync::Blocking(_) => unsafe { std::hint::unreachable_unchecked() },
#[cfg(feature = "async")]
MaybeAsync::Async(value) => match value {
#[cfg(feature = "async-std")]
Async::AsyncStd(value) => (async_std)(value),
#[cfg(not(feature = "async-std"))]
Async::AsyncStd(_) => unsafe { std::hint::unreachable_unchecked() },
#[cfg(feature = "tokio")]
Async::Tokio(value) => (tokio)(value),
#[cfg(not(feature = "tokio"))]
Async::Tokio(_) => unsafe { std::hint::unreachable_unchecked() },
},
#[cfg(not(feature = "async"))]
MaybeAsync::Async(_) => unsafe { std::hint::unreachable_unchecked() },
}
}
#[allow(unused_variables)]
#[allow(dead_code)]
pub fn apply_with<Args, Ret, BFn, TFn, AFn>(
&self,
args: Args,
blocking: BFn,
async_std: AFn,
tokio: TFn,
) -> Ret
where
AFn: FnOnce(&A, Args) -> Ret,
BFn: FnOnce(&B, Args) -> Ret,
TFn: FnOnce(&T, Args) -> Ret,
{
match &self.0 {
#[cfg(feature = "blocking")]
MaybeAsync::Blocking(value) => (blocking)(value, args),
#[cfg(not(feature = "blocking"))]
MaybeAsync::Blocking(_) => unsafe { std::hint::unreachable_unchecked() },
#[cfg(feature = "async")]
MaybeAsync::Async(value) => match value {
#[cfg(feature = "async-std")]
Async::AsyncStd(value) => (async_std)(value, args),
#[cfg(not(feature = "async-std"))]
Async::AsyncStd(_) => unsafe { std::hint::unreachable_unchecked() },
#[cfg(feature = "tokio")]
Async::Tokio(value) => (tokio)(value, args),
#[cfg(not(feature = "tokio"))]
Async::Tokio(_) => unsafe { std::hint::unreachable_unchecked() },
},
#[cfg(not(feature = "async"))]
MaybeAsync::Async(_) => unsafe { std::hint::unreachable_unchecked() },
}
}
#[allow(unused_variables)]
pub fn apply_mut<Ret, BFn, TFn, AFn>(
&mut self,
blocking: BFn,
async_std: AFn,
tokio: TFn,
) -> Ret
where
AFn: FnOnce(&mut A) -> Ret,
BFn: FnOnce(&mut B) -> Ret,
TFn: FnOnce(&mut T) -> Ret,
{
match &mut self.0 {
#[cfg(feature = "blocking")]
MaybeAsync::Blocking(value) => (blocking)(value),
#[cfg(not(feature = "blocking"))]
MaybeAsync::Blocking(_) => unsafe { std::hint::unreachable_unchecked() },
#[cfg(feature = "async")]
MaybeAsync::Async(value) => match value {
#[cfg(feature = "async-std")]
Async::AsyncStd(value) => (async_std)(value),
#[cfg(not(feature = "async-std"))]
Async::AsyncStd(_) => unsafe { std::hint::unreachable_unchecked() },
#[cfg(feature = "tokio")]
Async::Tokio(value) => (tokio)(value),
#[cfg(not(feature = "tokio"))]
Async::Tokio(_) => unsafe { std::hint::unreachable_unchecked() },
},
#[cfg(not(feature = "async"))]
MaybeAsync::Async(_) => unsafe { std::hint::unreachable_unchecked() },
}
}
#[allow(unused_variables)]
pub fn apply_mut_with<Args, Ret, BFn, TFn, AFn>(
&mut self,
args: Args,
blocking: BFn,
async_std: AFn,
tokio: TFn,
) -> Ret
where
AFn: FnOnce(&mut A, Args) -> Ret,
BFn: FnOnce(&mut B, Args) -> Ret,
TFn: FnOnce(&mut T, Args) -> Ret,
{
match &mut self.0 {
#[cfg(feature = "blocking")]
MaybeAsync::Blocking(value) => (blocking)(value, args),
#[cfg(not(feature = "blocking"))]
MaybeAsync::Blocking(_) => unsafe { std::hint::unreachable_unchecked() },
#[cfg(feature = "async")]
MaybeAsync::Async(value) => match value {
#[cfg(feature = "async-std")]
Async::AsyncStd(value) => (async_std)(value, args),
#[cfg(not(feature = "async-std"))]
Async::AsyncStd(_) => unsafe { std::hint::unreachable_unchecked() },
#[cfg(feature = "tokio")]
Async::Tokio(value) => (tokio)(value, args),
#[cfg(not(feature = "tokio"))]
Async::Tokio(_) => unsafe { std::hint::unreachable_unchecked() },
},
#[cfg(not(feature = "async"))]
MaybeAsync::Async(_) => unsafe { std::hint::unreachable_unchecked() },
}
}
}
macro_rules! apply_runtime {
($from:expr, {
"std" => $std:expr,
"async-std" => $async_std:expr,
"tokio" => $tokio:expr,
}) => {{
$from.apply(
#[cfg(feature = "blocking")]
{
$std
},
#[cfg(not(feature = "blocking"))]
{
|_| unsafe { std::hint::unreachable_unchecked() }
},
#[cfg(feature = "async-std")]
{
$async_std
},
#[cfg(not(feature = "async-std"))]
{
|_| unsafe { std::hint::unreachable_unchecked() }
},
#[cfg(feature = "tokio")]
{
$tokio
},
#[cfg(not(feature = "tokio"))]
{
|_| unsafe { std::hint::unreachable_unchecked() }
},
)
}};
($from:expr, $args:expr, {
"std" => $std:expr,
"async-std" => $async_std:expr,
"tokio" => $tokio:expr,
}) => {{
$from.apply_with(
$args,
#[cfg(feature = "blocking")]
{
$std
},
#[cfg(not(feature = "blocking"))]
{
|_, _| unsafe { std::hint::unreachable_unchecked() }
},
#[cfg(feature = "async-std")]
{
$async_std
},
#[cfg(not(feature = "async-std"))]
{
|_, _| unsafe { std::hint::unreachable_unchecked() }
},
#[cfg(feature = "tokio")]
{
$tokio
},
#[cfg(not(feature = "tokio"))]
{
|_, _| unsafe { std::hint::unreachable_unchecked() }
},
)
}};
}
macro_rules! apply_mut_runtime {
($from:expr, {
"std" => $std:expr,
"async-std" => $async_std:expr,
"tokio" => $tokio:expr,
}) => {{
$from.apply_mut(
#[cfg(feature = "blocking")]
{
$std
},
#[cfg(not(feature = "blocking"))]
{
|_| unsafe { std::hint::unreachable_unchecked() }
},
#[cfg(feature = "async-std")]
{
$async_std
},
#[cfg(not(feature = "async-std"))]
{
|_| unsafe { std::hint::unreachable_unchecked() }
},
#[cfg(feature = "tokio")]
{
$tokio
},
#[cfg(not(feature = "tokio"))]
{
|_| unsafe { std::hint::unreachable_unchecked() }
},
)
}};
($from:expr, $args:expr, {
"std" => $std:expr,
"async-std" => $async_std:expr,
"tokio" => $tokio:expr,
}) => {{
$from.apply_mut_with(
$args,
#[cfg(feature = "blocking")]
{
$std
},
#[cfg(not(feature = "blocking"))]
{
|_, _| unsafe { std::hint::unreachable_unchecked() }
},
#[cfg(feature = "async-std")]
{
$async_std
},
#[cfg(not(feature = "async-std"))]
{
|_, _| unsafe { std::hint::unreachable_unchecked() }
},
#[cfg(feature = "tokio")]
{
$tokio
},
#[cfg(not(feature = "tokio"))]
{
|_, _| unsafe { std::hint::unreachable_unchecked() }
},
)
}};
}
#[allow(unused_macros)]
macro_rules! apply_runtime_blocking {
($from:expr, {
"std" => $std:expr,
}) => {{
$from.apply(
#[cfg(feature = "blocking")]
{
$std
},
#[cfg(not(feature = "blocking"))]
{
|_| unsafe { std::hint::unreachable_unchecked() }
},
#[cfg(feature = "async-std")]
{
|_| panic!("rtx: use of blocking IO on non-blocking instance")
},
#[cfg(not(feature = "async-std"))]
{
|_| unsafe { std::hint::unreachable_unchecked() }
},
#[cfg(feature = "tokio")]
{
|_| panic!("rtx: use of blocking IO on non-blocking instance")
},
#[cfg(not(feature = "tokio"))]
{
|_| unsafe { std::hint::unreachable_unchecked() }
},
)
}};
($from:expr, $args:expr, {
"std" => $std:expr,
"async-std" => $async_std:expr,
"tokio" => $tokio:expr,
}) => {{
$from.apply_with(
$args,
#[cfg(feature = "blocking")]
{
$std
},
#[cfg(not(feature = "blocking"))]
{
|_, _| unsafe { std::hint::unreachable_unchecked() }
},
#[cfg(feature = "async-std")]
{
|_, _| panic!("rtx: use of blocking IO on non-blocking instance")
},
#[cfg(not(feature = "async-std"))]
{
|_, _| unsafe { std::hint::unreachable_unchecked() }
},
#[cfg(feature = "tokio")]
{
|_, _| panic!("rtx: use of blocking IO on non-blocking instance")
},
#[cfg(not(feature = "tokio"))]
{
|_, _| unsafe { std::hint::unreachable_unchecked() }
},
)
}};
}
#[allow(unused_macros)]
macro_rules! apply_mut_runtime_blocking {
($from:expr, {
"std" => $std:expr,
}) => {{
$from.apply_mut(
#[cfg(feature = "blocking")]
{
$std
},
#[cfg(not(feature = "blocking"))]
{
|_| unsafe { std::hint::unreachable_unchecked() }
},
#[cfg(feature = "async-std")]
{
|_| panic!("rtx: use of blocking IO on non-blocking instance")
},
#[cfg(not(feature = "async-std"))]
{
|_| unsafe { std::hint::unreachable_unchecked() }
},
#[cfg(feature = "tokio")]
{
|_| panic!("rtx: use of blocking IO on non-blocking instance")
},
#[cfg(not(feature = "tokio"))]
{
|_| unsafe { std::hint::unreachable_unchecked() }
},
)
}};
($from:expr, $args:expr, {
"std" => $std:expr,
}) => {{
$from.apply_mut_with(
$args,
#[cfg(feature = "blocking")]
{
$std
},
#[cfg(not(feature = "blocking"))]
{
|_, _| unsafe { std::hint::unreachable_unchecked() }
},
#[cfg(feature = "async-std")]
{
|_, _| panic!("rtx: use of blocking IO on non-blocking instance")
},
#[cfg(not(feature = "async-std"))]
{
|_, _| unsafe { std::hint::unreachable_unchecked() }
},
#[cfg(feature = "tokio")]
{
|_, _| panic!("rtx: use of blocking IO on non-blocking instance")
},
#[cfg(not(feature = "tokio"))]
{
|_, _| unsafe { std::hint::unreachable_unchecked() }
},
)
}};
}
#[allow(unused_macros)]
macro_rules! apply_runtime_async {
($from:expr, {
"async-std" => $async_std:expr,
"tokio" => $tokio:expr,
}) => {{
$from.apply(
#[cfg(feature = "blocking")]
{
|_| panic!("rtx: use of non-blocking IO on blocking instance")
},
#[cfg(not(feature = "blocking"))]
{
|_| unsafe { std::hint::unreachable_unchecked() }
},
#[cfg(feature = "async-std")]
{
$async_std
},
#[cfg(not(feature = "async-std"))]
{
|_| unsafe { std::hint::unreachable_unchecked() }
},
#[cfg(feature = "tokio")]
{
$tokio
},
#[cfg(not(feature = "tokio"))]
{
|_| unsafe { std::hint::unreachable_unchecked() }
},
)
}};
($from:expr, $args:expr, {
"async-std" => $async_std:expr,
"tokio" => $tokio:expr,
}) => {{
$from.apply_with(
$args,
#[cfg(feature = "blocking")]
{
|_, _| panic!("rtx: use of non-blocking IO on blocking instance")
},
#[cfg(not(feature = "blocking"))]
{
|_, _| unsafe { std::hint::unreachable_unchecked() }
},
#[cfg(feature = "async-std")]
{
$async_std
},
#[cfg(not(feature = "async-std"))]
{
|_, _| unsafe { std::hint::unreachable_unchecked() }
},
#[cfg(feature = "tokio")]
{
$tokio
},
#[cfg(not(feature = "tokio"))]
{
|_, _| unsafe { std::hint::unreachable_unchecked() }
},
)
}};
}
macro_rules! apply_mut_runtime_async {
($from:expr, {
"async-std" => $async_std:expr,
"tokio" => $tokio:expr,
}) => {{
$from.apply_mut(
#[cfg(feature = "blocking")]
{
|_| panic!("rtx: use of non-blocking IO on blocking instance")
},
#[cfg(not(feature = "blocking"))]
{
|_| unsafe { std::hint::unreachable_unchecked() }
},
#[cfg(feature = "async-std")]
{
$async_std
},
#[cfg(not(feature = "async-std"))]
{
|_| unsafe { std::hint::unreachable_unchecked() }
},
#[cfg(feature = "tokio")]
{
$tokio
},
#[cfg(not(feature = "tokio"))]
{
|_| unsafe { std::hint::unreachable_unchecked() }
},
)
}};
($from:expr, $args:expr, {
"async-std" => $async_std:expr,
"tokio" => $tokio:expr,
}) => {{
$from.apply_mut_with(
$args,
#[cfg(feature = "blocking")]
{
|_, _| panic!("rtx: use of non-blocking IO on blocking instance")
},
#[cfg(not(feature = "blocking"))]
{
|_, _| unsafe { std::hint::unreachable_unchecked() }
},
#[cfg(feature = "async-std")]
{
$async_std
},
#[cfg(not(feature = "async-std"))]
{
|_, _| unsafe { std::hint::unreachable_unchecked() }
},
#[cfg(feature = "tokio")]
{
$tokio
},
#[cfg(not(feature = "tokio"))]
{
|_, _| unsafe { std::hint::unreachable_unchecked() }
},
)
}};
}
impl<B, A, T, AFut, TFut> FromRuntime<B, AFut, TFut>
where
AFut: Future<Output = A>,
TFut: Future<Output = T>,
{
pub async fn resolve(self) -> FromRuntime<B, A, T> {
match self.0 {
MaybeAsync::Blocking(value) => FromRuntime(MaybeAsync::Blocking(value)),
MaybeAsync::Async(value) => match value {
Async::Tokio(value) => FromRuntime(MaybeAsync::Async(Async::Tokio(value.await))),
Async::AsyncStd(value) => {
FromRuntime(MaybeAsync::Async(Async::AsyncStd(value.await)))
}
},
}
}
}
impl<B, Err, A, T> FromRuntime<Result<B, Err>, Result<A, Err>, Result<T, Err>> {
pub fn into_result(self) -> Result<FromRuntime<B, A, T>, Err> {
Ok(match self.0 {
MaybeAsync::Blocking(value) => FromRuntime(MaybeAsync::Blocking(value?)),
MaybeAsync::Async(value) => match value {
Async::Tokio(value) => FromRuntime(MaybeAsync::Async(Async::Tokio(value?))),
Async::AsyncStd(value) => FromRuntime(MaybeAsync::Async(Async::AsyncStd(value?))),
},
})
}
}
impl<B, A, T> FromRuntime<B, A, T> {
#[doc(hidden)]
#[allow(unreachable_code, unused_variables)]
#[inline]
pub fn pick_async<Args, AFn, TFn>(args: Args, async_std: AFn, tokio: TFn) -> Self
where
AFn: FnOnce(Args) -> A,
TFn: FnOnce(Args) -> T,
{
#[cfg(feature = "tokio")]
if tokio::runtime::Handle::try_current().is_ok() {
return FromRuntime::tokio((tokio)(args));
}
#[cfg(feature = "async-std")]
{
return FromRuntime::async_std((async_std)(args));
}
panic!("rtx: no async runtime enabled or available")
}
}
#[allow(non_snake_case)]
macro_rules! pick_async_runtime {
($args:expr, {
"async-std" => $async_std:expr,
"tokio" => $tokio:expr,
}) => {
$crate::runtime::FromRuntime::pick_async(
$args,
#[cfg(feature = "async-std")]
{
$async_std
},
#[cfg(not(feature = "async-std"))]
{
|_| unsafe { std::hint::unreachable_unchecked() }
},
#[cfg(feature = "tokio")]
{
$tokio
},
#[cfg(not(feature = "tokio"))]
{
|_| unsafe { std::hint::unreachable_unchecked() }
},
)
};
}
#[allow(non_snake_case)]
macro_rules! pick_async_runtime_async {
($args:expr, {
"async-std" => $async_std:expr,
"tokio" => $tokio:expr,
}) => {
$crate::runtime::FromRuntime::pick_async(
$args,
#[cfg(feature = "async-std")]
{
$async_std
},
#[cfg(not(feature = "async-std"))]
{
|_| async { unsafe { std::hint::unreachable_unchecked() } }
},
#[cfg(feature = "tokio")]
{
$tokio
},
#[cfg(not(feature = "tokio"))]
{
|_| async { unsafe { std::hint::unreachable_unchecked() } }
},
)
};
}
impl<B, A, T> FromRuntime<B, A, T> {
#[doc(hidden)]
#[allow(unreachable_code, unused_variables)]
#[inline]
pub fn pick_blocking<Args, Err, BFn>(args: Args, blocking: BFn) -> Result<Self, Err>
where
BFn: FnOnce(Args) -> Result<B, Err>,
{
#[cfg(feature = "blocking")]
{
return Ok(FromRuntime::std((blocking)(args)?));
}
panic!("rtx: no blocking runtime enabled or available")
}
}
#[allow(non_snake_case)]
macro_rules! pick_blocking_runtime {
($args:expr, {
"std" => $blocking:expr,
}) => {
$crate::runtime::FromRuntime::pick_blocking(
$args,
#[cfg(feature = "blocking")]
{
$blocking
},
#[cfg(not(feature = "blocking"))]
{
|_| unsafe { std::hint::unreachable_unchecked() }
},
)
};
}