Skip to main content

vyre_runtime/megakernel/
workspace_layout.rs

1//! Generic resident workspace region layout for megakernel adapters.
2//!
3//! Domain adapters own their region identifiers and capacity policy. Runtime
4//! owns the checked contiguous-layout arithmetic because every resident
5//! megakernel workspace has the same ABI shape: ordered u32-word regions with
6//! fixed record widths and explicit capacities.
7
8/// One contiguous u32-word region inside a resident megakernel workspace.
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub struct MegakernelWorkspaceRegion<R> {
11    /// Domain-owned region id encoded in the workspace manifest.
12    pub id: R,
13    /// Offset from workspace word zero.
14    pub offset_words: u32,
15    /// Total words reserved for the region.
16    pub words: u32,
17    /// Words in one logical record for this region.
18    pub record_words: u32,
19    /// Logical record capacity for this region.
20    pub capacity_records: u32,
21}
22
23/// Declarative region specification for bulk resident-workspace layout.
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub enum MegakernelWorkspaceRegionSpec<R> {
26    /// Region whose total word count is already known.
27    Fixed {
28        /// Domain-owned region id encoded in the workspace manifest.
29        id: R,
30        /// Total words reserved for the region.
31        words: u32,
32        /// Words in one logical record for this region.
33        record_words: u32,
34        /// Logical record capacity for this region.
35        capacity_records: u32,
36    },
37    /// Region sized as `record_words * capacity_records`.
38    Record {
39        /// Domain-owned region id encoded in the workspace manifest.
40        id: R,
41        /// Words in one logical record for this region.
42        record_words: u32,
43        /// Logical record capacity for this region.
44        capacity_records: u32,
45    },
46}
47
48impl<R> MegakernelWorkspaceRegionSpec<R> {
49    /// Build a fixed-size region specification.
50    #[must_use]
51    pub const fn fixed(id: R, words: u32, record_words: u32, capacity_records: u32) -> Self {
52        Self::Fixed {
53            id,
54            words,
55            record_words,
56            capacity_records,
57        }
58    }
59
60    /// Build a record-backed region specification.
61    #[must_use]
62    pub const fn record(id: R, record_words: u32, capacity_records: u32) -> Self {
63        Self::Record {
64            id,
65            record_words,
66            capacity_records,
67        }
68    }
69}
70
71/// Error returned by bulk resident-workspace layout planning.
72#[derive(Debug, Clone, Copy, PartialEq, Eq)]
73pub enum MegakernelWorkspaceLayoutError<R> {
74    /// `record_words * capacity_records` overflowed for this record-backed region.
75    RecordWordsOverflow {
76        /// Region whose record arena overflowed.
77        region: R,
78    },
79    /// Contiguous region offset arithmetic overflowed for this region.
80    OffsetOverflow {
81        /// Region whose starting offset could not fit the accumulated layout.
82        region: R,
83    },
84}
85
86impl<R: Copy> MegakernelWorkspaceRegion<R> {
87    /// Exclusive end offset for this region.
88    #[must_use]
89    pub const fn end_words(self) -> Option<u32> {
90        self.offset_words.checked_add(self.words)
91    }
92}
93
94/// Return `record_words * capacity_records` for a record-backed region.
95#[must_use]
96pub const fn workspace_record_words(record_words: u32, capacity_records: u32) -> Option<u32> {
97    record_words.checked_mul(capacity_records)
98}
99
100/// Build the first region in a resident workspace.
101#[must_use]
102pub const fn first_workspace_region<R>(
103    id: R,
104    words: u32,
105    record_words: u32,
106    capacity_records: u32,
107) -> MegakernelWorkspaceRegion<R> {
108    MegakernelWorkspaceRegion {
109        id,
110        offset_words: 0,
111        words,
112        record_words,
113        capacity_records,
114    }
115}
116
117/// Build the next contiguous region after `previous`.
118#[must_use]
119pub fn next_workspace_region<R: Copy>(
120    previous: MegakernelWorkspaceRegion<R>,
121    id: R,
122    words: u32,
123    record_words: u32,
124    capacity_records: u32,
125) -> Option<MegakernelWorkspaceRegion<R>> {
126    Some(MegakernelWorkspaceRegion {
127        id,
128        offset_words: previous.end_words()?,
129        words,
130        record_words,
131        capacity_records,
132    })
133}
134
135/// Build the next contiguous record-backed region after `previous`.
136#[must_use]
137pub fn next_record_workspace_region<R: Copy>(
138    previous: MegakernelWorkspaceRegion<R>,
139    id: R,
140    record_words: u32,
141    capacity_records: u32,
142) -> Option<MegakernelWorkspaceRegion<R>> {
143    next_workspace_region(
144        previous,
145        id,
146        workspace_record_words(record_words, capacity_records)?,
147        record_words,
148        capacity_records,
149    )
150}
151
152/// Build a contiguous resident-workspace layout from declarative specs.
153///
154/// This is the generic seam domain adapters should use when they own many
155/// regions. It centralizes checked record multiplication and checked offset
156/// accumulation in `vyre-runtime`, while each adapter keeps its own region ids
157/// and capacity policy.
158pub fn build_workspace_regions<R: Copy>(
159    specs: &[MegakernelWorkspaceRegionSpec<R>],
160) -> Result<Vec<MegakernelWorkspaceRegion<R>>, MegakernelWorkspaceLayoutError<R>> {
161    let mut regions = Vec::with_capacity(specs.len());
162    let mut next_offset_words = 0_u32;
163
164    for spec in specs {
165        let (id, words, record_words, capacity_records) = match *spec {
166            MegakernelWorkspaceRegionSpec::Fixed {
167                id,
168                words,
169                record_words,
170                capacity_records,
171            } => (id, words, record_words, capacity_records),
172            MegakernelWorkspaceRegionSpec::Record {
173                id,
174                record_words,
175                capacity_records,
176            } => {
177                let words = workspace_record_words(record_words, capacity_records)
178                    .ok_or(MegakernelWorkspaceLayoutError::RecordWordsOverflow { region: id })?;
179                (id, words, record_words, capacity_records)
180            }
181        };
182        let end_words = next_offset_words
183            .checked_add(words)
184            .ok_or(MegakernelWorkspaceLayoutError::OffsetOverflow { region: id })?;
185        regions.push(MegakernelWorkspaceRegion {
186            id,
187            offset_words: next_offset_words,
188            words,
189            record_words,
190            capacity_records,
191        });
192        next_offset_words = end_words;
193    }
194
195    Ok(regions)
196}
197
198#[cfg(test)]
199mod tests {
200    use super::*;
201
202    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
203    enum Region {
204        Header,
205        Rows,
206        Work,
207    }
208
209    #[test]
210    fn generated_workspace_regions_are_contiguous_for_many_capacities() {
211        for rows in [1_u32, 2, 7, 8, 31, 32, 1024] {
212            for work in [1_u32, 3, 64, 4096] {
213                let header = first_workspace_region(Region::Header, 16, 1, 16);
214                let rows = next_record_workspace_region(header, Region::Rows, 5, rows)
215                    .expect("Fix: generated row region should fit");
216                let work = next_record_workspace_region(rows, Region::Work, 2, work)
217                    .expect("Fix: generated work region should fit");
218
219                assert_eq!(header.offset_words, 0);
220                assert_eq!(rows.offset_words, header.end_words().unwrap());
221                assert_eq!(work.offset_words, rows.end_words().unwrap());
222            }
223        }
224    }
225
226    #[test]
227    fn record_region_word_overflow_is_reported_before_offset_overflow() {
228        let header = first_workspace_region(Region::Header, 16, 1, 16);
229
230        assert_eq!(
231            workspace_record_words(u32::MAX, 2),
232            None,
233            "record sizing must catch multiplication overflow"
234        );
235        assert_eq!(
236            next_record_workspace_region(header, Region::Rows, u32::MAX, 2),
237            None,
238            "record-backed layout must reject overflowing record arenas"
239        );
240    }
241
242    #[test]
243    fn next_region_rejects_offset_overflow() {
244        let previous = MegakernelWorkspaceRegion {
245            id: Region::Header,
246            offset_words: u32::MAX,
247            words: 1,
248            record_words: 1,
249            capacity_records: 1,
250        };
251
252        assert_eq!(
253            next_workspace_region(previous, Region::Rows, 1, 1, 1),
254            None,
255            "contiguous layout must reject overflowing end offsets"
256        );
257    }
258
259    #[test]
260    fn bulk_workspace_region_builder_matches_chained_layout_for_generated_capacities() {
261        for rows in [1_u32, 2, 7, 8, 31, 32, 1024] {
262            for work in [1_u32, 3, 64, 4096] {
263                let specs = [
264                    MegakernelWorkspaceRegionSpec::fixed(Region::Header, 16, 1, 16),
265                    MegakernelWorkspaceRegionSpec::record(Region::Rows, 5, rows),
266                    MegakernelWorkspaceRegionSpec::record(Region::Work, 2, work),
267                ];
268                let bulk = build_workspace_regions(&specs)
269                    .expect("Fix: generated bulk workspace layout should fit");
270
271                let header = first_workspace_region(Region::Header, 16, 1, 16);
272                let rows = next_record_workspace_region(header, Region::Rows, 5, rows)
273                    .expect("Fix: generated row region should fit");
274                let work = next_record_workspace_region(rows, Region::Work, 2, work)
275                    .expect("Fix: generated work region should fit");
276
277                assert_eq!(bulk, vec![header, rows, work]);
278            }
279        }
280    }
281
282    #[test]
283    fn bulk_workspace_region_builder_reports_record_and_offset_overflow_separately() {
284        let record = [MegakernelWorkspaceRegionSpec::record(
285            Region::Rows,
286            u32::MAX,
287            2,
288        )];
289        assert_eq!(
290            build_workspace_regions(&record),
291            Err(MegakernelWorkspaceLayoutError::RecordWordsOverflow {
292                region: Region::Rows
293            })
294        );
295
296        let offset = [
297            MegakernelWorkspaceRegionSpec::fixed(Region::Header, u32::MAX, 1, u32::MAX),
298            MegakernelWorkspaceRegionSpec::fixed(Region::Rows, 1, 1, 1),
299        ];
300        assert_eq!(
301            build_workspace_regions(&offset),
302            Err(MegakernelWorkspaceLayoutError::OffsetOverflow {
303                region: Region::Rows
304            })
305        );
306    }
307}