use generate::generate_impl;
use module::get_struct_from_path;
use path::{get_root_src_path, parse_input_paths};
use proc_macro::TokenStream;
use syn::{parse_macro_input, Expr, ExprPath, ItemStruct};
macro_rules! err {
($span:expr, $($text:expr),*) => {
{
let message = format!($($text,)*);
let span = $span.span();
quote::quote_spanned!( span => compile_error!(#message); )
}
}
}
macro_rules! ok_or_err_return {
($expr:expr, $span:ident, $($text:expr),*) => {
match $expr {
Ok(result) => result,
Err(error) => {
return Err(err!($span, $($text,)* error));
}
}
}
}
mod generate;
mod module;
mod path;
#[proc_macro_attribute]
pub fn struct_merge(args: TokenStream, struct_ast: TokenStream) -> TokenStream {
struct_merge_base(args, struct_ast, Mode::Owned)
}
#[proc_macro_attribute]
pub fn struct_merge_ref(args: TokenStream, struct_ast: TokenStream) -> TokenStream {
struct_merge_base(args, struct_ast, Mode::Borrowed)
}
enum Mode {
Owned,
Borrowed,
}
pub(crate) struct Parameters {
pub src_struct: ItemStruct,
pub target_path: ExprPath,
pub target_struct: ItemStruct,
}
fn struct_merge_base(args: TokenStream, mut struct_ast: TokenStream, mode: Mode) -> TokenStream {
let parsed_args = parse_macro_input!(args as Expr);
let src_root_path = match get_root_src_path(&parsed_args) {
Some(path) => path,
None => return struct_ast,
};
let cloned_struct_ast = struct_ast.clone();
let src_struct = parse_macro_input!(cloned_struct_ast as ItemStruct);
let paths = parse_input_paths(parsed_args);
let mut impls = Vec::new();
for target_path in paths {
let target_struct = match get_struct_from_path(src_root_path.clone(), target_path.clone()) {
Ok(ast) => ast,
Err(error) => {
impls.push(error);
continue;
}
};
let params = Parameters {
src_struct: src_struct.clone(),
target_path,
target_struct,
};
match generate_impl(&mode, params) {
Ok(ast) => impls.push(ast),
Err(error) => {
impls.push(error);
continue;
}
}
}
struct_ast.extend(impls.into_iter().map(TokenStream::from));
struct_ast
}