use proc_macro_error::proc_macro_error;
use quote::{quote, ToTokens};
use syn::{parse::Parse, ItemFn, LitStr, Token};
mod fields;
mod payload;
mod serde;
mod tokens;
mod validate;
mod validify;
#[proc_macro_derive(Validify, attributes(modify, validate, validify))]
#[proc_macro_error]
pub fn derive_validify(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = syn::parse(input).unwrap();
validify::r#impl::impl_validify(&ast).into()
}
#[proc_macro_derive(Validate, attributes(validate))]
#[proc_macro_error]
pub fn derive_validate(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = syn::parse(input).unwrap();
validate::r#impl::impl_validate(&input).into()
}
#[proc_macro_attribute]
pub fn schema_validation(
_attr: proc_macro::TokenStream,
input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let mut func: ItemFn = syn::parse(input).unwrap();
let start_tokens = syn::parse(
quote! {
let mut errors = ::validify::ValidationErrors::new();
}
.into(),
)
.unwrap();
func.block.stmts.insert(0, start_tokens);
let return_tokens = syn::parse(
quote!(if errors.is_empty() {
Ok(())
} else {
Err(errors)
})
.into(),
)
.unwrap();
func.block.stmts.push(return_tokens);
func.to_token_stream().into()
}
#[proc_macro_derive(Payload)]
#[proc_macro_error]
pub fn derive_payload(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = syn::parse(input).unwrap();
payload::r#impl::impl_payload(&input).into()
}
#[proc_macro]
pub fn schema_err(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let SchemaErr { code, message } = syn::parse(input).expect("invalid tokens");
let message = message.map(|m| quote!(.with_message(#m.to_string())));
quote!(
errors.add(::validify::ValidationError::new_schema(#code) #message);
)
.into()
}
struct SchemaErr {
code: LitStr,
message: Option<LitStr>,
}
impl Parse for SchemaErr {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let code = input.parse()?;
if input.peek(Token![,]) {
input.parse::<Token![,]>()?;
}
if input.is_empty() {
return Ok(SchemaErr {
code,
message: None,
});
}
let message = input.parse()?;
if input.peek(Token![,]) {
input.parse::<Token![,]>()?;
}
Ok(SchemaErr { code, message })
}
}