use core::marker::PhantomData;
use crate::primitives::Peano;
use crate::primitives::{Bool, Present, Absent, GetTail, BoolAnd, BoolOr, BoolNot};
use crate::primitives::stream::{S, D0};
use super::node::{Empty, Leaf, Node16};
use super::capability::Capability;
pub struct Has<Cap>(PhantomData<Cap>);
pub struct And<L, R>(PhantomData<(L, R)>);
pub struct Or<L, R>(PhantomData<(L, R)>);
pub struct Not<Q>(PhantomData<Q>);
pub struct HNil;
pub struct HCons<H, T>(PhantomData<(H, T)>);
pub struct All<List>(PhantomData<List>);
pub struct Any<List>(PhantomData<List>);
#[diagnostic::on_unimplemented(
message = "Capability logic requirement evaluated to false or is invalid",
label = "Logic '{Query}' is NOT satisfied by capability set '{Self}'",
note = "Check if you are missing a required capability or possess a conflicting one."
)]
pub trait Evaluate<Query> {
type Out: Bool;
const RESULT: bool = <Self::Out as Bool>::VALUE;
}
pub trait EvalAt<Query, Depth> {
type Out: Bool;
}
impl<Cap, Depth> EvalAt<Has<Cap>, Depth> for Empty {
type Out = Absent;
}
use crate::primitives::stream::{StreamEq, DefaultMaxDepth};
impl<QCap, StoredCap, Depth> EvalAt<Has<QCap>, Depth> for Leaf<StoredCap>
where
QCap: Capability,
StoredCap: Capability,
QCap::Stream: StreamEq<StoredCap::Stream, DefaultMaxDepth>,
{
type Out = <QCap::Stream as StreamEq<StoredCap::Stream, DefaultMaxDepth>>::Out;
}
#[macros::node16]
impl<QCap, Depth, _Slots_> EvalAt<Has<QCap>, Depth> for _Node16_
where
QCap: Capability,
Depth: Peano,
QCap::Stream: GetTail<Depth>,
Self: RouteQuery<QCap, Depth, QCap::At<Depth>>,
{
type Out = <Self as RouteQuery<QCap, Depth, QCap::At<Depth>>>::Out;
}
use crate::primitives::nibble::{Nibble, X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, XA, XB, XC, XD, XE, XF};
pub trait RouteQuery<Cap, Depth, Nib: Nibble> {
type Out: Bool;
}
#[macros::node16(for_nibble)]
impl<Cap, Depth, _Slots_> RouteQuery<Cap, Depth, _Nibble_> for _Node16_
where
Cap: Capability,
Depth: Peano,
_SlotN_: EvalAt<Has<Cap>, S<Depth>>,
{
type Out = <_SlotN_ as EvalAt<Has<Cap>, S<Depth>>>::Out;
}
use super::node::Bucket;
impl<QCap, Head, Tail, Depth> EvalAt<Has<QCap>, Depth> for Bucket<Head, Tail>
where
QCap: Capability,
Head: Capability,
Tail: EvalAt<Has<QCap>, Depth>,
QCap::Stream: StreamEq<Head::Stream, DefaultMaxDepth>,
<QCap::Stream as StreamEq<Head::Stream, DefaultMaxDepth>>::Out: BoolOr<<Tail as EvalAt<Has<QCap>, Depth>>::Out>,
{
type Out = <<QCap::Stream as StreamEq<Head::Stream, DefaultMaxDepth>>::Out as BoolOr<<Tail as EvalAt<Has<QCap>, Depth>>::Out>>::Out;
}
impl<Cap, Depth> EvalAt<Has<Cap>, Depth> for &Leaf<Cap>
where
Cap: Capability,
{
type Out = Present; }
impl<Ctx, Cap> Evaluate<Cap> for Ctx
where
Cap: Capability,
Ctx: EvalAt<Has<Cap>, D0>,
{
type Out = <Ctx as EvalAt<Has<Cap>, D0>>::Out;
}
impl<Ctx, L, R> Evaluate<And<L, R>> for Ctx
where
Ctx: Evaluate<L> + Evaluate<R>,
<Ctx as Evaluate<L>>::Out: BoolAnd<<Ctx as Evaluate<R>>::Out>,
{
type Out = <<Ctx as Evaluate<L>>::Out as BoolAnd<<Ctx as Evaluate<R>>::Out>>::Out;
}
impl<Ctx, L, R> Evaluate<Or<L, R>> for Ctx
where
Ctx: Evaluate<L> + Evaluate<R>,
<Ctx as Evaluate<L>>::Out: BoolOr<<Ctx as Evaluate<R>>::Out>,
{
type Out = <<Ctx as Evaluate<L>>::Out as BoolOr<<Ctx as Evaluate<R>>::Out>>::Out;
}
impl<Ctx, Q> Evaluate<Not<Q>> for Ctx
where
Ctx: Evaluate<Q>,
<Ctx as Evaluate<Q>>::Out: BoolNot,
{
type Out = <<Ctx as Evaluate<Q>>::Out as BoolNot>::Out;
}
impl<Ctx> Evaluate<All<HNil>> for Ctx {
type Out = Present;
}
impl<Ctx, H, T> Evaluate<All<HCons<H, T>>> for Ctx
where
Ctx: Evaluate<H> + Evaluate<All<T>>,
<Ctx as Evaluate<H>>::Out: BoolAnd<<Ctx as Evaluate<All<T>>>::Out>,
{
type Out = <<Ctx as Evaluate<H>>::Out as BoolAnd<<Ctx as Evaluate<All<T>>>::Out>>::Out;
}
impl<Ctx> Evaluate<Any<HNil>> for Ctx {
type Out = Absent;
}
impl<Ctx, H, T> Evaluate<Any<HCons<H, T>>> for Ctx
where
Ctx: Evaluate<H> + Evaluate<Any<T>>,
<Ctx as Evaluate<H>>::Out: BoolOr<<Ctx as Evaluate<Any<T>>>::Out>,
{
type Out = <<Ctx as Evaluate<H>>::Out as BoolOr<<Ctx as Evaluate<Any<T>>>::Out>>::Out;
}
#[diagnostic::on_unimplemented(
message = "Capability requirement failed: {Query}",
label = "This capability set violates requirement '{Query}'",
note = "Set: {Set}\nCheck if you are missing a required capability or possess a conflicting one."
)]
pub trait IsTrue<Set, Query: ?Sized> {}
impl<S, Q: ?Sized> IsTrue<S, Q> for Present {}
pub trait Require<Q> {}
impl<C, Q> Require<Q> for C
where
C: Evaluate<Q>,
<C as Evaluate<Q>>::Out: IsTrue<C, Q>,
{
}
#[macro_export]
macro_rules! hlist {
() => { $crate::trie::HNil };
($head:ty $(, $tail:ty)*) => {
$crate::trie::HCons<$head, hlist![$($tail),*]>
};
}
#[macro_export]
macro_rules! all {
($($item:ty),* $(,)?) => {
$crate::trie::All<hlist![$($item),*]>
};
}
#[macro_export]
macro_rules! any {
($($item:ty),* $(,)?) => {
$crate::trie::Any<hlist![$($item),*]>
};
}