use proc_macro2::TokenStream;
use quote::quote;
use syn::{
Ident, ItemStruct, Meta, Path, Token,
parse::{Parse, ParseStream},
punctuated::Punctuated,
token::Comma,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DocRec {
NoReq,
StructDoc,
AllDoc,
}
impl DocRec {
pub fn need_struct(&self) -> bool {
match self {
DocRec::NoReq => false,
DocRec::StructDoc => true,
DocRec::AllDoc => true,
}
}
}
const DERIVE_WHITELIST: &[&str] = &["Debug", "PartialEq", "Eq", "PartialOrd", "Ord"];
pub struct BridgeableArgs {
pub derives_to_pass: Vec<Ident>,
pub compares_to_add: Vec<Ident>,
pub doc_rec: DocRec,
}
impl BridgeableArgs {
pub fn from_metas(metas: Punctuated<Meta, Comma>) -> syn::Result<Self> {
let mut derives_to_pass = Vec::new();
let mut compares_to_add = Vec::new();
for meta in metas {
match &meta {
Meta::List(list) if list.path.is_ident("derive") => {
let nested = list
.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)
.unwrap_or_default();
for nested_meta in nested {
if let Meta::Path(path) = nested_meta {
if let Some(ident) = path.get_ident() {
let s = ident.to_string();
if DERIVE_WHITELIST.contains(&s.as_str()) {
derives_to_pass.push(ident.clone());
}
if s == "PartialEq" || s == "PartialOrd" {
compares_to_add.push(ident.clone());
}
}
}
}
}
other => {
return Err(syn::Error::new_spanned(
other,
"unexpected bridgeable argument; expected `derive(...)` or `Document`",
));
}
}
}
Ok(BridgeableArgs {
derives_to_pass,
compares_to_add,
doc_rec: DocRec::NoReq,
})
}
}
impl Parse for BridgeableArgs {
fn parse(input: ParseStream) -> syn::Result<Self> {
let metas = Punctuated::<Meta, Token![,]>::parse_terminated(input)?;
Self::from_metas(metas)
}
}
pub mod bridgeable;
pub mod deep_ref;
pub mod documentation;
pub mod from_row;
pub mod library;
pub mod to_row;
pub fn magma(
args: BridgeableArgs,
item: &mut ItemStruct,
import_location: &Path,
) -> syn::Result<TokenStream> {
let documentation =
documentation::generate_documented_impl(&item, &import_location, args.doc_rec)?;
let ref_documentation =
documentation::ref_documentation(&item, &import_location, args.doc_rec)?;
let bridge_tokens = bridgeable::bridgeable(&args, item, import_location)?;
let deep_ref = deep_ref::deep_ref(&item, import_location, &args.derives_to_pass)?;
let deep_ref_rkyv = deep_ref::deep_ref_rkyv(&item, import_location)?;
let from_row = from_row::from_row(&item, import_location)?;
let ref_from_row = from_row::ref_from_row(&item, import_location)?;
let to_row = to_row::to_row(&item, import_location)?;
Ok(quote! {
#documentation
#ref_documentation
#bridge_tokens
#deep_ref
#deep_ref_rkyv
#from_row
#ref_from_row
#to_row
})
}