Skip to main content

macroonz_compiler/relation/
type_guard.rs

1//! The relation home's invariant nucleus: every road that reaches a private field.
2//!
3//! Declared inside `types.rs` as its own child so foreign endpoint references and repeated relation pairs are values a caller cannot forge.
4
5use super::{
6    CanonicalRelationPosition, KeyedRosterRelation, KeyedRosterRows, KeyedRosterRowsError,
7    ReferencedRosterRow, RelationPair, RepeatedRelationPair, RepeatedRelationPairs,
8    ResolvedRosterMember, RowResolutionError,
9};
10use crate::bounded::{Bounded, ForeignRosterReference, KeyedRoster, NonEmpty, NonEmptyError};
11use core::borrow::Borrow;
12
13impl<
14    'rosters,
15    Left,
16    LeftKey,
17    Right,
18    RightKey,
19    Payload,
20    const LEFT: usize,
21    const RIGHT: usize,
22    const ROWS: usize,
23> KeyedRosterRows<'rosters, Left, LeftKey, Right, RightKey, Payload, LEFT, RIGHT, ROWS>
24{
25    /// The left roster every row was resolved against.
26    #[must_use]
27    pub const fn left(&self) -> &'rosters KeyedRoster<Left, LeftKey, LEFT> {
28        self.left
29    }
30
31    /// The right roster every row was resolved against.
32    #[must_use]
33    pub const fn right(&self) -> &'rosters KeyedRoster<Right, RightKey, RIGHT> {
34        self.right
35    }
36
37    /// How many foreign-free rows are held.
38    #[must_use]
39    pub fn count(&self) -> usize {
40        self.rows.len()
41    }
42
43    /// Whether no relation row was declared.
44    #[must_use]
45    pub fn is_empty(&self) -> bool {
46        self.rows.is_empty()
47    }
48
49    /// Reads every authored row with both resolved roster members and its caller-owned payload.
50    pub fn indexed(
51        &self,
52    ) -> impl Iterator<Item = (usize, &LeftKey, &Left, &RightKey, &Right, &Payload)> {
53        self.rows.iter().enumerate().map(|(index, row)| {
54            (
55                index,
56                row.left_key,
57                row.left_member,
58                row.right_key,
59                row.right_member,
60                &row.payload,
61            )
62        })
63    }
64
65    /// Reads one authored row at a checked position.
66    #[must_use]
67    pub fn at(&self, index: usize) -> Option<(&LeftKey, &Left, &RightKey, &Right, &Payload)> {
68        self.rows.as_slice().get(index).map(|row| {
69            (
70                row.left_key,
71                row.left_member,
72                row.right_key,
73                row.right_member,
74                &row.payload,
75            )
76        })
77    }
78
79    /// The authored row indices in canonical left-position then right-position order.
80    ///
81    /// Equal endpoint pairs retain authored order until duplicate posture is settled.
82    #[must_use]
83    pub fn canonical_indices(&self) -> &[usize] {
84        self.canonical_indices.as_slice()
85    }
86
87    /// Reads one row by its canonical-order position.
88    #[must_use]
89    pub fn canonical_at(
90        &self,
91        index: usize,
92    ) -> Option<(&LeftKey, &Left, &RightKey, &Right, &Payload)> {
93        self.canonical_indices()
94            .get(index)
95            .and_then(|authored| self.at(*authored))
96    }
97
98    /// Reads every payload under one pair of borrowed roster keys.
99    pub fn payloads_for<'reading, LeftQuery, RightQuery>(
100        &'reading self,
101        left: &LeftQuery,
102        right: &RightQuery,
103    ) -> impl Iterator<Item = &'reading Payload>
104    where
105        LeftKey: Borrow<LeftQuery>,
106        LeftQuery: Eq + ?Sized,
107        RightKey: Borrow<RightQuery>,
108        RightQuery: Eq + ?Sized,
109    {
110        let left_position = self.left.index_of(left);
111        let right_position = self.right.index_of(right);
112        self.rows.iter().filter_map(move |row| {
113            (Some(row.left_position) == left_position && Some(row.right_position) == right_position)
114                .then_some(&row.payload)
115        })
116    }
117
118    /// Promote these foreign-free rows into a relation where every endpoint pair occurs once.
119    ///
120    /// # Errors
121    ///
122    /// Returns every distinct repeated endpoint pair with its first and later authored positions.
123    pub fn distinct(
124        self,
125    ) -> Result<
126        KeyedRosterRelation<'rosters, Left, LeftKey, Right, RightKey, Payload, LEFT, RIGHT, ROWS>,
127        RepeatedRelationPairs<ROWS>,
128    > {
129        match repeated_relation_pairs(&self) {
130            Some(repeated) => Err(repeated),
131            None => Ok(KeyedRosterRelation { rows: self }),
132        }
133    }
134}
135
136impl<
137    'rosters,
138    Left,
139    LeftKey: Eq,
140    Right,
141    RightKey: Eq,
142    Payload,
143    const LEFT: usize,
144    const RIGHT: usize,
145    const ROWS: usize,
146> KeyedRosterRows<'rosters, Left, LeftKey, Right, RightKey, Payload, LEFT, RIGHT, ROWS>
147{
148    /// Resolve one complete row offering against two existing keyed rosters.
149    ///
150    /// Row magnitude is settled before either endpoint projection runs.
151    /// Every left reference is settled before the right projection begins.
152    ///
153    /// # Errors
154    ///
155    /// Returns row overflow, every foreign left reference, or every foreign right reference under that precedence.
156    pub fn referenced(
157        left: &'rosters KeyedRoster<Left, LeftKey, LEFT>,
158        right: &'rosters KeyedRoster<Right, RightKey, RIGHT>,
159        payloads: Vec<Payload>,
160        left_key_of: impl FnMut(&Payload) -> LeftKey,
161        right_key_of: impl FnMut(&Payload) -> RightKey,
162    ) -> Result<Self, KeyedRosterRowsError<LeftKey, RightKey, ROWS>> {
163        let payloads = Bounded::new(payloads).map_err(KeyedRosterRowsError::Overflow)?;
164        let left_rows = resolve_rows(left, &payloads, left_key_of).map_err(left_refusal)?;
165        let right_rows = resolve_rows(right, &payloads, right_key_of).map_err(right_refusal)?;
166        let rows = payloads
167            .into_vec()
168            .into_iter()
169            .zip(left_rows)
170            .zip(right_rows)
171            .map(row_from_resolved)
172            .collect::<Vec<_>>();
173        let rows = Bounded::new(rows).map_err(KeyedRosterRowsError::Overflow)?;
174        let canonical_indices = canonical_indices(&rows)?;
175        Ok(Self {
176            left,
177            right,
178            rows,
179            canonical_indices,
180        })
181    }
182}
183
184impl<
185    'rosters,
186    Left,
187    LeftKey,
188    Right,
189    RightKey,
190    Payload,
191    const LEFT: usize,
192    const RIGHT: usize,
193    const ROWS: usize,
194> KeyedRosterRelation<'rosters, Left, LeftKey, Right, RightKey, Payload, LEFT, RIGHT, ROWS>
195{
196    /// The foreign-free authored rows whose endpoint pairs this relation proves distinct.
197    #[must_use]
198    pub const fn rows(
199        &self,
200    ) -> &KeyedRosterRows<'rosters, Left, LeftKey, Right, RightKey, Payload, LEFT, RIGHT, ROWS>
201    {
202        &self.rows
203    }
204
205    /// Recover the foreign-free row value where a later caller posture permits repetition.
206    #[must_use]
207    pub fn into_rows(
208        self,
209    ) -> KeyedRosterRows<'rosters, Left, LeftKey, Right, RightKey, Payload, LEFT, RIGHT, ROWS> {
210        self.rows
211    }
212}
213
214impl<const N: usize> RepeatedRelationPair<N> {
215    /// The resolved left-roster position of the repeated pair.
216    #[must_use]
217    pub const fn left_position(&self) -> usize {
218        self.duplicate.key().left
219    }
220
221    /// The resolved right-roster position of the repeated pair.
222    #[must_use]
223    pub const fn right_position(&self) -> usize {
224        self.duplicate.key().right
225    }
226
227    /// The pair's first authored row position.
228    #[must_use]
229    pub const fn first_position(&self) -> usize {
230        self.duplicate.first_position()
231    }
232
233    /// Every later authored row position carrying the same pair.
234    #[must_use]
235    pub const fn repeated_positions(&self) -> &NonEmpty<usize, N> {
236        self.duplicate.repeated_positions()
237    }
238}
239
240impl<const N: usize> RepeatedRelationPairs<N> {
241    /// Every distinct repeated pair in first-occurrence order.
242    pub fn iter(&self) -> impl Iterator<Item = &RepeatedRelationPair<N>> {
243        self.pairs.iter()
244    }
245
246    /// How many distinct endpoint pairs repeated.
247    #[must_use]
248    pub fn count(&self) -> usize {
249        self.pairs.count()
250    }
251}
252
253fn resolve_rows<'roster, Member, Key: Eq, Payload, const MEMBERS: usize, const ROWS: usize>(
254    roster: &'roster KeyedRoster<Member, Key, MEMBERS>,
255    payloads: &Bounded<Payload, ROWS>,
256    mut key_of: impl FnMut(&Payload) -> Key,
257) -> Result<Vec<ResolvedRosterMember<'roster, Member, Key>>, RowResolutionError<Key, ROWS>> {
258    let mut resolved = Vec::with_capacity(payloads.len());
259    let mut foreign = Vec::new();
260    for (offered_position, payload) in payloads.iter().enumerate() {
261        let key = key_of(payload);
262        match roster.indexed_get(&key) {
263            Some((position, retained, member)) => resolved.push(ResolvedRosterMember {
264                position,
265                key: retained,
266                member,
267            }),
268            None => foreign.push(ForeignRosterReference::at(key, offered_position)),
269        }
270    }
271    settle_resolved_rows(resolved, foreign)
272}
273
274fn settle_resolved_rows<Member, Key, const ROWS: usize>(
275    resolved: Vec<ResolvedRosterMember<'_, Member, Key>>,
276    foreign: Vec<ForeignRosterReference<Key>>,
277) -> Result<Vec<ResolvedRosterMember<'_, Member, Key>>, RowResolutionError<Key, ROWS>> {
278    match NonEmpty::new(foreign) {
279        Ok(foreign) => Err(RowResolutionError::Foreign(foreign)),
280        Err(NonEmptyError::Empty(_)) => Ok(resolved),
281        Err(NonEmptyError::Overflow(overflow)) => Err(RowResolutionError::Overflow(overflow)),
282    }
283}
284
285fn left_refusal<LeftKey, RightKey, const N: usize>(
286    refusal: RowResolutionError<LeftKey, N>,
287) -> KeyedRosterRowsError<LeftKey, RightKey, N> {
288    match refusal {
289        RowResolutionError::Overflow(overflow) => KeyedRosterRowsError::Overflow(overflow),
290        RowResolutionError::Foreign(foreign) => KeyedRosterRowsError::ForeignLeft(foreign),
291    }
292}
293
294fn right_refusal<LeftKey, RightKey, const N: usize>(
295    refusal: RowResolutionError<RightKey, N>,
296) -> KeyedRosterRowsError<LeftKey, RightKey, N> {
297    match refusal {
298        RowResolutionError::Overflow(overflow) => KeyedRosterRowsError::Overflow(overflow),
299        RowResolutionError::Foreign(foreign) => KeyedRosterRowsError::ForeignRight(foreign),
300    }
301}
302
303fn row_from_resolved<'rosters, Left, LeftKey, Right, RightKey, Payload>(
304    ((payload, left), right): (
305        (Payload, ResolvedRosterMember<'rosters, Left, LeftKey>),
306        ResolvedRosterMember<'rosters, Right, RightKey>,
307    ),
308) -> ReferencedRosterRow<'rosters, Left, LeftKey, Right, RightKey, Payload> {
309    ReferencedRosterRow {
310        left_position: left.position,
311        left_key: left.key,
312        left_member: left.member,
313        right_position: right.position,
314        right_key: right.key,
315        right_member: right.member,
316        payload,
317    }
318}
319
320fn canonical_indices<Left, LeftKey, Right, RightKey, Payload, const N: usize>(
321    rows: &Bounded<ReferencedRosterRow<'_, Left, LeftKey, Right, RightKey, Payload>, N>,
322) -> Result<Bounded<usize, N>, KeyedRosterRowsError<LeftKey, RightKey, N>> {
323    let mut canonical = rows
324        .iter()
325        .enumerate()
326        .map(|(authored, row)| CanonicalRelationPosition {
327            authored,
328            left: row.left_position,
329            right: row.right_position,
330        })
331        .collect::<Vec<_>>();
332    canonical.sort_by_key(|position| (position.left, position.right, position.authored));
333    Bounded::new(
334        canonical
335            .into_iter()
336            .map(|position| position.authored)
337            .collect(),
338    )
339    .map_err(KeyedRosterRowsError::Overflow)
340}
341
342fn repeated_relation_pairs<
343    Left,
344    LeftKey,
345    Right,
346    RightKey,
347    Payload,
348    const LEFT: usize,
349    const RIGHT: usize,
350    const ROWS: usize,
351>(
352    rows: &KeyedRosterRows<'_, Left, LeftKey, Right, RightKey, Payload, LEFT, RIGHT, ROWS>,
353) -> Option<RepeatedRelationPairs<ROWS>> {
354    let pairs = rows.rows.mapped(|row| RelationPair {
355        left: row.left_position,
356        right: row.right_position,
357    });
358    let pairs = NonEmpty::from_bounded(pairs).ok()?;
359    let duplicates = pairs.duplicate_keys()?;
360    Some(RepeatedRelationPairs {
361        pairs: duplicates.mapped(|duplicate| RepeatedRelationPair { duplicate }),
362    })
363}