miden_assembly_syntax/ast/path/
join.rs1use alloc::{boxed::Box, string::String, sync::Arc};
2
3use super::*;
4use crate::ast;
5
6pub trait Join<T: ?Sized>: sealed::Joinable {
14 fn join(&self, other: &T) -> PathBuf;
28}
29
30mod sealed {
31 #[doc(hidden)]
32 pub trait Joinable {}
33
34 impl Joinable for crate::ast::Path {}
35 impl Joinable for crate::ast::PathBuf {}
36}
37
38impl Join<Path> for Path {
39 fn join(&self, other: &Path) -> PathBuf {
40 if other.is_empty() {
41 return self.to_path_buf();
42 }
43
44 if self.is_empty() {
45 other.to_path_buf()
46 } else if other.is_absolute() || other.is_in_kernel() || other.is_in_exec() {
47 other.to_absolute().into_owned()
48 } else {
49 let mut buf = self.to_path_buf();
50 buf.push(other);
51
52 buf
53 }
54 }
55}
56
57impl Join<PathBuf> for Path {
58 #[inline(always)]
59 fn join(&self, other: &PathBuf) -> PathBuf {
60 <Path as Join<Path>>::join(self, other.as_path())
61 }
62}
63
64impl Join<str> for Path {
65 fn join(&self, other: &str) -> PathBuf {
66 let mut buf = self.to_path_buf();
67 buf.push_component(other);
68 buf
69 }
70}
71
72impl Join<String> for Path {
73 fn join(&self, other: &String) -> PathBuf {
74 <Path as Join<str>>::join(self, other)
75 }
76}
77
78impl Join<Box<str>> for Path {
79 fn join(&self, other: &Box<str>) -> PathBuf {
80 <Path as Join<str>>::join(self, other)
81 }
82}
83
84impl Join<Arc<str>> for Path {
85 fn join(&self, other: &Arc<str>) -> PathBuf {
86 <Path as Join<str>>::join(self, other)
87 }
88}
89
90impl Join<ast::Ident> for Path {
91 fn join(&self, other: &ast::Ident) -> PathBuf {
92 <Path as Join<str>>::join(self, other.as_str())
93 }
94}
95
96impl Join<ast::ProcedureName> for Path {
97 fn join(&self, other: &ast::ProcedureName) -> PathBuf {
98 <Path as Join<str>>::join(self, other.as_str())
99 }
100}
101
102impl Join<ast::QualifiedProcedureName> for Path {
103 fn join(&self, other: &ast::QualifiedProcedureName) -> PathBuf {
104 let mut buf = <Path as Join<Path>>::join(self, other.namespace());
105 buf.push_component(other.name());
106 buf
107 }
108}
109
110impl Join<Path> for PathBuf {
111 #[inline]
112 fn join(&self, other: &Path) -> PathBuf {
113 <Path as Join<Path>>::join(self.as_path(), other)
114 }
115}
116
117impl Join<PathBuf> for PathBuf {
118 #[inline(always)]
119 fn join(&self, other: &PathBuf) -> PathBuf {
120 <Path as Join<Path>>::join(self.as_path(), other.as_path())
121 }
122}
123
124impl Join<str> for PathBuf {
125 fn join(&self, other: &str) -> PathBuf {
126 <Path as Join<str>>::join(self.as_path(), other)
127 }
128}
129
130impl Join<String> for PathBuf {
131 fn join(&self, other: &String) -> PathBuf {
132 <Path as Join<str>>::join(self.as_path(), other)
133 }
134}
135
136impl Join<Box<str>> for PathBuf {
137 fn join(&self, other: &Box<str>) -> PathBuf {
138 <Path as Join<str>>::join(self.as_path(), other)
139 }
140}
141
142impl Join<Arc<str>> for PathBuf {
143 fn join(&self, other: &Arc<str>) -> PathBuf {
144 <Path as Join<str>>::join(self.as_path(), other)
145 }
146}
147
148impl Join<ast::Ident> for PathBuf {
149 fn join(&self, other: &ast::Ident) -> PathBuf {
150 <Path as Join<ast::Ident>>::join(self.as_path(), other)
151 }
152}
153
154impl Join<ast::ProcedureName> for PathBuf {
155 fn join(&self, other: &ast::ProcedureName) -> PathBuf {
156 <Path as Join<ast::ProcedureName>>::join(self.as_path(), other)
157 }
158}
159
160impl Join<ast::QualifiedProcedureName> for PathBuf {
161 fn join(&self, other: &ast::QualifiedProcedureName) -> PathBuf {
162 <Path as Join<ast::QualifiedProcedureName>>::join(self.as_path(), other)
163 }
164}
165
166#[cfg(test)]
167mod tests {
168 use miden_core::assert_matches;
169
170 use super::*;
171
172 #[test]
173 fn test_join_path_to_path_plain() {
174 let p1 = Path::new("foo");
175 let p2 = Path::new("bar::baz");
176 let joined = Join::join(p1, p2);
177 assert_eq!(joined.as_path(), Path::new("foo::bar::baz"));
178 let mut components = joined.components();
179 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("foo"))));
180 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("bar"))));
181 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("baz"))));
182 assert_matches!(components.next(), None);
183 }
184
185 #[test]
186 fn test_join_absolute_path_to_path_plain() {
187 let p1 = Path::new("foo");
188 let p2 = Path::new("::bar::baz");
189 let joined = Join::join(p1, p2);
190 assert_eq!(joined.as_path(), Path::new("::bar::baz"));
191 let mut components = joined.components();
192 assert_matches!(components.next(), Some(Ok(PathComponent::Root)));
193 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("bar"))));
194 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("baz"))));
195 assert_matches!(components.next(), None);
196 }
197
198 #[test]
199 fn test_join_path_to_path_quoted() {
200 let p1 = Path::new("foo");
201 let p2 = Path::new("\"bar::baz\"::qux");
202 let joined = Join::join(p1, p2);
203 assert_eq!(joined.as_path(), Path::new("foo::\"bar::baz\"::qux"));
204 let mut components = joined.components();
205 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("foo"))));
206 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("\"bar::baz\""))));
207 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("qux"))));
208 assert_matches!(components.next(), None);
209 }
210
211 #[test]
212 fn test_join_path_to_absolute_path_quoted() {
213 let p1 = Path::new("::foo");
214 let p2 = Path::new("\"bar::baz\"::qux");
215 let joined = Join::join(p1, p2);
216 assert_eq!(joined.as_path(), Path::new("::foo::\"bar::baz\"::qux"));
217 let mut components = joined.components();
218 assert_matches!(components.next(), Some(Ok(PathComponent::Root)));
219 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("foo"))));
220 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("\"bar::baz\""))));
221 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("qux"))));
222 assert_matches!(components.next(), None);
223 }
224
225 #[test]
226 fn test_join_str_to_path_simple() {
227 let p1 = Path::new("foo");
228 let joined = Join::join(p1, "bar");
229 assert_eq!(joined.as_path(), Path::new("foo::bar"));
230 let mut components = joined.components();
231 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("foo"))));
232 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("bar"))));
233 assert_matches!(components.next(), None);
234 }
235
236 #[test]
237 fn test_join_str_to_path_multi_component_quoted() {
238 let p1 = Path::new("foo");
239 let joined = Join::join(p1, "\"bar::baz\"");
240 assert_eq!(joined.as_path(), Path::new("foo::\"bar::baz\""));
241 let mut components = joined.components();
242 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("foo"))));
243 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("\"bar::baz\""))));
244 assert_matches!(components.next(), None);
245 }
246
247 #[test]
248 fn test_join_str_to_path_multi_component_unquoted() {
249 let p1 = Path::new("foo");
250 let joined = Join::join(p1, "bar::baz");
251 assert_eq!(joined.as_path(), Path::new("foo::\"bar::baz\""));
252 let mut components = joined.components();
253 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("foo"))));
254 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("\"bar::baz\""))));
255 assert_matches!(components.next(), None);
256 }
257
258 #[test]
259 fn test_join_qualified_proc_name_to_path() {
260 let p1 = Path::new("foo");
261 let proc = ast::ProcedureName::new("qux").unwrap();
262 let p2 = ast::QualifiedProcedureName::new("bar::baz", proc);
263 let joined = Join::join(p1, &p2);
264 assert_eq!(joined.as_path(), Path::new("foo::bar::baz::qux"));
265 let mut components = joined.components();
266 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("foo"))));
267 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("bar"))));
268 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("baz"))));
269 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("qux"))));
270 assert_matches!(components.next(), None);
271 }
272}