use crate::is_eq::IsEq;
use ordofp::async_core::FunctorAsync;
use std::future::Future;
pub fn id<T>(x: T) -> T {
x
}
pub async fn option_identity_async<A: Clone + Eq + Send + 'static>(fa: Option<A>) -> bool {
let result = FunctorAsync::fmap_async(fa.clone(), |x| async move { x }).await;
result == fa
}
pub async fn option_composition_async<A, B, C, F, G, Fut1, Fut2>(fa: Option<A>, f: F, g: G) -> bool
where
A: Clone + Send + 'static,
B: Clone + Send + 'static,
C: Eq + Send + 'static,
F: Fn(A) -> Fut1 + Clone + Send + Sync + 'static,
G: Fn(B) -> Fut2 + Clone + Send + Sync + 'static,
Fut1: Future<Output = B> + Send,
Fut2: Future<Output = C> + Send,
{
let f_clone = f.clone();
let g_clone = g.clone();
let intermediate: Option<B> = FunctorAsync::fmap_async(fa.clone(), f).await;
let lhs: Option<C> = FunctorAsync::fmap_async(intermediate, g).await;
let rhs: Option<C> = FunctorAsync::fmap_async(fa, move |x| {
let f = f_clone.clone();
let g = g_clone.clone();
async move {
let b = f(x).await;
g(b).await
}
})
.await;
lhs == rhs
}
pub async fn option_identity_eq_async<A: Clone + Send + 'static>(fa: Option<A>) -> IsEq<Option<A>> {
let mapped = FunctorAsync::fmap_async(fa.clone(), |x| async move { x }).await;
IsEq::equal_under_law(mapped, fa)
}
pub async fn result_identity_async<A, E>(fa: Result<A, E>) -> bool
where
A: Clone + Eq + Send + 'static,
E: Clone + Eq + Send + 'static,
{
let result = FunctorAsync::fmap_async(fa.clone(), |x| async move { x }).await;
result == fa
}
pub async fn result_composition_async<A, B, C, E, F, G, Fut1, Fut2>(
fa: Result<A, E>,
f: F,
g: G,
) -> bool
where
A: Clone + Send + 'static,
B: Clone + Send + 'static,
C: Eq + Send + 'static,
E: Clone + Eq + Send + 'static,
F: Fn(A) -> Fut1 + Clone + Send + Sync + 'static,
G: Fn(B) -> Fut2 + Clone + Send + Sync + 'static,
Fut1: Future<Output = B> + Send,
Fut2: Future<Output = C> + Send,
{
let f_clone = f.clone();
let g_clone = g.clone();
let intermediate: Result<B, E> = FunctorAsync::fmap_async(fa.clone(), f).await;
let lhs: Result<C, E> = FunctorAsync::fmap_async(intermediate, g).await;
let rhs: Result<C, E> = FunctorAsync::fmap_async(fa, move |x| {
let f = f_clone.clone();
let g = g_clone.clone();
async move {
let b = f(x).await;
g(b).await
}
})
.await;
lhs == rhs
}
pub async fn result_identity_eq_async<A, E>(fa: Result<A, E>) -> IsEq<Result<A, E>>
where
A: Clone + Send + 'static,
E: Clone + Send + 'static,
{
let mapped = FunctorAsync::fmap_async(fa.clone(), |x| async move { x }).await;
IsEq::equal_under_law(mapped, fa)
}
use ordofp::async_core::FunctorAsyncMut;
pub async fn vec_identity_async<A: Clone + Eq + Send + 'static>(fa: Vec<A>) -> bool {
let result = FunctorAsyncMut::fmap_async_mut(fa.clone(), |x| async move { x }).await;
result == fa
}
pub async fn vec_composition_async<A, B, C, F, G, Fut1, Fut2>(
fa: Vec<A>,
mut f: F,
mut g: G,
) -> bool
where
A: Clone + Send + 'static,
B: Clone + Send + 'static,
C: Eq + Send + 'static,
F: FnMut(A) -> Fut1 + Clone + Send + 'static,
G: FnMut(B) -> Fut2 + Clone + Send + 'static,
Fut1: Future<Output = B> + Send,
Fut2: Future<Output = C> + Send,
{
let intermediate: Vec<B> = FunctorAsyncMut::fmap_async_mut(fa.clone(), &mut f).await;
let lhs: Vec<C> = FunctorAsyncMut::fmap_async_mut(intermediate, &mut g).await;
let mut rhs = Vec::with_capacity(fa.len());
for a in fa {
let b = f(a).await;
let c = g(b).await;
rhs.push(c);
}
lhs == rhs
}
pub async fn vec_identity_eq_async<A: Clone + Send + 'static>(fa: Vec<A>) -> IsEq<Vec<A>> {
let mapped = FunctorAsyncMut::fmap_async_mut(fa.clone(), |x| async move { x }).await;
IsEq::equal_under_law(mapped, fa)
}
#[cfg(test)]
mod tests {
use super::*;
fn block_on<F: std::future::Future>(fut: F) -> F::Output {
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
fn noop_raw_waker() -> RawWaker {
fn noop(_: *const ()) {}
fn clone_waker(_: *const ()) -> RawWaker {
noop_raw_waker()
}
static VTABLE: RawWakerVTable = RawWakerVTable::new(clone_waker, noop, noop, noop);
RawWaker::new(std::ptr::null(), &VTABLE)
}
let waker = unsafe { Waker::from_raw(noop_raw_waker()) };
let mut cx = Context::from_waker(&waker);
let mut fut = std::pin::pin!(fut);
loop {
match fut.as_mut().poll(&mut cx) {
Poll::Ready(result) => return result,
Poll::Pending => std::thread::yield_now(),
}
}
}
#[test]
fn test_option_identity_async_some() {
let result = block_on(option_identity_async(Some(42)));
assert!(result);
}
#[test]
fn test_option_identity_async_none() {
let result = block_on(option_identity_async(None::<i32>));
assert!(result);
}
#[test]
fn test_option_composition_async_some() {
let result = block_on(option_composition_async(
Some(5),
|x| async move { x + 1 },
|x| async move { x * 2 },
));
assert!(result);
}
#[test]
fn test_option_composition_async_none() {
let result = block_on(option_composition_async(
None::<i32>,
|x| async move { x + 1 },
|x| async move { x * 2 },
));
assert!(result);
}
#[test]
fn test_option_composition_async_type_change() {
let result = block_on(option_composition_async(
Some(42),
|x: i32| async move { x.to_string() },
|s: String| async move { s.len() },
));
assert!(result);
}
#[test]
fn test_result_identity_async_ok() {
let result = block_on(result_identity_async(Ok::<i32, String>(42)));
assert!(result);
}
#[test]
fn test_result_identity_async_err() {
let result = block_on(result_identity_async(Err::<i32, String>(
"error".to_string(),
)));
assert!(result);
}
#[test]
fn test_result_composition_async_ok() {
let result = block_on(result_composition_async(
Ok::<i32, String>(5),
|x| async move { x + 1 },
|x| async move { x * 2 },
));
assert!(result);
}
#[test]
fn test_result_composition_async_err() {
let result = block_on(result_composition_async(
Err::<i32, String>("error".to_string()),
|x| async move { x + 1 },
|x| async move { x * 2 },
));
assert!(result);
}
#[test]
fn test_vec_identity_async() {
let result = block_on(vec_identity_async(vec![1, 2, 3]));
assert!(result);
}
#[test]
fn test_vec_identity_async_empty() {
let result = block_on(vec_identity_async(Vec::<i32>::new()));
assert!(result);
}
#[test]
fn test_vec_composition_async() {
let result = block_on(vec_composition_async(
vec![1, 2, 3],
|x| async move { x + 1 },
|x| async move { x * 2 },
));
assert!(result);
}
#[test]
fn test_option_identity_eq_async() {
let eq = block_on(option_identity_eq_async(Some(42)));
assert!(eq.holds());
}
#[test]
fn test_result_identity_eq_async() {
let eq = block_on(result_identity_eq_async(Ok::<i32, String>(42)));
assert!(eq.holds());
}
#[test]
fn test_vec_identity_eq_async() {
let eq = block_on(vec_identity_eq_async(vec![1, 2, 3]));
assert!(eq.holds());
}
}