use std::marker::PhantomData;
use frunk_core::{
hlist::{HCons, HNil, Plucker, Sculptor},
traits::IntoReverse,
};
use crate::{
proposition::{
list::{EvaluablePropositionList, PropositionList},
Evaluable, Proposition,
},
proven::Proven,
};
pub struct AllOf<S, PL: PropositionList<S>> {
_phantom: PhantomData<fn() -> (S, PL)>,
}
impl<S, PL: PropositionList<S>> Clone for AllOf<S, PL> {
fn clone(&self) -> Self {
Self {
_phantom: self._phantom,
}
}
}
impl<S, PL: PropositionList<S>> std::fmt::Debug for AllOf<S, PL> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AllOf").finish()
}
}
impl<S, PL> Proposition<S> for AllOf<S, PL> where PL: PropositionList<S> {}
impl<S, PLH, PLT> Proven<S, AllOf<S, HCons<PLH, PLT>>>
where
PLH: Proposition<S>,
PLT: PropositionList<S>,
{
#[inline]
pub fn into_head_proven(self) -> Proven<S, PLH> {
unsafe { Proven::new_unchecked(self.into_subject()) }
}
#[inline]
pub fn into_tail_proven(self) -> Proven<S, AllOf<S, PLT>> {
unsafe { Proven::new_unchecked(self.into_subject()) }
}
#[inline]
pub fn into_plucked_proven<T, Index>(self) -> Proven<S, T>
where
T: Proposition<S>,
HCons<PLH, PLT>: Plucker<T, Index>,
{
unsafe { Proven::new_unchecked(self.into_subject()) }
}
}
impl<S, PL> Proven<S, AllOf<S, PL>>
where
PL: PropositionList<S>,
{
#[inline]
pub fn into_sculpted_proven<Ts, Indices>(self) -> Proven<S, AllOf<S, Ts>>
where
Ts: PropositionList<S>,
PL: Sculptor<Ts, Indices>,
{
unsafe { Proven::new_unchecked(self.into_subject()) }
}
#[inline]
pub fn into_rev_list_proven(self) -> Proven<S, AllOf<S, <PL as IntoReverse>::Output>>
where
PL: IntoReverse,
<PL as IntoReverse>::Output: PropositionList<S>,
{
unsafe { Proven::new_unchecked(self.into_subject()) }
}
#[allow(clippy::type_complexity)]
pub fn try_extend_proposition<P>(
self,
) -> Result<Proven<S, AllOf<S, HCons<P, PL>>>, <P as Evaluable<S>>::EvalError>
where
P: Proposition<S> + Evaluable<S>,
{
P::evaluate_for(self.as_ref())
.map(|_| unsafe { Proven::new_unchecked(self.into_subject()) })
}
pub unsafe fn extend_proposition_unchecked<P>(self) -> Proven<S, AllOf<S, HCons<P, PL>>>
where
P: Proposition<S>,
{
Proven::new_unchecked(self.into_subject())
}
}
impl<S> Proven<S, AllOf<S, HNil>> {
pub fn new(subject: S) -> Self {
unsafe { Self::new_unchecked(subject) }
}
}
impl<S, PL> Evaluable<S> for AllOf<S, PL>
where
PL: EvaluablePropositionList<S>,
{
type EvalError = Box<dyn std::error::Error + Send + Sync + 'static>;
#[inline]
fn evaluate_for(sub: &S) -> Result<(), Self::EvalError> {
PL::evaluate_all_for(sub)
}
}