miden_assembly_syntax/ast/path/
mod.rs1mod components;
2mod join;
3#[expect(clippy::module_inception)]
4mod path;
5mod path_buf;
6
7pub use self::{
8 components::{Iter, PathComponent},
9 join::Join,
10 path::Path,
11 path_buf::PathBuf,
12};
13#[cfg(feature = "serde")]
14use crate::debuginfo::Span;
15use crate::diagnostics::{Diagnostic, miette};
16
17#[derive(Debug, thiserror::Error)]
19pub enum PathError {
20 #[error("invalid item path: cannot be empty")]
21 Empty,
22 #[error("invalid item path component: cannot be empty")]
23 EmptyComponent,
24 #[error("invalid item path component: {0}")]
25 InvalidComponent(crate::ast::IdentError),
26 #[error("invalid item path: contains invalid utf8 byte sequences")]
27 InvalidUtf8,
28 #[error(transparent)]
29 InvalidNamespace(NamespaceError),
30 #[error("cannot join a path with reserved name to other paths")]
31 UnsupportedJoin,
32 #[error("'::' delimiter found where path component was expected")]
33 UnexpectedDelimiter,
34 #[error("path is missing a '::' delimiter between quoted/unquoted components")]
35 MissingPathSeparator,
36 #[error("quoted path component is missing a closing '\"'")]
37 UnclosedQuotedComponent,
38}
39
40#[derive(Debug, thiserror::Error, Diagnostic)]
42pub enum NamespaceError {
43 #[error("invalid library namespace name: cannot be empty")]
44 #[diagnostic()]
45 Empty,
46 #[error("invalid library namespace name: too many characters")]
47 #[diagnostic()]
48 Length,
49 #[error(
50 "invalid character in library namespace: expected lowercase ascii-alphanumeric character or '_'"
51 )]
52 #[diagnostic()]
53 InvalidChars,
54 #[error("invalid library namespace name: must start with lowercase ascii-alphabetic character")]
55 #[diagnostic()]
56 InvalidStart,
57}
58
59pub trait StartsWith<Prefix: ?Sized> {
72 fn starts_with(&self, prefix: &Prefix) -> bool;
74
75 fn starts_with_exactly(&self, prefix: &Prefix) -> bool;
77}
78
79#[cfg(feature = "serde")]
81pub fn serialize<P, S>(path: P, serializer: S) -> Result<S::Ok, S::Error>
82where
83 P: AsRef<Path>,
84 S: serde::Serializer,
85{
86 use serde::Serialize;
87 path.as_ref().serialize(serializer)
88}
89
90#[cfg(feature = "serde")]
92pub fn deserialize<'de, P, D>(deserializer: D) -> Result<P, D::Error>
93where
94 P: From<PathBuf>,
95 D: serde::Deserializer<'de>,
96{
97 let path = <PathBuf as serde::Deserialize>::deserialize(deserializer)?;
98 Ok(P::from(path))
99}
100
101#[cfg(feature = "serde")]
103pub fn deserialize_spanned<'de, P, D>(deserializer: D) -> Result<Span<P>, D::Error>
104where
105 P: From<PathBuf>,
106 D: serde::Deserializer<'de>,
107{
108 let path = <PathBuf as serde::Deserialize>::deserialize(deserializer)?;
109 Ok(Span::unknown(P::from(path)))
110}
111
112#[cfg(feature = "arbitrary")]
113pub mod arbitrary {
114 use alloc::{sync::Arc, vec::Vec};
115
116 use proptest::{arbitrary::Arbitrary, collection::vec, prelude::*};
117
118 use super::*;
119 use crate::ast::{Ident, ident};
120
121 impl Arbitrary for PathBuf {
122 type Parameters = ();
123
124 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
125 pathbuf_random_length(1).boxed()
126 }
127
128 type Strategy = BoxedStrategy<Self>;
129 }
130
131 prop_compose! {
132 fn components_any(min: u8, max: u8)
135 (components in vec(prop_oneof![
136 ident::arbitrary::ident_any_random_length(),
137 ident::arbitrary::bare_ident_any_random_length()
138 ], (min as usize)..=(max as usize))) -> Vec<Ident> {
139 components
140 }
141 }
142
143 prop_compose! {
144 fn bare_components_any(min: u8, max: u8)
147 (components in vec(ident::arbitrary::bare_ident_any_random_length(), (min as usize)..=(max as usize))) -> Vec<Ident> {
148 components
149 }
150 }
151
152 prop_compose! {
153 pub fn pathbuf(min: u8, max: u8)
156 (components in components_any(min, max)) -> PathBuf {
157 let mut buf = PathBuf::default();
158 for component in components {
159 buf.push_component(&component);
160 }
161 buf
162 }
163 }
164
165 prop_compose! {
166 pub fn bare_pathbuf(min: u8, max: u8)
168 (components in bare_components_any(min, max)) -> PathBuf {
169 let mut buf = PathBuf::default();
170 for component in components {
171 buf.push_component(&component);
172 }
173 buf
174 }
175 }
176
177 prop_compose! {
178 pub fn constant_pathbuf(min: u8, max: u8)
183 (prefix in components_any(min, max), name in ident::arbitrary::const_ident_any_random_length()) -> PathBuf {
184 let mut buf = PathBuf::default();
185 for component in prefix {
186 buf.push_component(&component);
187 }
188 buf.push_component(&name);
189 buf
190 }
191 }
192
193 prop_compose! {
194 pub fn builtin_type_pathbuf()
198 (name in ident::arbitrary::builtin_type_any()) -> PathBuf {
199 PathBuf::from(name)
200 }
201 }
202
203 prop_compose! {
204 pub fn user_defined_type_pathbuf(min: u8, max: u8)
207 ((name, prefix) in (ident::arbitrary::bare_ident_any_random_length(), components_any(min, max))) -> PathBuf {
208 let mut buf = PathBuf::default();
209 for component in prefix {
210 buf.push_component(&component);
211 }
212 buf.push_component(&name);
213 buf
214 }
215 }
216
217 prop_compose! {
218 pub fn type_pathbuf(min: u8, max: u8)
221 (path in prop_oneof![
222 1 => user_defined_type_pathbuf(min, max),
223 2 => builtin_type_pathbuf()
224 ]) -> PathBuf {
225 path
226 }
227 }
228
229 prop_compose! {
230 pub fn pathbuf_random_length(min: u8)
234 (max in min..=core::cmp::max(min.saturating_add(1), 10))
235 (path in pathbuf(min, max)) -> PathBuf {
236 path
237 }
238 }
239
240 prop_compose! {
241 pub fn bare_pathbuf_random_length(min: u8)
247 (max in min..=core::cmp::max(min.saturating_add(1), 10))
248 (path in bare_pathbuf(min, max)) -> PathBuf {
249 path
250 }
251 }
252
253 prop_compose! {
254 pub fn constant_pathbuf_random_length(min: u8)
259 (max in min..=core::cmp::max(min.saturating_add(1), 10))
260 (path in constant_pathbuf(min, max)) -> PathBuf {
261 path
262 }
263 }
264
265 prop_compose! {
266 pub fn type_pathbuf_random_length(min: u8)
271 (max in min..=core::cmp::max(min.saturating_add(1), 10))
272 (path in type_pathbuf(min, max)) -> PathBuf {
273 path
274 }
275 }
276
277 prop_compose! {
278 pub fn user_defined_type_pathbuf_random_length(min: u8)
283 (max in min..=core::cmp::max(min.saturating_add(1), 10))
284 (path in user_defined_type_pathbuf(min, max)) -> PathBuf {
285 path
286 }
287 }
288
289 prop_compose! {
290 pub fn path_random_length(min: u8)
292 (path in pathbuf_random_length(min)) -> Arc<Path> {
293 path.into()
294 }
295 }
296
297 prop_compose! {
298 pub fn bare_path_random_length(min: u8)
302 (path in bare_pathbuf_random_length(min)) -> Arc<Path> {
303 path.into()
304 }
305 }
306
307 prop_compose! {
308 pub fn constant_path_random_length(min: u8)
313 (path in constant_pathbuf_random_length(min)) -> Arc<Path> {
314 path.into()
315 }
316 }
317
318 prop_compose! {
319 pub fn type_path_random_length(min: u8)
324 (path in type_pathbuf_random_length(min)) -> Arc<Path> {
325 path.into()
326 }
327 }
328
329 prop_compose! {
330 pub fn user_defined_type_path_random_length(min: u8)
335 (path in user_defined_type_pathbuf_random_length(min)) -> Arc<Path> {
336 path.into()
337 }
338 }
339}