pistonite_cu/str/
path_macro.rs1#[cfg(doc)]
91#[macro_export]
92macro_rules! path {
93 ($(&)? ident / $(ident_or_literal_or_expr) / * ) => {};
94 (literal / $(ident_or_literal_or_expr) / * ) => {};
95 ($(&)? ( path_expression ) / $(ident_or_literal_or_expr) / *) => {};
96}
97
98#[cfg(not(doc))]
99#[macro_export]
100macro_rules! path {
101 ($first:ident / $($rest_segs:tt)* ) => {{
102 let mut x = $first;
103 $crate::__path_internal!(x / $($rest_segs)*)
104 }};
105 ( & $first:ident / $($rest_segs:tt)* ) => {{
106 let mut x = std::path::PathBuf::from($first.to_owned());
107 $crate::__path_internal!(x / $($rest_segs)*)
108 }};
109 ($first:literal / $($rest_segs:tt)* ) => {{
110 let mut x = std::path::PathBuf::from($first);
111 $crate::__path_internal!(x / $($rest_segs)*)
112 }};
113 (( $first:expr ) / $($rest_segs:tt)* ) => {{
114 let mut x: ::std::path::PathBuf = $first;
115 $crate::__path_internal!(x / $($rest_segs)*)
116 }};
117 ( & ( $first:expr ) / $($rest_segs:tt)* ) => {{
118 let x: &::std::path::Path = ($first).as_ref();
119 let mut x = x.to_path_buf();
120 $crate::__path_internal!(x / $($rest_segs)*)
121 }};
122 ( $first:block / $($rest_segs:tt)* ) => {{
123 let mut x: ::std::path::PathBuf = $first;
124 $crate::__path_internal!(x / $($rest_segs)*)
125 }};
126 ( & $first:block / $($rest_segs:tt)* ) => {{
127 let x: &::std::path::Path = $first.as_ref();
128 let mut x = x.to_path_buf();
129 $crate::__path_internal!(x / $($rest_segs)*)
130 }};
131}
132
133#[macro_export]
134#[doc(hidden)]
135macro_rules! __path_internal {
136 ($first:ident / $second:literal) => {{
138 $first.push($second); $first
139 }};
140 ($first:ident / $second:ident) => {{
141 let x: &::std::path::Path = $second.as_ref();
142 $first.push(x); $first
143 }};
144 ($first:ident / $second:literal / $third:literal) => {{
145 $first.push($second); $first.push($third); $first
146 }};
147 ($first:ident / $second:literal / $third:ident) => {{
148 $first.push($second);
149 let x: &::std::path::Path = $third.as_ref();
150 $first.push(x); $first
151 }};
152 ($first:ident / $second:ident / $third:literal) => {{
153 let x: &::std::path::Path = $second.as_ref();
154 $first.push(x);
155 $first.push($third); $first
156 }};
157 ($first:ident / $second:ident / $third:ident) => {{
158 let x: &::std::path::Path = $second.as_ref();
159 $first.push(x);
160 let x: &::std::path::Path = $third.as_ref();
161 $first.push(x); $first
162 }};
163
164 ($first:ident / $second:literal / $third:literal / $($rest_segs:tt)* ) => {{
166 $first.push($second); $first.push($third);
167 $crate::__path_internal!($first / $($rest_segs)* )
168 }};
169 ($first:ident / $second:literal / $third:ident / $($rest_segs:tt)* ) => {{
170 $first.push($second);
171 let x: &::std::path::Path = $third.as_ref();
172 $first.push(x);
173 $crate::__path_internal!($first / $($rest_segs)* )
174 }};
175 ($first:ident / $second:literal / ( $third:expr ) / $($rest_segs:tt)* ) => {{
176 $first.push($second);
177 let x: &::std::path::Path = ($third).as_ref();
178 $first.push(x);
179 $crate::__path_internal!($first / $($rest_segs)* )
180 }};
181 ($first:ident / $second:literal / $third:block / $($rest_segs:tt)* ) => {{
182 $first.push($second);
183 let x: &::std::path::Path = $third.as_ref();
184 $first.push(x);
185 $crate::__path_internal!($first / $($rest_segs)* )
186 }};
187 ($first:ident / $second:ident / $third:literal / $($rest_segs:tt)* ) => {{
188 let x: &::std::path::Path = $second.as_ref();
189 $first.push(x);
190 $first.push($third);
191 $crate::__path_internal!($first / $($rest_segs)* )
192 }};
193 ($first:ident / $second:ident / $third:ident / $($rest_segs:tt)* ) => {{
194 let x: &::std::path::Path = $second.as_ref();
195 $first.push(x);
196 let x: &::std::path::Path = $third.as_ref();
197 $first.push(x);
198 $crate::__path_internal!($first / $($rest_segs)* )
199 }};
200 ($first:ident / $second:ident / ( $third:expr ) / $($rest_segs:tt)* ) => {{
201 let x: &::std::path::Path = $second.as_ref();
202 $first.push(x);
203 let x: &::std::path::Path = ($third).as_ref();
204 $first.push(x);
205 $crate::__path_internal!($first / $($rest_segs)* )
206 }};
207 ($first:ident / $second:ident / $third:block / $($rest_segs:tt)* ) => {{
208 let x: &::std::path::Path = $second.as_ref();
209 $first.push(x);
210 let x: &::std::path::Path = $third.as_ref();
211 $first.push(x);
212 $crate::__path_internal!($first / $($rest_segs)* )
213 }};
214 ($first:ident / ( $second:expr ) / $($rest_segs:tt)* ) => {{
216 let x: &::std::path::Path = ($second).as_ref();
217 $first.push(x);
218 $crate::__path_internal!($first / $($rest_segs)* )
219 }};
220 ($first:ident / $second:block / $($rest_segs:tt)* ) => {{
221 let x: &::std::path::Path = $second.as_ref();
222 $first.push(x);
223 $crate::__path_internal!($first / $($rest_segs)* )
224 }};
225
226 ($first:ident / $second:literal / $third:expr) => {{
230 $first.push($second);
231 fn cast(x: &::std::path::Path) -> &::std::path::Path { x }
232 $first.push(cast($third.as_ref()));
233 $first
234 }};
235 ($first:ident / $second:ident / $third:expr) => {{
236 let x: &::std::path::Path = $second.as_ref();
237 $first.push(x);
238 fn cast(x: &::std::path::Path) -> &::std::path::Path { x }
239 $first.push(cast($third.as_ref())); $first
240 }};
241 ($first:ident / $second:expr) => {{
242 fn cast(x: &::std::path::Path) -> &::std::path::Path { x }
243 $first.push(cast($second.as_ref())); $first
244 }};
245
246}
247
248#[cfg(test)]
249mod tests {
250 use std::path::{Path, PathBuf};
251
252 fn long_expected() -> PathBuf {
253 PathBuf::from("a")
254 .join("b")
255 .join("c")
256 .join("d")
257 .join("e")
258 .join("f")
259 .join("g")
260 .join("h")
261 .join("i")
262 .join("j")
263 }
264
265 #[test]
267 fn long_path_from_literal() {
268 let c = "c";
269 let e = String::from("e");
270 let h = "h";
271 let p = crate::path!("a" / "b" / (c) / "d" / (e.as_str()) / "f" / "g" / h / "i" / "j");
272 assert_eq!(p, long_expected());
273 let _ = (c, h); }
275
276 #[test]
278 fn long_path_from_owned() {
279 let base = PathBuf::from("a");
280 let b = "b";
281 let d = String::from("d");
282 let g = "g";
283 let p = crate::path!(base / (b) / "c" / (d.as_str()) / "e" / "f" / g / "h" / "i" / "j");
284 assert_eq!(p, long_expected());
285 let _ = (b, g);
286 }
287
288 #[test]
290 fn long_path_from_borrowed() {
291 let base = PathBuf::from("a");
292 let base_ref: &Path = base.as_path();
293 let c = String::from("c");
294 let f = "f";
295 let i = "i";
296 let p = crate::path!(&base_ref / "b" / (c.as_str()) / "d" / "e" / f / "g" / "h" / i / "j");
297 assert_eq!(p, long_expected());
298 let _ = (f, i);
299 }
300
301 #[test]
303 fn long_path_from_expr_owned() {
304 let d = "d";
305 let e = String::from("e");
306 let f = String::from("f");
307 let p = crate::path!(
308 (PathBuf::from("a")) / "b" / "c" / d / (&e) / (f.as_str()) / "g" / "h" / "i" / "j"
309 );
310 assert_eq!(p, long_expected());
311 let _ = d;
312 }
313
314 #[test]
316 fn long_path_from_expr_borrowed() {
317 let base = PathBuf::from("a");
318 let b = "b";
319 let e = String::from("e");
320 let j = "j";
321 let p = crate::path!(
322 &(base.as_path()) / b / "c" / "d" / (e.as_str()) / "f" / "g" / "h" / "i" / j
323 );
324 assert_eq!(p, long_expected());
325 let _ = (b, j);
326 }
327
328 #[test]
331 fn long_path_no_consecutive_same_type_even() {
332 let b = "b";
333 let c = String::from("c");
334 let e = "e";
335 let f = String::from("f");
336 let h = "h";
337 let i = String::from("i");
338 let p = crate::path!(
339 "a" / b / (c.as_str()) / "d" / e / (f.as_str()) / "g" / h / (i.as_str()) / "j"
340 );
341 assert_eq!(p, long_expected());
342 let _ = (b, e, h);
343 }
344
345 fn nine_expected() -> PathBuf {
346 PathBuf::from("a")
347 .join("b")
348 .join("c")
349 .join("d")
350 .join("e")
351 .join("f")
352 .join("g")
353 .join("h")
354 .join("i")
355 }
356
357 #[test]
360 fn long_path_no_consecutive_same_type_odd() {
361 let b = "b";
362 let c = String::from("c");
363 let e = "e";
364 let f = String::from("f");
365 let h = "h";
366 let i = String::from("i");
367 let p =
368 crate::path!("a" / b / (c.as_str()) / "d" / e / (f.as_str()) / "g" / h / i.as_str());
369 assert_eq!(p, nine_expected());
370 let _ = (b, e, h);
371 }
372
373 #[test]
374 fn no_temporary() {
375 let aaa = String::from("aaa");
376 let bbb = String::from("bbb");
377 struct Foo {
378 bar: String,
379 }
380 let foo = Foo {
381 bar: String::from("bar"),
382 };
383 let p = crate::path!(&aaa / "k" / bbb / foo.bar);
384 let expected = PathBuf::from("aaa").join("k").join("bbb").join("bar");
385 assert_eq!(p, expected);
386 let p = crate::path!((aaa.clone().into()) / "k" / bbb / foo.bar);
387 assert_eq!(p, expected);
388 let p = crate::path!((aaa.into()) / "k" / bbb / format!("biz{}biz", foo.bar));
389 let expected = PathBuf::from("aaa").join("k").join("bbb").join("bizbarbiz");
390 assert_eq!(p, expected);
391 }
392}