use core::{marker::Destruct, ops::AsyncFn, pin::Pin};
use array_trait::Array;
use slice_ops::AsSlice;
use crate::{private::guard::PartialDivideAndConquerGuard, future::FutureDivideAndConquer};
use super::ArrayEach;
#[const_trait]
pub trait ArrayDivideAndConquer<T, const N: usize>: Array + AsSlice<Item = T>
{
fn divide_and_conquer<F>(self, reduce: F) -> Option<T>
where
F: FnMut(T, T) -> T + ~const Destruct;
fn divide_and_conquer_ref<'a, F>(&'a self, reduce: F) -> Option<&'a T>
where
F: FnMut(&'a T, &'a T) -> &'a T + ~const Destruct;
fn divide_and_conquer_mut<'a, F>(&'a mut self, reduce: F) -> Option<&'a mut T>
where
F: FnMut(&'a mut T, &'a mut T) -> &'a mut T + ~const Destruct;
fn divide_and_conquer_pin_ref<'a, F>(self: Pin<&'a Self>, reduce: F) -> Option<Pin<&'a T>>
where
F: FnMut(Pin<&'a T>, Pin<&'a T>) -> Pin<&'a T> + ~const Destruct;
fn divide_and_conquer_pin_mut<'a, F>(self: Pin<&'a mut Self>, reduce: F) -> Option<Pin<&'a mut T>>
where
F: FnMut(Pin<&'a mut T>, Pin<&'a mut T>) -> Pin<&'a mut T> + ~const Destruct;
async fn divide_and_conquer_async<F>(self, reduce: F) -> Option<T>
where
F: AsyncFn(T, T) -> T + ~const Destruct;
async fn divide_and_conquer_ref_async<'a, F>(&'a self, reduce: F) -> Option<&'a T>
where
F: AsyncFn(&'a T, &'a T) -> &'a T + ~const Destruct,
T: 'a;
async fn divide_and_conquer_mut_async<'a, F>(&'a mut self, reduce: F) -> Option<&'a mut T>
where
F: AsyncFn(&'a mut T, &'a mut T) -> &'a mut T + ~const Destruct,
T: 'a;
async fn divide_and_conquer_pin_ref_async<'a, F>(self: Pin<&'a Self>, reduce: F) -> Option<Pin<&'a T>>
where
F: AsyncFn(Pin<&'a T>, Pin<&'a T>) -> Pin<&'a T> + ~const Destruct,
T: 'a;
async fn divide_and_conquer_pin_mut_async<'a, F>(self: Pin<&'a mut Self>, reduce: F) -> Option<Pin<&'a mut T>>
where
F: AsyncFn(Pin<&'a mut T>, Pin<&'a mut T>) -> Pin<&'a mut T> + ~const Destruct,
T: 'a;
}
impl<T, const N: usize> ArrayDivideAndConquer<T, N> for [T; N]
{
fn divide_and_conquer<F>(self, reduce: F) -> Option<T>
where
F: FnMut(T, T) -> T
{
PartialDivideAndConquerGuard::new_left(self).reduce(reduce)
}
fn divide_and_conquer_ref<'a, F>(&'a self, reduce: F) -> Option<&'a T>
where
F: FnMut(&'a T, &'a T) -> &'a T
{
PartialDivideAndConquerGuard::new_left(self).reduce(reduce)
}
fn divide_and_conquer_mut<'a, F>(&'a mut self, reduce: F) -> Option<&'a mut T>
where
F: FnMut(&'a mut T, &'a mut T) -> &'a mut T
{
PartialDivideAndConquerGuard::new_left(self).reduce(reduce)
}
fn divide_and_conquer_pin_ref<'a, F>(self: Pin<&'a Self>, reduce: F) -> Option<Pin<&'a T>>
where
F: FnMut(Pin<&'a T>, Pin<&'a T>) -> Pin<&'a T>
{
PartialDivideAndConquerGuard::new_left(self).reduce(reduce)
}
fn divide_and_conquer_pin_mut<'a, F>(self: Pin<&'a mut Self>, reduce: F) -> Option<Pin<&'a mut T>>
where
F: FnMut(Pin<&'a mut T>, Pin<&'a mut T>) -> Pin<&'a mut T>
{
PartialDivideAndConquerGuard::new_left(self).reduce(reduce)
}
async fn divide_and_conquer_async<F>(self, reduce: F) -> Option<T>
where
F: AsyncFn(T, T) -> T
{
#[allow(clippy::redundant_closure)]
FutureDivideAndConquer::new(self, |x, y| reduce(x, y)).await
}
async fn divide_and_conquer_ref_async<'a, F>(&'a self, reduce: F) -> Option<&'a T>
where
F: AsyncFn(&'a T, &'a T) -> &'a T,
T: 'a
{
#[allow(clippy::redundant_closure)]
FutureDivideAndConquer::new(self.each_ref(), |x, y| reduce(x, y)).await
}
async fn divide_and_conquer_mut_async<'a, F>(&'a mut self, reduce: F) -> Option<&'a mut T>
where
F: AsyncFn(&'a mut T, &'a mut T) -> &'a mut T,
T: 'a
{
#[allow(clippy::redundant_closure)]
FutureDivideAndConquer::new(self.each_mut(), |x, y| reduce(x, y)).await
}
async fn divide_and_conquer_pin_ref_async<'a, F>(self: Pin<&'a Self>, reduce: F) -> Option<Pin<&'a T>>
where
F: AsyncFn(Pin<&'a T>, Pin<&'a T>) -> Pin<&'a T>,
T: 'a
{
#[allow(clippy::redundant_closure)]
FutureDivideAndConquer::new(self.each_pin_ref(), |x, y| reduce(x, y)).await
}
async fn divide_and_conquer_pin_mut_async<'a, F>(self: Pin<&'a mut Self>, reduce: F) -> Option<Pin<&'a mut T>>
where
F: AsyncFn(Pin<&'a mut T>, Pin<&'a mut T>) -> Pin<&'a mut T>,
T: 'a
{
#[allow(clippy::redundant_closure)]
FutureDivideAndConquer::new(self.each_pin_mut(), |x, y| reduce(x, y)).await
}
}
#[cfg(test)]
mod test
{
use crate::ops::*;
#[test]
fn it_works()
{
let a = [1, 2, 3, 4, 5];
let s = a.divide_and_conquer(|x, y| x + y).unwrap();
println!("{}", s);
tokio_test::block_on(async {
let s = a.divide_and_conquer_async(async |x, y| x + y).await.unwrap();
println!("{}", s);
});
}
}