use proc_macro::TokenStream;
use quote::quote;
use syn::punctuated::Punctuated;
use syn::{parse_macro_input, Expr, Lit, Token};
#[proc_macro]
pub fn path(input: TokenStream) -> TokenStream {
let args = parse_macro_input!(input with Punctuated::<Expr, Token![,]>::parse_terminated);
let mut component_exprs = Vec::new();
for expr in &args {
match expr {
Expr::Lit(expr_lit) => match &expr_lit.lit {
Lit::Str(s) => {
for component in s.value().split('/').filter(|c| !c.is_empty()) {
if let Err(msg) = structfs_path_validation::validate_component(component) {
return syn::Error::new(
s.span(),
format!("invalid path component '{component}': {msg}"),
)
.to_compile_error()
.into();
}
component_exprs.push(quote! { ::std::string::String::from(#component) });
}
}
Lit::Int(n) => {
let s = n.base10_digits();
if let Err(msg) = structfs_path_validation::validate_component(s) {
return syn::Error::new(
n.span(),
format!("invalid path component '{s}': {msg}"),
)
.to_compile_error()
.into();
}
component_exprs.push(quote! { ::std::string::String::from(#s) });
}
other => {
return syn::Error::new(
other.span(),
"expected string literal, integer literal, or PathComponent expression",
)
.to_compile_error()
.into();
}
},
other => {
component_exprs.push(quote! {
::std::string::String::from((#other).validated_str())
});
}
}
}
quote! {
::structfs_core_store::Path::from_validated_components(
::std::vec![#(#component_exprs),*]
)
}
.into()
}