miden_assembly_syntax/ast/item/
index.rs1#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
3#[repr(transparent)]
4pub struct ItemIndex(u16);
5
6#[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)]
7#[error("invalid item index: too many items")]
8pub struct ItemIndexError {
9 attempted: usize,
10}
11
12impl ItemIndex {
13 pub const MAX_ITEMS: usize = u16::MAX as usize + 1;
14
15 pub fn new(id: usize) -> Self {
16 Self::try_new(id).expect("invalid item index: too many items")
17 }
18
19 pub fn try_new(id: usize) -> Result<Self, ItemIndexError> {
20 let raw = id.try_into().map_err(|_| ItemIndexError { attempted: id })?;
21 Ok(Self(raw))
22 }
23
24 #[inline(always)]
25 pub const fn const_new(id: u16) -> Self {
26 Self(id)
27 }
28
29 #[inline(always)]
31 pub const fn as_usize(&self) -> usize {
32 self.0 as usize
33 }
34}
35
36impl core::fmt::Display for ItemIndex {
37 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
38 write!(f, "{}", self.as_usize())
39 }
40}
41
42#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
70pub struct GlobalItemIndex {
71 pub module: ModuleIndex,
73 pub index: ItemIndex,
75}
76
77impl core::fmt::Display for GlobalItemIndex {
78 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
79 write!(f, "{}:{}", self.module, self.index)
80 }
81}
82
83#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
85#[repr(transparent)]
86pub struct ModuleIndex(u16);
87
88impl ModuleIndex {
89 pub const MAX_MODULES: usize = u16::MAX as usize + 1;
90
91 pub fn new(index: usize) -> Self {
92 Self::try_new(index).expect("invalid module index: too many modules")
93 }
94
95 pub fn try_new(index: usize) -> Result<Self, core::num::TryFromIntError> {
96 index.try_into().map(Self)
97 }
98
99 pub const fn const_new(index: u16) -> Self {
100 Self(index)
101 }
102
103 #[inline(always)]
104 pub const fn as_usize(&self) -> usize {
105 self.0 as usize
106 }
107}
108
109impl core::ops::Add<ItemIndex> for ModuleIndex {
110 type Output = GlobalItemIndex;
111
112 fn add(self, rhs: ItemIndex) -> Self::Output {
113 GlobalItemIndex { module: self, index: rhs }
114 }
115}
116
117impl core::fmt::Display for ModuleIndex {
118 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
119 write!(f, "{}", self.as_usize())
120 }
121}
122
123#[cfg(test)]
124mod regression_tests {
125 use std::string::String;
126
127 use super::ModuleIndex;
128 use crate::sema::{LimitKind, SemanticAnalysisError, SyntaxError};
129
130 #[test]
131 fn module_index_try_new_checks_capacity() {
132 let last = ModuleIndex::try_new(ModuleIndex::MAX_MODULES - 1)
133 .expect("the final representable module index must be accepted");
134
135 assert_eq!(last.as_usize(), ModuleIndex::MAX_MODULES - 1);
136 assert!(ModuleIndex::try_new(ModuleIndex::MAX_MODULES).is_err());
137 }
138
139 fn huge_library_masm() -> String {
140 let num_consts = usize::from(u16::MAX) + 2;
141 let mut masm = String::with_capacity(num_consts * 16);
142 masm.push_str("namespace ::m::huge\n\n");
143 for i in 0..num_consts {
144 masm.push_str("const A");
145 masm.push_str(&format!("{i}"));
146 masm.push_str(" = 0\n");
147 }
148 masm
149 }
150
151 #[test]
152 fn too_many_items_in_module_is_rejected_during_analysis() {
153 let test = crate::testing::SyntaxTestContext::new();
154 let err = test
155 .parse_module(&huge_library_masm())
156 .expect_err("expected oversized module to be rejected during analysis");
157
158 let syntax_error = err.downcast_ref::<SyntaxError>().expect("expected SyntaxError report");
159 assert!(
160 syntax_error.errors.iter().any(|error| {
161 matches!(error, SemanticAnalysisError::LimitExceeded { kind: LimitKind::Items, .. })
162 }),
163 "expected item-limit error, got {:?}",
164 syntax_error.errors
165 );
166 }
167}