use core::marker::PhantomData;
use prism::operation::TermValue;
use prism::pipeline::{
ChainComplexResolver, CochainComplexResolver, CohomologyGroupResolver, HasChainComplexResolver,
HasCochainComplexResolver, HasCohomologyGroupResolver, HasHomologyGroupResolver,
HasHomotopyGroupResolver, HasKInvariantResolver, HasNerveResolver, HasPostnikovResolver,
HomologyGroupResolver, HomotopyGroupResolver, KInvariantResolver, NerveResolver,
PostnikovResolver, ResolverCategory, ResolverTuple, ShapeViolation,
};
use prism::uor_foundation::pipeline::__sdk_seal::Sealed;
use prism::uor_foundation::pipeline::shape_iri_registry::EmptyShapeRegistry;
use crate::hash::{AddrHash, MAX_LABEL_BYTES};
const HEX_LOWER: [u8; 16] = *b"0123456789abcdef";
fn kappa_label_carrier<const N: usize, H: AddrHash>(
input: &TermValue<'_, N>,
) -> TermValue<'static, N> {
let digest = H::digest_carrier(input);
let prefix = H::LABEL_PREFIX.as_bytes();
let p = prefix.len();
let mut out = [0u8; MAX_LABEL_BYTES];
out[..p].copy_from_slice(prefix);
out[p] = b':';
for (i, byte) in digest.iter().enumerate().take(H::OUTPUT_BYTES) {
out[p + 1 + 2 * i] = HEX_LOWER[(byte >> 4) as usize];
out[p + 1 + 2 * i + 1] = HEX_LOWER[(byte & 0x0F) as usize];
}
TermValue::inline_from_slice(&out[..H::LABEL_BYTES])
}
macro_rules! address_resolver {
($name:ident) => {
#[derive(Debug)]
pub struct $name<H>(PhantomData<H>);
impl<H> Sealed for $name<H> {}
impl<H> Default for $name<H> {
#[inline]
fn default() -> Self {
Self(PhantomData)
}
}
};
}
address_resolver!(AddressNerveResolver);
address_resolver!(AddressChainComplexResolver);
address_resolver!(AddressHomologyGroupResolver);
address_resolver!(AddressCochainComplexResolver);
address_resolver!(AddressCohomologyGroupResolver);
address_resolver!(AddressPostnikovResolver);
address_resolver!(AddressHomotopyGroupResolver);
address_resolver!(AddressKInvariantResolver);
macro_rules! passthrough_resolver {
($trait:ident, $name:ident) => {
impl<const N: usize, H> $trait<N, H> for $name<H> {
#[inline]
fn resolve<'a>(
&self,
input: TermValue<'a, N>,
) -> Result<TermValue<'a, N>, ShapeViolation> {
Ok(input)
}
}
};
}
passthrough_resolver!(NerveResolver, AddressNerveResolver);
passthrough_resolver!(ChainComplexResolver, AddressChainComplexResolver);
passthrough_resolver!(HomologyGroupResolver, AddressHomologyGroupResolver);
passthrough_resolver!(CochainComplexResolver, AddressCochainComplexResolver);
passthrough_resolver!(CohomologyGroupResolver, AddressCohomologyGroupResolver);
passthrough_resolver!(PostnikovResolver, AddressPostnikovResolver);
passthrough_resolver!(HomotopyGroupResolver, AddressHomotopyGroupResolver);
impl<const N: usize, H: AddrHash> KInvariantResolver<N, H> for AddressKInvariantResolver<H> {
#[inline]
fn resolve<'a>(&self, input: TermValue<'a, N>) -> Result<TermValue<'a, N>, ShapeViolation> {
Ok(kappa_label_carrier::<N, H>(&input))
}
}
pub struct AddressResolverTuple<H: AddrHash> {
pub nerve: AddressNerveResolver<H>,
pub chain_complex: AddressChainComplexResolver<H>,
pub homology_groups: AddressHomologyGroupResolver<H>,
pub cochain_complex: AddressCochainComplexResolver<H>,
pub cohomology_groups: AddressCohomologyGroupResolver<H>,
pub postnikov: AddressPostnikovResolver<H>,
pub homotopy_groups: AddressHomotopyGroupResolver<H>,
pub k_invariants: AddressKInvariantResolver<H>,
#[doc(hidden)]
pub _phantom: PhantomData<H>,
}
impl<H: AddrHash> Sealed for AddressResolverTuple<H> {}
impl<H: AddrHash> ResolverTuple for AddressResolverTuple<H> {
const ARITY: usize = 8;
const CATEGORIES: &'static [ResolverCategory] = &[
ResolverCategory::Nerve,
ResolverCategory::ChainComplex,
ResolverCategory::HomologyGroup,
ResolverCategory::CochainComplex,
ResolverCategory::CohomologyGroup,
ResolverCategory::Postnikov,
ResolverCategory::HomotopyGroup,
ResolverCategory::KInvariant,
];
type ShapeRegistry = EmptyShapeRegistry;
}
impl<H: AddrHash> Default for AddressResolverTuple<H> {
fn default() -> Self {
Self {
nerve: AddressNerveResolver::default(),
chain_complex: AddressChainComplexResolver::default(),
homology_groups: AddressHomologyGroupResolver::default(),
cochain_complex: AddressCochainComplexResolver::default(),
cohomology_groups: AddressCohomologyGroupResolver::default(),
postnikov: AddressPostnikovResolver::default(),
homotopy_groups: AddressHomotopyGroupResolver::default(),
k_invariants: AddressKInvariantResolver::default(),
_phantom: PhantomData,
}
}
}
macro_rules! has_resolver {
($marker:ident, $rtrait:ident, $accessor:ident, $field:ident) => {
impl<const N: usize, H: AddrHash> $marker<N, H> for AddressResolverTuple<H> {
fn $accessor(&self) -> &dyn $rtrait<N, H> {
&self.$field
}
}
};
}
has_resolver!(HasNerveResolver, NerveResolver, nerve_resolver, nerve);
has_resolver!(
HasChainComplexResolver,
ChainComplexResolver,
chain_complex_resolver,
chain_complex
);
has_resolver!(
HasHomologyGroupResolver,
HomologyGroupResolver,
homology_group_resolver,
homology_groups
);
has_resolver!(
HasCochainComplexResolver,
CochainComplexResolver,
cochain_complex_resolver,
cochain_complex
);
has_resolver!(
HasCohomologyGroupResolver,
CohomologyGroupResolver,
cohomology_group_resolver,
cohomology_groups
);
has_resolver!(
HasPostnikovResolver,
PostnikovResolver,
postnikov_resolver,
postnikov
);
has_resolver!(
HasHomotopyGroupResolver,
HomotopyGroupResolver,
homotopy_group_resolver,
homotopy_groups
);
has_resolver!(
HasKInvariantResolver,
KInvariantResolver,
k_invariant_resolver,
k_invariants
);