use std::collections::HashSet;
use proc_macro::TokenStream;
use syn::{parse::Parse, parse_macro_input, DeriveInput, LitStr};
mod salt;
mod task;
#[proc_macro_derive(Task, attributes(title))]
pub fn derive_task(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
task::impl_task_derive(&ast)
}
#[proc_macro_derive(Salt, attributes(salt))]
pub fn derive_salt(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
salt::impl_salt_derive(&ast)
}
#[derive(Debug)]
pub(crate) struct VariadicStringParams {
format_str: String,
field_names: HashSet<String>,
}
impl VariadicStringParams {
fn extract_field_name(chars: &mut std::iter::Peekable<std::str::Chars>) -> Option<String> {
let mut field = String::new();
if chars
.clone()
.collect::<String>()
.as_str()
.starts_with("self.")
{
for _ in 0..5 {
chars.next();
}
}
while let Some(&c) = chars.peek() {
if c == '}' {
chars.next();
return Some(field);
}
field.push(chars.next().unwrap());
}
None }
fn parse_format_string(format_str: &str) -> HashSet<String> {
let mut field_names = HashSet::new();
let mut chars = format_str.chars().peekable();
while let Some(c) = chars.next() {
if c == '{' {
if let Some(field) = Self::extract_field_name(&mut chars) {
if !field.is_empty() {
field_names.insert(field);
}
}
}
}
field_names
}
}
impl Parse for VariadicStringParams {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let format_lit = input.parse::<LitStr>()?;
let format_str = format_lit.value();
let field_names = Self::parse_format_string(&format_str);
Ok(VariadicStringParams {
format_str,
field_names,
})
}
}