1use crate::{
2 merkle::{Family, Location, Proof},
3 qmdb::{
4 self,
5 any::{
6 ordered::{
7 fixed::{Db as OrderedFixedDb, Operation as OrderedFixedOperation},
8 variable::{Db as OrderedVariableDb, Operation as OrderedVariableOperation},
9 },
10 unordered::{
11 fixed::{Db as FixedDb, Operation as FixedOperation},
12 variable::{Db as VariableDb, Operation as VariableOperation},
13 },
14 FixedValue, VariableValue,
15 },
16 immutable::{
17 fixed::{Db as ImmutableFixedDb, Operation as ImmutableFixedOp},
18 variable::{Db as ImmutableVariableDb, Operation as ImmutableVariableOp},
19 },
20 keyless::{
21 fixed::{Db as KeylessFixedDb, Operation as KeylessFixedOp},
22 variable::{Db as KeylessVariableDb, Operation as KeylessVariableOp},
23 },
24 operation::Key,
25 },
26 translator::Translator,
27 Context,
28};
29use commonware_cryptography::{Digest, Hasher};
30use commonware_parallel::Strategy;
31use commonware_utils::{channel::oneshot, sync::AsyncRwLock, Array};
32use std::{future::Future, num::NonZeroU64, sync::Arc};
33
34pub struct FetchResult<F: Family, Op, D: Digest> {
36 pub proof: Proof<F, D>,
38 pub operations: Vec<Op>,
40 pub pinned_nodes: Option<Vec<D>>,
42 pub callback: Option<oneshot::Sender<bool>>,
44}
45
46impl<F: Family, Op, D: Digest> FetchResult<F, Op, D> {
47 pub const fn new(
49 proof: Proof<F, D>,
50 operations: Vec<Op>,
51 pinned_nodes: Option<Vec<D>>,
52 ) -> Self {
53 Self {
54 proof,
55 operations,
56 pinned_nodes,
57 callback: None,
58 }
59 }
60
61 pub const fn with_callback(
63 proof: Proof<F, D>,
64 operations: Vec<Op>,
65 pinned_nodes: Option<Vec<D>>,
66 callback: oneshot::Sender<bool>,
67 ) -> Self {
68 Self {
69 proof,
70 operations,
71 pinned_nodes,
72 callback: Some(callback),
73 }
74 }
75}
76
77pub struct FetchedOperations<F: Family, Op, D: Digest> {
79 pub proof: Proof<F, D>,
81 pub operations: Vec<Op>,
83 pub pinned_nodes: Option<Vec<D>>,
85}
86
87impl<F: Family, Op, D: Digest> FetchedOperations<F, Op, D> {
88 pub const fn new(
90 proof: Proof<F, D>,
91 operations: Vec<Op>,
92 pinned_nodes: Option<Vec<D>>,
93 ) -> Self {
94 Self {
95 proof,
96 operations,
97 pinned_nodes,
98 }
99 }
100}
101
102impl<F: Family, Op: std::fmt::Debug, D: Digest> std::fmt::Debug for FetchResult<F, Op, D> {
103 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104 f.debug_struct("FetchResult")
105 .field("proof", &self.proof)
106 .field("operations", &self.operations)
107 .field("pinned_nodes", &self.pinned_nodes)
108 .field("callback", &self.callback.as_ref().map(|_| "<callback>"))
109 .finish()
110 }
111}
112
113pub async fn fetch_operation_range<F, Op, D, Error, Fetch, FetchFuture>(
119 op_count: Location<F>,
120 start_loc: Location<F>,
121 max_ops: NonZeroU64,
122 include_pinned_nodes: bool,
123 fetch: Fetch,
124) -> Result<FetchResult<F, Op, D>, Error>
125where
126 F: Family,
127 D: Digest,
128 Fetch: FnOnce(Location<F>, Location<F>, NonZeroU64, bool) -> FetchFuture,
129 FetchFuture: Future<Output = Result<FetchedOperations<F, Op, D>, Error>>,
130{
131 let FetchedOperations {
132 proof,
133 operations,
134 pinned_nodes,
135 } = fetch(op_count, start_loc, max_ops, include_pinned_nodes).await?;
136 Ok(FetchResult::new(proof, operations, pinned_nodes))
137}
138
139pub async fn fetch_operations<
145 F,
146 Op,
147 D,
148 Error,
149 HistoricalProof,
150 HistoricalFuture,
151 Pins,
152 PinsFuture,
153>(
154 op_count: Location<F>,
155 start_loc: Location<F>,
156 max_ops: NonZeroU64,
157 include_pinned_nodes: bool,
158 historical_proof: HistoricalProof,
159 pinned_nodes_at: Pins,
160) -> Result<FetchResult<F, Op, D>, Error>
161where
162 F: Family,
163 D: Digest,
164 HistoricalProof: FnOnce(Location<F>, Location<F>, NonZeroU64) -> HistoricalFuture,
165 HistoricalFuture: Future<Output = Result<(Proof<F, D>, Vec<Op>), Error>>,
166 Pins: FnOnce(Location<F>) -> PinsFuture,
167 PinsFuture: Future<Output = Result<Vec<D>, Error>>,
168{
169 fetch_operation_range(
170 op_count,
171 start_loc,
172 max_ops,
173 include_pinned_nodes,
174 |op_count, start_loc, max_ops, include_pinned_nodes| async move {
175 let (proof, operations) = historical_proof(op_count, start_loc, max_ops).await?;
176 let pinned_nodes = if include_pinned_nodes {
177 Some(pinned_nodes_at(start_loc).await?)
178 } else {
179 None
180 };
181 Ok(FetchedOperations::new(proof, operations, pinned_nodes))
182 },
183 )
184 .await
185}
186
187pub trait Resolver: Send + Sync + Clone + 'static {
189 type Family: Family;
191
192 type Digest: Digest;
194
195 type Op;
197
198 type Error: std::error::Error + Send + 'static;
200
201 #[allow(clippy::type_complexity)]
210 fn get_operations<'a>(
211 &'a self,
212 op_count: Location<Self::Family>,
213 start_loc: Location<Self::Family>,
214 max_ops: NonZeroU64,
215 include_pinned_nodes: bool,
216 cancel_rx: oneshot::Receiver<()>,
217 ) -> impl Future<Output = Result<FetchResult<Self::Family, Self::Op, Self::Digest>, Self::Error>>
218 + Send
219 + 'a;
220}
221
222macro_rules! impl_resolver {
223 ($db:ident, $op:ident, $val_bound:ident) => {
224 impl<F, E, K, V, H, T, S> Resolver for Arc<$db<F, E, K, V, H, T, S>>
225 where
226 F: Family,
227 E: Context,
228 K: Array,
229 V: $val_bound + Send + Sync + 'static,
230 H: Hasher,
231 T: Translator + Send + Sync + 'static,
232 T::Key: Send + Sync,
233 S: Strategy,
234 {
235 type Family = F;
236 type Digest = H::Digest;
237 type Op = $op<F, K, V>;
238 type Error = qmdb::Error<F>;
239
240 async fn get_operations(
241 &self,
242 op_count: Location<Self::Family>,
243 start_loc: Location<Self::Family>,
244 max_ops: NonZeroU64,
245 include_pinned_nodes: bool,
246 _cancel_rx: oneshot::Receiver<()>,
247 ) -> Result<FetchResult<Self::Family, Self::Op, Self::Digest>, Self::Error> {
248 fetch_operations(
249 op_count,
250 start_loc,
251 max_ops,
252 include_pinned_nodes,
253 |op_count, start_loc, max_ops| {
254 self.historical_proof(op_count, start_loc, max_ops)
255 },
256 |start_loc| self.pinned_nodes_at(start_loc),
257 )
258 .await
259 }
260 }
261
262 impl<F, E, K, V, H, T, S> Resolver for Arc<AsyncRwLock<$db<F, E, K, V, H, T, S>>>
263 where
264 F: Family,
265 E: Context,
266 K: Array,
267 V: $val_bound + Send + Sync + 'static,
268 H: Hasher,
269 T: Translator + Send + Sync + 'static,
270 T::Key: Send + Sync,
271 S: Strategy,
272 {
273 type Family = F;
274 type Digest = H::Digest;
275 type Op = $op<F, K, V>;
276 type Error = qmdb::Error<F>;
277
278 async fn get_operations(
279 &self,
280 op_count: Location<Self::Family>,
281 start_loc: Location<Self::Family>,
282 max_ops: NonZeroU64,
283 include_pinned_nodes: bool,
284 _cancel_rx: oneshot::Receiver<()>,
285 ) -> Result<FetchResult<Self::Family, Self::Op, Self::Digest>, Self::Error> {
286 let db = self.read().await;
287 fetch_operations(
288 op_count,
289 start_loc,
290 max_ops,
291 include_pinned_nodes,
292 |op_count, start_loc, max_ops| {
293 db.historical_proof(op_count, start_loc, max_ops)
294 },
295 |start_loc| db.pinned_nodes_at(start_loc),
296 )
297 .await
298 }
299 }
300
301 impl<F, E, K, V, H, T, S> Resolver for Arc<AsyncRwLock<Option<$db<F, E, K, V, H, T, S>>>>
302 where
303 F: Family,
304 E: Context,
305 K: Array,
306 V: $val_bound + Send + Sync + 'static,
307 H: Hasher,
308 T: Translator + Send + Sync + 'static,
309 T::Key: Send + Sync,
310 S: Strategy,
311 {
312 type Family = F;
313 type Digest = H::Digest;
314 type Op = $op<F, K, V>;
315 type Error = qmdb::Error<F>;
316
317 async fn get_operations(
318 &self,
319 op_count: Location<Self::Family>,
320 start_loc: Location<Self::Family>,
321 max_ops: NonZeroU64,
322 include_pinned_nodes: bool,
323 _cancel_rx: oneshot::Receiver<()>,
324 ) -> Result<FetchResult<Self::Family, Self::Op, Self::Digest>, Self::Error> {
325 let guard = self.read().await;
326 let db = guard.as_ref().ok_or(qmdb::Error::KeyNotFound)?;
327 fetch_operations(
328 op_count,
329 start_loc,
330 max_ops,
331 include_pinned_nodes,
332 |op_count, start_loc, max_ops| {
333 db.historical_proof(op_count, start_loc, max_ops)
334 },
335 |start_loc| db.pinned_nodes_at(start_loc),
336 )
337 .await
338 }
339 }
340 };
341}
342
343impl_resolver!(FixedDb, FixedOperation, FixedValue);
345
346impl_resolver!(VariableDb, VariableOperation, VariableValue);
348
349impl_resolver!(OrderedFixedDb, OrderedFixedOperation, FixedValue);
351
352impl_resolver!(OrderedVariableDb, OrderedVariableOperation, VariableValue);
354
355macro_rules! impl_resolver_immutable {
359 ($db:ident, $op:ident, $val_bound:ident, $key_bound:path) => {
360 impl<F, E, K, V, H, T, S> Resolver for Arc<$db<F, E, K, V, H, T, S>>
361 where
362 F: Family,
363 E: Context,
364 K: $key_bound,
365 V: $val_bound + Send + Sync + 'static,
366 H: Hasher,
367 T: Translator + Send + Sync + 'static,
368 T::Key: Send + Sync,
369 S: Strategy,
370 {
371 type Family = F;
372 type Digest = H::Digest;
373 type Op = $op<F, K, V>;
374 type Error = qmdb::Error<F>;
375
376 async fn get_operations(
377 &self,
378 op_count: Location<Self::Family>,
379 start_loc: Location<Self::Family>,
380 max_ops: NonZeroU64,
381 include_pinned_nodes: bool,
382 _cancel_rx: oneshot::Receiver<()>,
383 ) -> Result<FetchResult<Self::Family, Self::Op, Self::Digest>, Self::Error> {
384 fetch_operations(
385 op_count,
386 start_loc,
387 max_ops,
388 include_pinned_nodes,
389 |op_count, start_loc, max_ops| {
390 self.historical_proof(op_count, start_loc, max_ops)
391 },
392 |start_loc| self.pinned_nodes_at(start_loc),
393 )
394 .await
395 }
396 }
397
398 impl<F, E, K, V, H, T, S> Resolver for Arc<AsyncRwLock<$db<F, E, K, V, H, T, S>>>
399 where
400 F: Family,
401 E: Context,
402 K: $key_bound,
403 V: $val_bound + Send + Sync + 'static,
404 H: Hasher,
405 T: Translator + Send + Sync + 'static,
406 T::Key: Send + Sync,
407 S: Strategy,
408 {
409 type Family = F;
410 type Digest = H::Digest;
411 type Op = $op<F, K, V>;
412 type Error = qmdb::Error<F>;
413
414 async fn get_operations(
415 &self,
416 op_count: Location<Self::Family>,
417 start_loc: Location<Self::Family>,
418 max_ops: NonZeroU64,
419 include_pinned_nodes: bool,
420 _cancel_rx: oneshot::Receiver<()>,
421 ) -> Result<FetchResult<Self::Family, Self::Op, Self::Digest>, Self::Error> {
422 let db = self.read().await;
423 fetch_operations(
424 op_count,
425 start_loc,
426 max_ops,
427 include_pinned_nodes,
428 |op_count, start_loc, max_ops| {
429 db.historical_proof(op_count, start_loc, max_ops)
430 },
431 |start_loc| db.pinned_nodes_at(start_loc),
432 )
433 .await
434 }
435 }
436
437 impl<F, E, K, V, H, T, S> Resolver for Arc<AsyncRwLock<Option<$db<F, E, K, V, H, T, S>>>>
438 where
439 F: Family,
440 E: Context,
441 K: $key_bound,
442 V: $val_bound + Send + Sync + 'static,
443 H: Hasher,
444 T: Translator + Send + Sync + 'static,
445 T::Key: Send + Sync,
446 S: Strategy,
447 {
448 type Family = F;
449 type Digest = H::Digest;
450 type Op = $op<F, K, V>;
451 type Error = qmdb::Error<F>;
452
453 async fn get_operations(
454 &self,
455 op_count: Location<Self::Family>,
456 start_loc: Location<Self::Family>,
457 max_ops: NonZeroU64,
458 include_pinned_nodes: bool,
459 _cancel_rx: oneshot::Receiver<()>,
460 ) -> Result<FetchResult<Self::Family, Self::Op, Self::Digest>, Self::Error> {
461 let guard = self.read().await;
462 let db = guard.as_ref().ok_or(qmdb::Error::KeyNotFound)?;
463 fetch_operations(
464 op_count,
465 start_loc,
466 max_ops,
467 include_pinned_nodes,
468 |op_count, start_loc, max_ops| {
469 db.historical_proof(op_count, start_loc, max_ops)
470 },
471 |start_loc| db.pinned_nodes_at(start_loc),
472 )
473 .await
474 }
475 }
476 };
477}
478
479impl_resolver_immutable!(ImmutableFixedDb, ImmutableFixedOp, FixedValue, Array);
481
482impl_resolver_immutable!(ImmutableVariableDb, ImmutableVariableOp, VariableValue, Key);
484
485macro_rules! impl_resolver_keyless {
487 ($db:ident, $op:ident, $val_bound:ident) => {
488 impl<F, E, V, H, S> Resolver for Arc<$db<F, E, V, H, S>>
489 where
490 F: Family,
491 E: Context,
492 V: $val_bound + Send + Sync + 'static,
493 H: Hasher,
494 S: Strategy,
495 {
496 type Family = F;
497 type Digest = H::Digest;
498 type Op = $op<F, V>;
499 type Error = qmdb::Error<F>;
500
501 async fn get_operations(
502 &self,
503 op_count: Location<Self::Family>,
504 start_loc: Location<Self::Family>,
505 max_ops: NonZeroU64,
506 include_pinned_nodes: bool,
507 _cancel_rx: oneshot::Receiver<()>,
508 ) -> Result<FetchResult<Self::Family, Self::Op, Self::Digest>, Self::Error> {
509 fetch_operations(
510 op_count,
511 start_loc,
512 max_ops,
513 include_pinned_nodes,
514 |op_count, start_loc, max_ops| {
515 self.historical_proof(op_count, start_loc, max_ops)
516 },
517 |start_loc| self.pinned_nodes_at(start_loc),
518 )
519 .await
520 }
521 }
522
523 impl<F, E, V, H, S> Resolver for Arc<AsyncRwLock<$db<F, E, V, H, S>>>
524 where
525 F: Family,
526 E: Context,
527 V: $val_bound + Send + Sync + 'static,
528 H: Hasher,
529 S: Strategy,
530 {
531 type Family = F;
532 type Digest = H::Digest;
533 type Op = $op<F, V>;
534 type Error = qmdb::Error<F>;
535
536 async fn get_operations(
537 &self,
538 op_count: Location<Self::Family>,
539 start_loc: Location<Self::Family>,
540 max_ops: NonZeroU64,
541 include_pinned_nodes: bool,
542 _cancel_rx: oneshot::Receiver<()>,
543 ) -> Result<FetchResult<Self::Family, Self::Op, Self::Digest>, Self::Error> {
544 let db = self.read().await;
545 fetch_operations(
546 op_count,
547 start_loc,
548 max_ops,
549 include_pinned_nodes,
550 |op_count, start_loc, max_ops| {
551 db.historical_proof(op_count, start_loc, max_ops)
552 },
553 |start_loc| db.pinned_nodes_at(start_loc),
554 )
555 .await
556 }
557 }
558
559 impl<F, E, V, H, S> Resolver for Arc<AsyncRwLock<Option<$db<F, E, V, H, S>>>>
560 where
561 F: Family,
562 E: Context,
563 V: $val_bound + Send + Sync + 'static,
564 H: Hasher,
565 S: Strategy,
566 {
567 type Family = F;
568 type Digest = H::Digest;
569 type Op = $op<F, V>;
570 type Error = qmdb::Error<F>;
571
572 async fn get_operations(
573 &self,
574 op_count: Location<Self::Family>,
575 start_loc: Location<Self::Family>,
576 max_ops: NonZeroU64,
577 include_pinned_nodes: bool,
578 _cancel_rx: oneshot::Receiver<()>,
579 ) -> Result<FetchResult<Self::Family, Self::Op, Self::Digest>, Self::Error> {
580 let guard = self.read().await;
581 let db = guard.as_ref().ok_or(qmdb::Error::KeyNotFound)?;
582 fetch_operations(
583 op_count,
584 start_loc,
585 max_ops,
586 include_pinned_nodes,
587 |op_count, start_loc, max_ops| {
588 db.historical_proof(op_count, start_loc, max_ops)
589 },
590 |start_loc| db.pinned_nodes_at(start_loc),
591 )
592 .await
593 }
594 }
595 };
596}
597
598impl_resolver_keyless!(KeylessFixedDb, KeylessFixedOp, FixedValue);
600
601impl_resolver_keyless!(KeylessVariableDb, KeylessVariableOp, VariableValue);
603
604#[cfg(test)]
605pub(crate) mod tests {
606 use super::*;
607 use crate::{
608 merkle::mmr,
609 translator::{OneCap, TwoCap},
610 };
611 use commonware_cryptography::{sha256::Digest as ShaDigest, Sha256};
612 use commonware_parallel::Rayon;
613 use commonware_runtime::deterministic;
614 use commonware_utils::sync::AsyncRwLock;
615 use std::{marker::PhantomData, sync::Arc};
616
617 macro_rules! assert_resolver_variants {
618 ($db:ty) => {
619 assert_resolver::<Arc<$db>>();
620 assert_resolver::<Arc<AsyncRwLock<$db>>>();
621 assert_resolver::<Arc<AsyncRwLock<Option<$db>>>>();
622 };
623 }
624
625 fn assert_resolver<R: Resolver>() {}
626
627 fn empty_proof() -> Proof<mmr::Family, ShaDigest> {
628 Proof {
629 leaves: Location::new(0),
630 inactive_peaks: 0,
631 digests: vec![],
632 }
633 }
634
635 #[test]
636 fn test_fetch_result_new_has_no_success_acknowledgement() {
637 let result = FetchResult::<mmr::Family, (), ShaDigest>::new(empty_proof(), vec![], None);
638 assert!(result.callback.is_none());
639 }
640
641 #[test]
642 fn test_fetch_result_with_callback_reports_to_external_receiver() {
643 let (success_tx, mut success_rx) = oneshot::channel();
644 let result = FetchResult::<mmr::Family, (), ShaDigest>::with_callback(
645 empty_proof(),
646 vec![],
647 None,
648 success_tx,
649 );
650 assert!(result.callback.expect("success sender").send(true).is_ok());
651 assert_eq!(success_rx.try_recv(), Ok(true));
652 }
653
654 #[derive(Clone)]
656 pub struct FailResolver<F: Family, Op, D> {
657 _phantom: PhantomData<(F, Op, D)>,
658 }
659
660 impl<F, Op, D> Resolver for FailResolver<F, Op, D>
661 where
662 F: Family,
663 D: Digest,
664 Op: Send + Sync + Clone + 'static,
665 {
666 type Family = F;
667 type Digest = D;
668 type Op = Op;
669 type Error = qmdb::Error<F>;
670
671 async fn get_operations(
672 &self,
673 _op_count: Location<F>,
674 _start_loc: Location<F>,
675 _max_ops: NonZeroU64,
676 _include_pinned_nodes: bool,
677 _cancel: oneshot::Receiver<()>,
678 ) -> Result<FetchResult<F, Op, D>, qmdb::Error<F>> {
679 Err(qmdb::Error::KeyNotFound) }
681 }
682
683 impl<F: Family, Op, D> FailResolver<F, Op, D> {
684 pub fn new() -> Self {
685 Self {
686 _phantom: PhantomData,
687 }
688 }
689 }
690
691 #[test]
692 fn test_all_qmdb_variants_implement_strategy_resolvers() {
693 type AnyOrderedFixed = crate::qmdb::any::ordered::fixed::Db<
694 mmr::Family,
695 deterministic::Context,
696 ShaDigest,
697 ShaDigest,
698 Sha256,
699 OneCap,
700 Rayon,
701 >;
702 type AnyOrderedVariable = crate::qmdb::any::ordered::variable::Db<
703 mmr::Family,
704 deterministic::Context,
705 ShaDigest,
706 Vec<u8>,
707 Sha256,
708 OneCap,
709 Rayon,
710 >;
711 type AnyUnorderedFixed = crate::qmdb::any::unordered::fixed::Db<
712 mmr::Family,
713 deterministic::Context,
714 ShaDigest,
715 ShaDigest,
716 Sha256,
717 TwoCap,
718 Rayon,
719 >;
720 type AnyUnorderedVariable = crate::qmdb::any::unordered::variable::Db<
721 mmr::Family,
722 deterministic::Context,
723 ShaDigest,
724 Vec<u8>,
725 Sha256,
726 TwoCap,
727 Rayon,
728 >;
729 type CurrentOrderedFixed = crate::qmdb::current::ordered::fixed::Db<
730 mmr::Family,
731 deterministic::Context,
732 ShaDigest,
733 ShaDigest,
734 Sha256,
735 OneCap,
736 32,
737 Rayon,
738 >;
739 type CurrentOrderedVariable = crate::qmdb::current::ordered::variable::Db<
740 mmr::Family,
741 deterministic::Context,
742 ShaDigest,
743 Vec<u8>,
744 Sha256,
745 OneCap,
746 32,
747 Rayon,
748 >;
749 type CurrentUnorderedFixed = crate::qmdb::current::unordered::fixed::Db<
750 mmr::Family,
751 deterministic::Context,
752 ShaDigest,
753 ShaDigest,
754 Sha256,
755 TwoCap,
756 32,
757 Rayon,
758 >;
759 type CurrentUnorderedVariable = crate::qmdb::current::unordered::variable::Db<
760 mmr::Family,
761 deterministic::Context,
762 ShaDigest,
763 Vec<u8>,
764 Sha256,
765 TwoCap,
766 32,
767 Rayon,
768 >;
769 type ImmutableFixed = crate::qmdb::immutable::fixed::Db<
770 mmr::Family,
771 deterministic::Context,
772 ShaDigest,
773 ShaDigest,
774 Sha256,
775 TwoCap,
776 Rayon,
777 >;
778 type ImmutableVariable = crate::qmdb::immutable::variable::Db<
779 mmr::Family,
780 deterministic::Context,
781 ShaDigest,
782 Vec<u8>,
783 Sha256,
784 TwoCap,
785 Rayon,
786 >;
787 type KeylessFixed = crate::qmdb::keyless::fixed::Db<
788 mmr::Family,
789 deterministic::Context,
790 ShaDigest,
791 Sha256,
792 Rayon,
793 >;
794 type KeylessVariable = crate::qmdb::keyless::variable::Db<
795 mmr::Family,
796 deterministic::Context,
797 Vec<u8>,
798 Sha256,
799 Rayon,
800 >;
801
802 assert_resolver_variants!(AnyOrderedFixed);
803 assert_resolver_variants!(AnyOrderedVariable);
804 assert_resolver_variants!(AnyUnorderedFixed);
805 assert_resolver_variants!(AnyUnorderedVariable);
806 assert_resolver_variants!(CurrentOrderedFixed);
807 assert_resolver_variants!(CurrentOrderedVariable);
808 assert_resolver_variants!(CurrentUnorderedFixed);
809 assert_resolver_variants!(CurrentUnorderedVariable);
810 assert_resolver_variants!(ImmutableFixed);
811 assert_resolver_variants!(ImmutableVariable);
812 assert_resolver_variants!(KeylessFixed);
813 assert_resolver_variants!(KeylessVariable);
814 }
815}