use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use syn::Field;
use crate::error::*;
use crate::generate::field::*;
use crate::generate::types::*;
use crate::generate::Parameters;
pub(crate) fn impl_owned(params: &Parameters, fields: Vec<(Field, Field)>) -> TokenStream {
let mut functions_tokens = TokenStream::new();
let stream = merge(params, fields);
functions_tokens.extend(vec![stream]);
let src_ident = ¶ms.src_struct.ident;
let target_path = ¶ms.target_path;
quote! {
impl inter_struct::merge::StructMergeInto<#target_path> for #src_ident {
#functions_tokens
}
}
}
fn merge(params: &Parameters, fields: Vec<(Field, Field)>) -> TokenStream {
let mut merge_code = TokenStream::new();
for (src_field, target_field) in fields {
let src_field_ident = src_field.ident;
let target_field_ident = target_field.ident;
let src_field_type = match determine_field_type(src_field.ty) {
Ok(field) => field,
Err(err) => {
merge_code.extend(vec![err]);
continue;
}
};
let target_field_type = match determine_field_type(target_field.ty) {
Ok(field) => field,
Err(err) => {
merge_code.extend(vec![err]);
continue;
}
};
let snippet = match (src_field_type, target_field_type) {
(FieldType::Normal(src_type), FieldType::Normal(target_type)) => {
equal_type_or_err!(
src_type,
target_type,
quote! {
target.#target_field_ident = self.#src_field_ident;
}
)
}
(
FieldType::Optional {
inner: src_type, ..
},
FieldType::Normal(target_type),
) => {
equal_type_or_err!(
src_type,
target_type,
quote! {
if let Some(value) = self.#src_field_ident {
target.#target_field_ident = value;
}
}
)
}
(
FieldType::Normal(src_type),
FieldType::Optional {
inner: target_type, ..
},
) => {
equal_type_or_err!(
src_type,
target_type,
quote! {
target.#target_field_ident = Some(self.#src_field_ident);
}
)
}
(
FieldType::Optional {
inner: inner_src_type,
outer: outer_src_type,
},
FieldType::Optional {
inner: inner_target_type,
outer: outer_target_type,
},
) => {
if is_equal_type(&inner_src_type, &inner_target_type) {
equal_type_or_err!(
inner_src_type,
inner_target_type,
quote! {
target.#target_field_ident = self.#src_field_ident;
}
)
} else if is_equal_type(&inner_src_type, &outer_target_type) {
equal_type_or_err!(
inner_src_type,
outer_target_type,
quote! {
if let Some(value) = self.#src_field_ident {
target.#target_field_ident = value;
}
}
)
} else {
equal_type_or_err!(
outer_src_type,
inner_target_type,
quote! {
target.#target_field_ident = Some(self.#src_field_ident);
}
)
}
}
(FieldType::Invalid, _) | (_, FieldType::Invalid) => continue,
};
merge_code.extend(vec![snippet]);
}
let merge_code = merge_code.to_token_stream();
let target_path = ¶ms.target_path;
quote! {
fn merge_into(self, target: &mut #target_path) {
#merge_code
}
}
}