1use proc_macro2::TokenStream;
2use quote::quote;
3use syn::{
4 Ident, ItemStruct, Meta, Path, Token,
5 parse::{Parse, ParseStream},
6 punctuated::Punctuated,
7 token::Comma,
8};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum DocRec {
13 NoReq,
15 StructDoc,
17 AllDoc,
19}
20
21impl DocRec {
22 pub fn need_struct(&self) -> bool {
23 match self {
24 DocRec::NoReq => false,
25 DocRec::StructDoc => true,
26 DocRec::AllDoc => true,
27 }
28 }
29}
30
31const DERIVE_WHITELIST: &[&str] = &["Debug", "PartialEq", "Eq", "PartialOrd", "Ord"];
33
34pub struct BridgeableArgs {
51 pub derives_to_pass: Vec<Ident>,
53 pub compares_to_add: Vec<Ident>,
56 pub doc_rec: DocRec,
57}
58
59impl BridgeableArgs {
60 pub fn from_metas(metas: Punctuated<Meta, Comma>) -> syn::Result<Self> {
63 let mut derives_to_pass = Vec::new();
64 let mut compares_to_add = Vec::new();
65
66 for meta in metas {
67 match &meta {
68 Meta::List(list) if list.path.is_ident("derive") => {
70 let nested = list
71 .parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)
72 .unwrap_or_default();
73
74 for nested_meta in nested {
75 if let Meta::Path(path) = nested_meta
76 && let Some(ident) = path.get_ident()
77 {
78 let s = ident.to_string();
79
80 if DERIVE_WHITELIST.contains(&s.as_str()) {
81 derives_to_pass.push(ident.clone());
82 }
83
84 if s == "PartialEq" || s == "PartialOrd" {
85 compares_to_add.push(ident.clone());
86 }
87 }
88 }
89 }
90 other => {
91 return Err(syn::Error::new_spanned(
92 other,
93 "unexpected bridgeable argument; expected `derive(...)` or `Document`",
94 ));
95 }
96 }
97 }
98
99 Ok(BridgeableArgs {
100 derives_to_pass,
101 compares_to_add,
102 doc_rec: DocRec::NoReq,
103 })
104 }
105}
106
107impl Parse for BridgeableArgs {
109 fn parse(input: ParseStream) -> syn::Result<Self> {
110 let metas = Punctuated::<Meta, Token![,]>::parse_terminated(input)?;
111 Self::from_metas(metas)
112 }
113}
114
115pub mod bridgeable;
116pub mod deep_ref;
117pub mod documentation;
118pub mod from_row;
119pub mod library;
120pub mod to_row;
121
122pub fn magma(
123 args: BridgeableArgs,
124 item: &mut ItemStruct,
125 import_location: &Path,
126) -> syn::Result<TokenStream> {
127 let documentation =
129 documentation::generate_documented_impl(item, import_location, args.doc_rec)?;
130 let ref_documentation = documentation::ref_documentation(item, import_location, args.doc_rec)?;
131
132 let bridge_tokens = bridgeable::bridgeable(&args, item, import_location)?;
135
136 let deep_ref = deep_ref::deep_ref(item, import_location, &args.derives_to_pass)?;
138 let deep_ref_rkyv = deep_ref::deep_ref_rkyv(item, import_location)?;
139
140 let from_row = from_row::from_row(item, import_location)?;
142 let ref_from_row = from_row::ref_from_row(item, import_location)?;
143
144 let to_row = to_row::to_row(item, import_location)?;
146
147 Ok(quote! {
148 #documentation
149 #ref_documentation
150 #bridge_tokens
151 #deep_ref
152 #deep_ref_rkyv
153 #from_row
154 #ref_from_row
155 #to_row
156 })
157}