1use core::marker::PhantomData;
24
25use prism::operation::TermValue;
26use prism::pipeline::{
27 ChainComplexResolver, CochainComplexResolver, CohomologyGroupResolver, HasChainComplexResolver,
28 HasCochainComplexResolver, HasCohomologyGroupResolver, HasHomologyGroupResolver,
29 HasHomotopyGroupResolver, HasKInvariantResolver, HasNerveResolver, HasPostnikovResolver,
30 HomologyGroupResolver, HomotopyGroupResolver, KInvariantResolver, NerveResolver,
31 PostnikovResolver, ResolverCategory, ResolverTuple, ShapeViolation,
32};
33use prism::uor_foundation::pipeline::__sdk_seal::Sealed;
34use prism::uor_foundation::pipeline::shape_iri_registry::EmptyShapeRegistry;
35
36use crate::hash::{AddrHash, MAX_LABEL_BYTES};
37
38const HEX_LOWER: [u8; 16] = *b"0123456789abcdef";
39
40fn kappa_label_carrier<const N: usize, H: AddrHash>(
45 input: &TermValue<'_, N>,
46) -> TermValue<'static, N> {
47 let digest = H::digest_carrier(input);
48 let prefix = H::LABEL_PREFIX.as_bytes();
49 let p = prefix.len();
50 let mut out = [0u8; MAX_LABEL_BYTES];
51 out[..p].copy_from_slice(prefix);
52 out[p] = b':';
53 for (i, byte) in digest.iter().enumerate().take(H::OUTPUT_BYTES) {
54 out[p + 1 + 2 * i] = HEX_LOWER[(byte >> 4) as usize];
55 out[p + 1 + 2 * i + 1] = HEX_LOWER[(byte & 0x0F) as usize];
56 }
57 TermValue::inline_from_slice(&out[..H::LABEL_BYTES])
58}
59
60macro_rules! address_resolver {
65 ($name:ident) => {
66 #[derive(Debug)]
67 pub struct $name<H>(PhantomData<H>);
68 impl<H> Sealed for $name<H> {}
69 impl<H> Default for $name<H> {
70 #[inline]
71 fn default() -> Self {
72 Self(PhantomData)
73 }
74 }
75 };
76}
77
78address_resolver!(AddressNerveResolver);
79address_resolver!(AddressChainComplexResolver);
80address_resolver!(AddressHomologyGroupResolver);
81address_resolver!(AddressCochainComplexResolver);
82address_resolver!(AddressCohomologyGroupResolver);
83address_resolver!(AddressPostnikovResolver);
84address_resolver!(AddressHomotopyGroupResolver);
85address_resolver!(AddressKInvariantResolver);
86
87macro_rules! passthrough_resolver {
88 ($trait:ident, $name:ident) => {
89 impl<const N: usize, H> $trait<N, H> for $name<H> {
90 #[inline]
91 fn resolve<'a>(
92 &self,
93 input: TermValue<'a, N>,
94 ) -> Result<TermValue<'a, N>, ShapeViolation> {
95 Ok(input)
96 }
97 }
98 };
99}
100
101passthrough_resolver!(NerveResolver, AddressNerveResolver);
102passthrough_resolver!(ChainComplexResolver, AddressChainComplexResolver);
103passthrough_resolver!(HomologyGroupResolver, AddressHomologyGroupResolver);
104passthrough_resolver!(CochainComplexResolver, AddressCochainComplexResolver);
105passthrough_resolver!(CohomologyGroupResolver, AddressCohomologyGroupResolver);
106passthrough_resolver!(PostnikovResolver, AddressPostnikovResolver);
107passthrough_resolver!(HomotopyGroupResolver, AddressHomotopyGroupResolver);
108
109impl<const N: usize, H: AddrHash> KInvariantResolver<N, H> for AddressKInvariantResolver<H> {
110 #[inline]
111 fn resolve<'a>(&self, input: TermValue<'a, N>) -> Result<TermValue<'a, N>, ShapeViolation> {
112 Ok(kappa_label_carrier::<N, H>(&input))
116 }
117}
118
119pub struct AddressResolverTuple<H: AddrHash> {
124 pub nerve: AddressNerveResolver<H>,
126 pub chain_complex: AddressChainComplexResolver<H>,
128 pub homology_groups: AddressHomologyGroupResolver<H>,
130 pub cochain_complex: AddressCochainComplexResolver<H>,
132 pub cohomology_groups: AddressCohomologyGroupResolver<H>,
134 pub postnikov: AddressPostnikovResolver<H>,
136 pub homotopy_groups: AddressHomotopyGroupResolver<H>,
138 pub k_invariants: AddressKInvariantResolver<H>,
140 #[doc(hidden)]
141 pub _phantom: PhantomData<H>,
142}
143
144impl<H: AddrHash> Sealed for AddressResolverTuple<H> {}
145
146impl<H: AddrHash> ResolverTuple for AddressResolverTuple<H> {
147 const ARITY: usize = 8;
148 const CATEGORIES: &'static [ResolverCategory] = &[
149 ResolverCategory::Nerve,
150 ResolverCategory::ChainComplex,
151 ResolverCategory::HomologyGroup,
152 ResolverCategory::CochainComplex,
153 ResolverCategory::CohomologyGroup,
154 ResolverCategory::Postnikov,
155 ResolverCategory::HomotopyGroup,
156 ResolverCategory::KInvariant,
157 ];
158 type ShapeRegistry = EmptyShapeRegistry;
159}
160
161impl<H: AddrHash> Default for AddressResolverTuple<H> {
162 fn default() -> Self {
163 Self {
164 nerve: AddressNerveResolver::default(),
165 chain_complex: AddressChainComplexResolver::default(),
166 homology_groups: AddressHomologyGroupResolver::default(),
167 cochain_complex: AddressCochainComplexResolver::default(),
168 cohomology_groups: AddressCohomologyGroupResolver::default(),
169 postnikov: AddressPostnikovResolver::default(),
170 homotopy_groups: AddressHomotopyGroupResolver::default(),
171 k_invariants: AddressKInvariantResolver::default(),
172 _phantom: PhantomData,
173 }
174 }
175}
176
177macro_rules! has_resolver {
178 ($marker:ident, $rtrait:ident, $accessor:ident, $field:ident) => {
179 impl<const N: usize, H: AddrHash> $marker<N, H> for AddressResolverTuple<H> {
180 fn $accessor(&self) -> &dyn $rtrait<N, H> {
181 &self.$field
182 }
183 }
184 };
185}
186
187has_resolver!(HasNerveResolver, NerveResolver, nerve_resolver, nerve);
188has_resolver!(
189 HasChainComplexResolver,
190 ChainComplexResolver,
191 chain_complex_resolver,
192 chain_complex
193);
194has_resolver!(
195 HasHomologyGroupResolver,
196 HomologyGroupResolver,
197 homology_group_resolver,
198 homology_groups
199);
200has_resolver!(
201 HasCochainComplexResolver,
202 CochainComplexResolver,
203 cochain_complex_resolver,
204 cochain_complex
205);
206has_resolver!(
207 HasCohomologyGroupResolver,
208 CohomologyGroupResolver,
209 cohomology_group_resolver,
210 cohomology_groups
211);
212has_resolver!(
213 HasPostnikovResolver,
214 PostnikovResolver,
215 postnikov_resolver,
216 postnikov
217);
218has_resolver!(
219 HasHomotopyGroupResolver,
220 HomotopyGroupResolver,
221 homotopy_group_resolver,
222 homotopy_groups
223);
224has_resolver!(
225 HasKInvariantResolver,
226 KInvariantResolver,
227 k_invariant_resolver,
228 k_invariants
229);