use proc_macro2::TokenStream;
use syn::Fields;
use syn::{Expr, ItemStruct, Path};
use crate::error::err;
use crate::module::get_struct_from_path;
mod field;
mod types;
pub mod into;
pub mod merge;
pub(crate) struct Parameters {
pub src_struct: ItemStruct,
pub target_path: Path,
pub target_struct: ItemStruct,
}
pub(crate) enum Mode {
Merge,
MergeRef,
Into,
IntoDefault,
}
fn inter_struct_base(
src_root_path: &std::path::Path,
src_struct: &ItemStruct,
parsed_args: Expr,
mode: Mode,
) -> Vec<TokenStream> {
let paths = crate::parse::input_paths(parsed_args);
let paths = match paths {
Ok(paths) => paths,
Err(err) => return vec![err],
};
let mut impls = Vec::new();
for target_path in paths {
let target_struct =
match get_struct_from_path(src_root_path.to_path_buf(), 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;
}
}
}
impls
}
pub(crate) fn generate_impl(mode: &Mode, params: Parameters) -> Result<TokenStream, TokenStream> {
let target_fields = match params.target_struct.fields.clone() {
Fields::Named(fields) => fields,
_ => {
return Err(err!(
params.target_struct,
"inter_struct only works on structs with named fields."
));
}
};
let src_fields = match params.src_struct.fields.clone() {
Fields::Named(fields) => fields,
_ => {
return Err(err!(
params.target_struct,
"inter_struct only works on structs with named fields."
));
}
};
let mut similar_fields = Vec::new();
for src_field in src_fields.named {
let src_ident = src_field.ident.clone().unwrap();
for target_field in target_fields.named.clone() {
let target_ident = target_field.clone().ident.unwrap();
if src_ident == target_ident {
similar_fields.push((src_field.clone(), target_field));
}
}
}
match *mode {
Mode::Merge => Ok(merge::owned::impl_owned(¶ms, similar_fields)),
Mode::MergeRef => Ok(merge::borrowed::impl_borrowed(¶ms, similar_fields)),
Mode::Into => Ok(into::normal::impl_into(¶ms, similar_fields, false)),
Mode::IntoDefault => Ok(into::normal::impl_into(¶ms, similar_fields, true)),
}
}