Skip to content

Commit

Permalink
change: compile error if different tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
Nukesor committed Apr 2, 2022
1 parent 3eac092 commit 3e8088a
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 74 deletions.
27 changes: 16 additions & 11 deletions codegen/src/generate/into/normal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ pub(crate) fn impl_into(params: &Parameters, fields: Vec<(Field, Field)>) -> Tok
fn into(params: &Parameters, fields: Vec<(Field, Field)>) -> TokenStream {
let mut assignments = TokenStream::new();

for (src_field, dest_field) in fields {
for (src_field, target_field) in fields {
let src_field_ident = src_field.ident;
let dest_field_ident = dest_field.ident;
let target_field_ident = target_field.ident;

// Find out, whether the fields are optional or not.
let src_field_type = match determine_field_type(src_field.ty) {
Expand All @@ -43,7 +43,7 @@ fn into(params: &Parameters, fields: Vec<(Field, Field)>) -> TokenStream {
continue;
}
};
let target_field_type = match determine_field_type(dest_field.ty) {
let target_field_type = match determine_field_type(target_field.ty) {
Ok(field) => field,
Err(err) => {
assignments.extend(vec![err]);
Expand All @@ -59,7 +59,7 @@ fn into(params: &Parameters, fields: Vec<(Field, Field)>) -> TokenStream {
target_type,
"",
quote! {
#dest_field_ident: src.#src_field_ident,
#target_field_ident: src.#src_field_ident,
}
)
}
Expand Down Expand Up @@ -87,7 +87,7 @@ fn into(params: &Parameters, fields: Vec<(Field, Field)>) -> TokenStream {
target_type,
"",
quote! {
#dest_field_ident: Some(src.#src_field_ident),
#target_field_ident: Some(src.#src_field_ident),
}
)
}
Expand All @@ -107,23 +107,28 @@ fn into(params: &Parameters, fields: Vec<(Field, Field)>) -> TokenStream {
) => {
// Handling the (Option<T>, Option<T>) case
if is_equal_type(&inner_src_type, &inner_target_type) {
quote! {
#dest_field_ident: src.#src_field_ident,
}
// Handling the (src: Option<Option<<T>>, dest: Option<T>) case
equal_type_or_err!(
inner_src_type,
inner_target_type,
"",
quote! {
#target_field_ident: src.#src_field_ident,
}
)
// Handling the (src: Option<Option<<T>>, target: Option<T>) case
} else if is_equal_type(&inner_src_type, &outer_target_type) {
err!(
inner_src_type,
"Inter-struct cannot 'into' an optional into a non-optional value."
)
// Handling the (src: Option<<T>, dest: Option<Option<T>)> case
// Handling the (src: Option<<T>, target: Option<Option<T>)> case
} else {
equal_type_or_err!(
outer_src_type,
inner_target_type,
"",
quote! {
#dest_field_ident: Some(src.#src_field_ident),
#target_field_ident: Some(src.#src_field_ident),
}
)
}
Expand Down
18 changes: 9 additions & 9 deletions codegen/src/generate/into/with_default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ pub(crate) fn impl_into_default(params: &Parameters, fields: Vec<(Field, Field)>
fn into_default(params: &Parameters, fields: Vec<(Field, Field)>) -> TokenStream {
let mut assignments = TokenStream::new();

for (src_field, dest_field) in fields {
for (src_field, target_field) in fields {
let src_field_ident = src_field.ident;
let dest_field_ident = dest_field.ident;
let target_field_ident = target_field.ident;

// Find out, whether the fields are optional or not.
let src_field_type = match determine_field_type(src_field.ty) {
Expand All @@ -44,7 +44,7 @@ fn into_default(params: &Parameters, fields: Vec<(Field, Field)>) -> TokenStream
continue;
}
};
let target_field_type = match determine_field_type(dest_field.ty) {
let target_field_type = match determine_field_type(target_field.ty) {
Ok(field) => field,
Err(err) => {
assignments.extend(vec![err]);
Expand All @@ -60,7 +60,7 @@ fn into_default(params: &Parameters, fields: Vec<(Field, Field)>) -> TokenStream
target_type,
"",
quote! {
#dest_field_ident: src.#src_field_ident,
#target_field_ident: src.#src_field_ident,
}
))
}
Expand All @@ -77,7 +77,7 @@ fn into_default(params: &Parameters, fields: Vec<(Field, Field)>) -> TokenStream
target_type,
"",
quote! {
#dest_field_ident: Some(src.#src_field_ident),
#target_field_ident: Some(src.#src_field_ident),
}
)),
// Both fields are optional. It can now be either of these:
Expand All @@ -97,19 +97,19 @@ fn into_default(params: &Parameters, fields: Vec<(Field, Field)>) -> TokenStream
// Handling the (Option<T>, Option<T>) case
if is_equal_type(&inner_src_type, &inner_target_type) {
Some(quote! {
#dest_field_ident: src.#src_field_ident,
#target_field_ident: src.#src_field_ident,
})
// Handling the (src: Option<Option<<T>>, dest: Option<T>) case
// Handling the (src: Option<Option<<T>>, target: Option<T>) case
} else if is_equal_type(&inner_src_type, &outer_target_type) {
None
// Handling the (src: Option<<T>, dest: Option<Option<T>)> case
// Handling the (src: Option<<T>, target: Option<Option<T>)> case
} else {
Some(equal_type_or_err!(
outer_src_type,
inner_target_type,
"",
quote! {
#dest_field_ident: Some(src.#src_field_ident.clone()),
#target_field_ident: Some(src.#src_field_ident.clone()),
}
))
}
Expand Down
38 changes: 24 additions & 14 deletions codegen/src/generate/merge/borrowed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ pub(crate) fn impl_borrowed(params: &Parameters, fields: Vec<(Field, Field)>) ->
/// All fields must implement `Clone`.
fn merge_ref(params: &Parameters, fields: Vec<(Field, Field)>) -> TokenStream {
let mut merge_code = TokenStream::new();
for (src_field, dest_field) in fields {
for (src_field, target_field) in fields {
let src_field_ident = src_field.ident;
let dest_field_ident = dest_field.ident;
let target_field_ident = target_field.ident;

// Find out, whether the fields are optional or not.
let src_field_type = match determine_field_type(src_field.ty) {
Expand All @@ -42,7 +42,7 @@ fn merge_ref(params: &Parameters, fields: Vec<(Field, Field)>) -> TokenStream {
continue;
}
};
let target_field_type = match determine_field_type(dest_field.ty) {
let target_field_type = match determine_field_type(target_field.ty) {
Ok(field) => field,
Err(err) => {
merge_code.extend(vec![err]);
Expand All @@ -58,7 +58,7 @@ fn merge_ref(params: &Parameters, fields: Vec<(Field, Field)>) -> TokenStream {
target_type,
"",
quote! {
target.#dest_field_ident = self.#src_field_ident.clone();
target.#target_field_ident = self.#src_field_ident.clone();
}
)
}
Expand All @@ -75,7 +75,7 @@ fn merge_ref(params: &Parameters, fields: Vec<(Field, Field)>) -> TokenStream {
"Inner ",
quote! {
if let Some(value) = self.#src_field_ident.as_ref() {
target.#dest_field_ident = value.clone();
target.#target_field_ident = value.clone();
}
}
)
Expand All @@ -92,7 +92,7 @@ fn merge_ref(params: &Parameters, fields: Vec<(Field, Field)>) -> TokenStream {
target_type,
"",
quote! {
self.#dest_field_ident = Some(src.#src_field_ident.clone());
self.#target_field_ident = Some(src.#src_field_ident.clone());
}
)
}
Expand All @@ -112,24 +112,34 @@ fn merge_ref(params: &Parameters, fields: Vec<(Field, Field)>) -> TokenStream {
) => {
// Handling the (Option<T>, Option<T>) case
if is_equal_type(&inner_src_type, &inner_target_type) {
quote! {
target.#dest_field_ident = self.#src_field_ident.clone();
}
equal_type_or_err!(
inner_src_type,
inner_target_type,
"",
quote! {
target.#target_field_ident = self.#src_field_ident.clone();
}
)
// Handling the (Option<Option<<T>>, Option<T>) case
} else if is_equal_type(&inner_src_type, &outer_target_type) {
quote! {
if let Some(value) = self.#src_field_ident.as_ref() {
target.#dest_field_ident = value.clone();
equal_type_or_err!(
inner_src_type,
outer_target_type,
"",
quote! {
if let Some(value) = self.#src_field_ident.as_ref() {
target.#target_field_ident = value.clone();
}
}
}
)
// Handling the (Option<<T>, Option<Option<T>)> case
} else {
equal_type_or_err!(
outer_src_type,
inner_target_type,
"",
quote! {
target.#dest_field_ident = Some(self.#src_field_ident.clone());
target.#target_field_ident = Some(self.#src_field_ident.clone());
}
)
}
Expand Down
99 changes: 67 additions & 32 deletions codegen/src/generate/merge/owned.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ pub(crate) fn impl_owned(params: &Parameters, fields: Vec<(Field, Field)>) -> To
/// Generate the [inter_struct::merge::StructMerge::merge] function for the given structs.
fn merge(params: &Parameters, fields: Vec<(Field, Field)>) -> TokenStream {
let mut merge_code = TokenStream::new();
for (src_field, dest_field) in fields {
for (src_field, target_field) in fields {
let src_field_ident = src_field.ident;
let dest_field_ident = dest_field.ident;
let target_field_ident = target_field.ident;

// Find out, whether the fields are optional or not.
let src_field_type = match determine_field_type(src_field.ty) {
Expand All @@ -40,34 +40,59 @@ fn merge(params: &Parameters, fields: Vec<(Field, Field)>) -> TokenStream {
continue;
}
};
let dest_field_type = match determine_field_type(dest_field.ty) {
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, dest_field_type) {
let snippet = match (src_field_type, target_field_type) {
// Both fields have the same type
(FieldType::Normal(_), FieldType::Normal(_)) => {
quote! {
dest.#dest_field_ident = self.#src_field_ident;
}
(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;
}
)
}
// The src is optional and needs to be `Some(T)` to be merged.
(FieldType::Optional { .. }, FieldType::Normal(_)) => {
quote! {
if let Some(value) = self.#src_field_ident {
dest.#dest_field_ident = value;
(
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;
}
}
}
)
}
// The dest is optional and needs to be wrapped in `Some(T)` to be merged.
(FieldType::Normal(_), FieldType::Optional { .. }) => {
quote! {
dest.#dest_field_ident = Some(self.#src_field_ident);
}
// The target is optional and needs to be wrapped in `Some(T)` to be merged.
(
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);
}
)
}
// Both fields are optional. It can now be either of these:
// - (Option<T>, Option<T>)
Expand All @@ -79,30 +104,40 @@ fn merge(params: &Parameters, fields: Vec<(Field, Field)>) -> TokenStream {
outer: outer_src_type,
},
FieldType::Optional {
inner: inner_dest_type,
outer: outer_dest_type,
inner: inner_target_type,
outer: outer_target_type,
},
) => {
// Handling the (Option<T>, Option<T>) case
if is_equal_type(&inner_src_type, &inner_dest_type) {
quote! {
dest.#dest_field_ident = self.#src_field_ident;
}
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;
}
)
// Handling the (Option<Option<<T>>, Option<T>) case
} else if is_equal_type(&inner_src_type, &outer_dest_type) {
quote! {
if let Some(value) = self.#src_field_ident {
dest.#dest_field_ident = value;
} 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;
}
}
}
)
// Handling the (Option<<T>, Option<Option<T>)> case
} else {
equal_type_or_err!(
outer_src_type,
inner_dest_type,
inner_target_type,
"",
quote! {
dest.#dest_field_ident = Some(self.#src_field_ident);
target.#target_field_ident = Some(self.#src_field_ident);
}
)
}
Expand All @@ -118,7 +153,7 @@ fn merge(params: &Parameters, fields: Vec<(Field, Field)>) -> TokenStream {

let target_path = &params.target_path;
quote! {
fn merge_into(self, dest: &mut #target_path) {
fn merge_into(self, target: &mut #target_path) {
#merge_code
}
}
Expand Down
4 changes: 3 additions & 1 deletion testing/tests/merge/incompatible_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ use inter_struct::prelude::*;
#[derive(InterStruct)]
#[merge("crate::MergeStruct")]
pub struct FromStruct {
pub normal: String,
pub normal: i32,
pub optional: i32,
pub optional_optional: Option<Option<i32>>,
}

pub struct MergeStruct {
pub normal: String,
pub optional: Option<String>,
pub optional_optional: Option<Option<String>>,
}

fn main() {}
Loading

0 comments on commit 3e8088a

Please sign in to comment.