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> {
61 fn starts_with(&self, prefix: &Prefix) -> bool;
63
64 fn starts_with_exactly(&self, prefix: &Prefix) -> bool;
66}
67
68#[cfg(feature = "serde")]
70pub fn serialize<P, S>(path: P, serializer: S) -> Result<S::Ok, S::Error>
71where
72 P: AsRef<Path>,
73 S: serde::Serializer,
74{
75 use serde::Serialize;
76 path.as_ref().serialize(serializer)
77}
78
79#[cfg(feature = "serde")]
81pub fn deserialize<'de, P, D>(deserializer: D) -> Result<P, D::Error>
82where
83 P: From<PathBuf>,
84 D: serde::Deserializer<'de>,
85{
86 let path = <PathBuf as serde::Deserialize>::deserialize(deserializer)?;
87 Ok(P::from(path))
88}
89
90#[cfg(feature = "serde")]
92pub fn deserialize_spanned<'de, P, D>(deserializer: D) -> Result<Span<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(Span::unknown(P::from(path)))
99}
100
101#[cfg(feature = "arbitrary")]
102pub mod arbitrary {
103 use alloc::{sync::Arc, vec::Vec};
104
105 use proptest::{arbitrary::Arbitrary, collection::vec, prelude::*};
106
107 use super::*;
108 use crate::ast::{Ident, ident};
109
110 impl Arbitrary for PathBuf {
111 type Parameters = ();
112
113 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
114 pathbuf_random_length(1).boxed()
115 }
116
117 type Strategy = BoxedStrategy<Self>;
118 }
119
120 prop_compose! {
121 fn components_any(min: u8, max: u8)
124 (components in vec(prop_oneof![
125 ident::arbitrary::ident_any_random_length(),
126 ident::arbitrary::bare_ident_any_random_length()
127 ], (min as usize)..=(max as usize))) -> Vec<Ident> {
128 components
129 }
130 }
131
132 prop_compose! {
133 fn bare_components_any(min: u8, max: u8)
136 (components in vec(ident::arbitrary::bare_ident_any_random_length(), (min as usize)..=(max as usize))) -> Vec<Ident> {
137 components
138 }
139 }
140
141 prop_compose! {
142 pub fn pathbuf(min: u8, max: u8)
145 (components in components_any(min, max)) -> PathBuf {
146 let mut buf = PathBuf::default();
147 for component in components {
148 buf.push_component(&component);
149 }
150 buf
151 }
152 }
153
154 prop_compose! {
155 pub fn bare_pathbuf(min: u8, max: u8)
157 (components in bare_components_any(min, max)) -> PathBuf {
158 let mut buf = PathBuf::default();
159 for component in components {
160 buf.push_component(&component);
161 }
162 buf
163 }
164 }
165
166 prop_compose! {
167 pub fn constant_pathbuf(min: u8, max: u8)
172 (prefix in components_any(min, max), name in ident::arbitrary::const_ident_any_random_length()) -> PathBuf {
173 let mut buf = PathBuf::default();
174 for component in prefix {
175 buf.push_component(&component);
176 }
177 buf.push_component(&name);
178 buf
179 }
180 }
181
182 prop_compose! {
183 pub fn builtin_type_pathbuf()
187 (name in ident::arbitrary::builtin_type_any()) -> PathBuf {
188 PathBuf::from(name)
189 }
190 }
191
192 prop_compose! {
193 pub fn user_defined_type_pathbuf(min: u8, max: u8)
196 ((name, prefix) in (ident::arbitrary::bare_ident_any_random_length(), components_any(min, max))) -> PathBuf {
197 let mut buf = PathBuf::default();
198 for component in prefix {
199 buf.push_component(&component);
200 }
201 buf.push_component(&name);
202 buf
203 }
204 }
205
206 prop_compose! {
207 pub fn type_pathbuf(min: u8, max: u8)
210 (path in prop_oneof![
211 1 => user_defined_type_pathbuf(min, max),
212 2 => builtin_type_pathbuf()
213 ]) -> PathBuf {
214 path
215 }
216 }
217
218 prop_compose! {
219 pub fn pathbuf_random_length(min: u8)
223 (max in min..=core::cmp::max(min.saturating_add(1), 10))
224 (path in pathbuf(min, max)) -> PathBuf {
225 path
226 }
227 }
228
229 prop_compose! {
230 pub fn bare_pathbuf_random_length(min: u8)
236 (max in min..=core::cmp::max(min.saturating_add(1), 10))
237 (path in bare_pathbuf(min, max)) -> PathBuf {
238 path
239 }
240 }
241
242 prop_compose! {
243 pub fn constant_pathbuf_random_length(min: u8)
248 (max in min..=core::cmp::max(min.saturating_add(1), 10))
249 (path in constant_pathbuf(min, max)) -> PathBuf {
250 path
251 }
252 }
253
254 prop_compose! {
255 pub fn type_pathbuf_random_length(min: u8)
260 (max in min..=core::cmp::max(min.saturating_add(1), 10))
261 (path in type_pathbuf(min, max)) -> PathBuf {
262 path
263 }
264 }
265
266 prop_compose! {
267 pub fn user_defined_type_pathbuf_random_length(min: u8)
272 (max in min..=core::cmp::max(min.saturating_add(1), 10))
273 (path in user_defined_type_pathbuf(min, max)) -> PathBuf {
274 path
275 }
276 }
277
278 prop_compose! {
279 pub fn path_random_length(min: u8)
281 (path in pathbuf_random_length(min)) -> Arc<Path> {
282 path.into()
283 }
284 }
285
286 prop_compose! {
287 pub fn bare_path_random_length(min: u8)
291 (path in bare_pathbuf_random_length(min)) -> Arc<Path> {
292 path.into()
293 }
294 }
295
296 prop_compose! {
297 pub fn constant_path_random_length(min: u8)
302 (path in constant_pathbuf_random_length(min)) -> Arc<Path> {
303 path.into()
304 }
305 }
306
307 prop_compose! {
308 pub fn type_path_random_length(min: u8)
313 (path in type_pathbuf_random_length(min)) -> Arc<Path> {
314 path.into()
315 }
316 }
317
318 prop_compose! {
319 pub fn user_defined_type_path_random_length(min: u8)
324 (path in user_defined_type_pathbuf_random_length(min)) -> Arc<Path> {
325 path.into()
326 }
327 }
328}