zenops_safe_relative_path_macros/
lib.rs1use proc_macro::TokenStream;
2use quote::quote;
3use relative_path::RelativePath;
4use syn::{Ident, LitStr, parse_macro_input};
5
6#[proc_macro]
8pub fn srpath(input: TokenStream) -> TokenStream {
9 let arg = parse_macro_input!(input as LitStr).value();
10
11 match RelativePath::from_path(&arg) {
12 Ok(path) => {
13 if zenops_safe_relative_path_validator::is_safe_relative_path(path) {
14 quote! {
15 unsafe {
16 ::zenops_safe_relative_path::SafeRelativePath::new_unchecked_from_str(#arg)
17 }
18 }
19 .into()
20 } else {
21 syn::Error::new_spanned(&arg, "The relative path uses traversal")
22 .to_compile_error()
23 .into()
24 }
25 }
26 Err(e) => syn::Error::new_spanned(&arg, e).to_compile_error().into(),
27 }
28}
29
30#[proc_macro]
31pub fn generate_is_valid_path_code(input: TokenStream) -> TokenStream {
32 let ident = parse_macro_input!(input as Ident);
33
34 quote! {
35 ::std::convert::AsRef<::relative_path::RelativePath>
36 .as_ref(#ident)
37 .components()
38 .scan(0, |level, c| {
39 match c {
40 relative_path::Component::CurDir => (),
41 relative_path::Component::ParentDir => *level -= 1,
42 relative_path::Component::Normal(_) => *level += 1,
43 }
44 Some(*level)
45 })
46 .all(|level| level >= 0)
47 }
48 .into()
49}