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