Skip to main content

macroonz_compiler/kind/
type_guard.rs

1//! The kind home's invariant nucleus: the only road from a consumer-owned disposition record to a complete set witness.
2
3use super::{Disposition, DispositionRecord, DispositionSet, DispositionSetError, KindSet};
4use core::marker::PhantomData;
5
6impl<Set: KindSet> DispositionSet<Set> {
7    /// Check one set's disposition record and seal it as complete.
8    ///
9    /// # Errors
10    ///
11    /// Returns [`DispositionSetError::CountMismatch`] when the record surrenders fewer or more dispositions than [`KindSet::NAMES`] declares.
12    /// Returns [`DispositionSetError::KindMismatch`] when a surrendered row names a kind other than the kind declared at that position.
13    /// Nothing is truncated, padded, or inferred: silence remains unable to enter an account.
14    pub fn complete(record: Set::Dispositions) -> Result<Self, DispositionSetError> {
15        let rows: Vec<_> = record.into_dispositions().collect();
16        let expected = Set::NAMES.len();
17        let observed = rows.len();
18        if expected != observed {
19            return Err(DispositionSetError::CountMismatch { expected, observed });
20        }
21        for ((observed_name, _), expected_name) in rows.iter().zip(Set::NAMES.iter().copied()) {
22            if *observed_name != expected_name {
23                return Err(DispositionSetError::KindMismatch {
24                    expected: expected_name,
25                    observed: observed_name,
26                });
27            }
28        }
29        Ok(Self {
30            dispositions: rows
31                .into_iter()
32                .map(|(_name, disposition)| disposition)
33                .collect(),
34            kind_set: PhantomData,
35        })
36    }
37
38    /// The number of disposition rows, equal to this set's declared-name count by construction.
39    #[must_use]
40    pub const fn len(&self) -> usize {
41        self.dispositions.len()
42    }
43
44    /// Whether this complete set has no declared kinds and therefore no disposition rows.
45    #[must_use]
46    pub const fn is_empty(&self) -> bool {
47        self.dispositions.is_empty()
48    }
49
50    /// Every declared kind name paired with its disposition, in declaration order.
51    #[must_use]
52    pub fn iter(&self) -> impl ExactSizeIterator<Item = (&'static str, &Disposition)> {
53        Set::NAMES.iter().copied().zip(self.dispositions.iter())
54    }
55}