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("invalid item path: too long (max {max} bytes)")]
29 TooLong { max: usize },
30 #[error(transparent)]
31 InvalidNamespace(NamespaceError),
32 #[error("cannot join a path with reserved name to other paths")]
33 UnsupportedJoin,
34 #[error("'::' delimiter found where path component was expected")]
35 UnexpectedDelimiter,
36 #[error("path is missing a '::' delimiter between quoted/unquoted components")]
37 MissingPathSeparator,
38 #[error("quoted path component is missing a closing '\"'")]
39 UnclosedQuotedComponent,
40}
41
42#[derive(Debug, thiserror::Error, Diagnostic)]
44pub enum NamespaceError {
45 #[error("invalid library namespace name: cannot be empty")]
46 #[diagnostic()]
47 Empty,
48 #[error("invalid library namespace name: too many characters")]
49 #[diagnostic()]
50 Length,
51 #[error(
52 "invalid character in library namespace: expected lowercase ascii-alphanumeric character or '_'"
53 )]
54 #[diagnostic()]
55 InvalidChars,
56 #[error("invalid library namespace name: must start with lowercase ascii-alphabetic character")]
57 #[diagnostic()]
58 InvalidStart,
59}
60
61pub trait StartsWith<Prefix: ?Sized> {
74 fn starts_with(&self, prefix: &Prefix) -> bool;
76
77 fn starts_with_exactly(&self, prefix: &Prefix) -> bool;
79}
80
81#[cfg(feature = "serde")]
83pub fn serialize<P, S>(path: P, serializer: S) -> Result<S::Ok, S::Error>
84where
85 P: AsRef<Path>,
86 S: serde::Serializer,
87{
88 use serde::Serialize;
89 path.as_ref().serialize(serializer)
90}
91
92#[cfg(feature = "serde")]
94pub fn deserialize<'de, P, D>(deserializer: D) -> Result<P, D::Error>
95where
96 P: From<PathBuf>,
97 D: serde::Deserializer<'de>,
98{
99 let path = <PathBuf as serde::Deserialize>::deserialize(deserializer)?;
100 Ok(P::from(path))
101}
102
103#[cfg(feature = "serde")]
105pub fn deserialize_spanned<'de, P, D>(deserializer: D) -> Result<Span<P>, D::Error>
106where
107 P: From<PathBuf>,
108 D: serde::Deserializer<'de>,
109{
110 let path = <PathBuf as serde::Deserialize>::deserialize(deserializer)?;
111 Ok(Span::unknown(P::from(path)))
112}
113
114#[cfg(feature = "arbitrary")]
115pub mod arbitrary {
116 use alloc::{sync::Arc, vec::Vec};
117
118 use proptest::{arbitrary::Arbitrary, collection::vec, prelude::*};
119
120 use super::*;
121 use crate::ast::{Ident, ident};
122
123 impl Arbitrary for PathBuf {
124 type Parameters = ();
125
126 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
127 pathbuf_random_length(1).boxed()
128 }
129
130 type Strategy = BoxedStrategy<Self>;
131 }
132
133 prop_compose! {
134 fn components_any(min: u8, max: u8)
137 (components in vec(prop_oneof![
138 ident::arbitrary::ident_any_random_length(),
139 ident::arbitrary::bare_ident_any_random_length()
140 ], (min as usize)..=(max as usize))) -> Vec<Ident> {
141 components
142 }
143 }
144
145 prop_compose! {
146 fn bare_components_any(min: u8, max: u8)
149 (components in vec(ident::arbitrary::bare_ident_any_random_length(), (min as usize)..=(max as usize))) -> Vec<Ident> {
150 components
151 }
152 }
153
154 prop_compose! {
155 pub fn pathbuf(min: u8, max: u8)
158 (components in components_any(min, max)) -> PathBuf {
159 let mut buf = PathBuf::default();
160 for component in components {
161 buf.push_component(&component);
162 }
163 buf
164 }
165 }
166
167 prop_compose! {
168 pub fn bare_pathbuf(min: u8, max: u8)
170 (components in bare_components_any(min, max)) -> PathBuf {
171 let mut buf = PathBuf::default();
172 for component in components {
173 buf.push_component(&component);
174 }
175 buf
176 }
177 }
178
179 prop_compose! {
180 pub fn constant_pathbuf(min: u8, max: u8)
185 (prefix in components_any(min, max), name in ident::arbitrary::const_ident_any_random_length()) -> PathBuf {
186 let mut buf = PathBuf::default();
187 for component in prefix {
188 buf.push_component(&component);
189 }
190 buf.push_component(&name);
191 buf
192 }
193 }
194
195 prop_compose! {
196 pub fn builtin_type_pathbuf()
200 (name in ident::arbitrary::builtin_type_any()) -> PathBuf {
201 PathBuf::from(name)
202 }
203 }
204
205 prop_compose! {
206 pub fn user_defined_type_pathbuf(min: u8, max: u8)
209 ((name, prefix) in (ident::arbitrary::bare_ident_any_random_length(), components_any(min, max))) -> PathBuf {
210 let mut buf = PathBuf::default();
211 for component in prefix {
212 buf.push_component(&component);
213 }
214 buf.push_component(&name);
215 buf
216 }
217 }
218
219 prop_compose! {
220 pub fn type_pathbuf(min: u8, max: u8)
223 (path in prop_oneof![
224 1 => user_defined_type_pathbuf(min, max),
225 2 => builtin_type_pathbuf()
226 ]) -> PathBuf {
227 path
228 }
229 }
230
231 prop_compose! {
232 pub fn pathbuf_random_length(min: u8)
236 (max in min..=core::cmp::max(min.saturating_add(1), 10))
237 (path in pathbuf(min, max)) -> PathBuf {
238 path
239 }
240 }
241
242 prop_compose! {
243 pub fn bare_pathbuf_random_length(min: u8)
249 (max in min..=core::cmp::max(min.saturating_add(1), 10))
250 (path in bare_pathbuf(min, max)) -> PathBuf {
251 path
252 }
253 }
254
255 prop_compose! {
256 pub fn constant_pathbuf_random_length(min: u8)
261 (max in min..=core::cmp::max(min.saturating_add(1), 10))
262 (path in constant_pathbuf(min, max)) -> PathBuf {
263 path
264 }
265 }
266
267 prop_compose! {
268 pub fn type_pathbuf_random_length(min: u8)
273 (max in min..=core::cmp::max(min.saturating_add(1), 10))
274 (path in type_pathbuf(min, max)) -> PathBuf {
275 path
276 }
277 }
278
279 prop_compose! {
280 pub fn user_defined_type_pathbuf_random_length(min: u8)
285 (max in min..=core::cmp::max(min.saturating_add(1), 10))
286 (path in user_defined_type_pathbuf(min, max)) -> PathBuf {
287 path
288 }
289 }
290
291 prop_compose! {
292 pub fn path_random_length(min: u8)
294 (path in pathbuf_random_length(min)) -> Arc<Path> {
295 path.into()
296 }
297 }
298
299 prop_compose! {
300 pub fn bare_path_random_length(min: u8)
304 (path in bare_pathbuf_random_length(min)) -> Arc<Path> {
305 path.into()
306 }
307 }
308
309 prop_compose! {
310 pub fn constant_path_random_length(min: u8)
315 (path in constant_pathbuf_random_length(min)) -> Arc<Path> {
316 path.into()
317 }
318 }
319
320 prop_compose! {
321 pub fn type_path_random_length(min: u8)
326 (path in type_pathbuf_random_length(min)) -> Arc<Path> {
327 path.into()
328 }
329 }
330
331 prop_compose! {
332 pub fn user_defined_type_path_random_length(min: u8)
337 (path in user_defined_type_pathbuf_random_length(min)) -> Arc<Path> {
338 path.into()
339 }
340 }
341}