diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 34f3709..8a2e91a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,18 +24,10 @@ jobs: nix develop -c cargo run --no-default-features --example json nix develop -c cargo run --no-default-features --example rename-patch-struct nix develop -c cargo run --no-default-features --example patch-attr + nix develop -c cargo run --no-default-features --example op nix develop -c cargo test --no-default-features - name: Test with default features run: | nix develop -c cargo run --example status nix develop -c cargo test - - - name: Test add feature - run: | - nix develop -c cargo run --features=add --example instance - nix develop -c cargo run --features=add --example diff - nix develop -c cargo run --features=add --example json - nix develop -c cargo run --features=add --example rename-patch-struct - nix develop -c cargo run --features=add --example patch-attr - nix develop -c cargo test --features=add diff --git a/struct-patch-derive/src/lib.rs b/struct-patch-derive/src/lib.rs index 2ad2223..cfc7e16 100644 --- a/struct-patch-derive/src/lib.rs +++ b/struct-patch-derive/src/lib.rs @@ -100,39 +100,23 @@ impl Patch { #[cfg(not(feature = "status"))] let patch_status_impl = quote!(); - #[cfg(feature = "add")] - let add_impl = quote! { - impl #generics core::ops::Add<#name #generics> for #struct_name #generics #where_clause { + let op_impl = quote! { + impl #generics core::ops::Shl<#name #generics> for #struct_name #generics #where_clause { type Output = Self; - fn add(mut self, rhs: #name #generics) -> Self { + fn shl(mut self, rhs: #name #generics) -> Self { self.apply(rhs); self } } - impl #generics core::ops::Add<#struct_name #generics> for #name #generics #where_clause { - type Output = #struct_name #generics; - - fn add(mut self, rhs: #struct_name #generics) -> #struct_name #generics { - let mut rhs = rhs; - rhs.apply(self); - rhs - } - } - - impl #generics core::ops::Add for #name #generics #where_clause { + impl #generics core::ops::Shl<#name #generics> for #name #generics #where_clause { type Output = Self; - fn add(mut self, rhs: Self) -> Self { + fn shl(mut self, rhs: #name #generics) -> Self { Self { #( - #renamed_field_names: match (self.#renamed_field_names, rhs.#renamed_field_names) { - (Some(a), Some(b)) => Some(a + b), - (Some(a), None) => Some(a), - (None, Some(b)) => Some(b), - (None, None) => None, - }, + #renamed_field_names: rhs.#renamed_field_names.or(self.#renamed_field_names), )* #( #original_field_names: rhs.#original_field_names.or(self.#original_field_names), @@ -140,9 +124,47 @@ impl Patch { } } } + + // TODO + // We need unstable feature to make sure the type of field for add feature + // https://doc.rust-lang.org/std/any/fn.type_name_of_val.html + // impl #generics core::ops::Add for #name #generics #where_clause { + // type Output = Self; + + // fn add(mut self, rhs: Self) -> Self { + // Self { + // #( + // #renamed_field_names: match (self.#renamed_field_names, rhs.#renamed_field_names) { + // (Some(a), Some(b)) => { + // if std::any::type_name_of_val(&a) == "usize" { + // Some(a + b) + // } else { + // Some(b) + // } + // }, + // (Some(a), None) => Some(a), + // (None, Some(b)) => Some(b), + // (None, None) => None, + // }, + // )* + // #( + // #original_field_names: match (self.#original_field_names, rhs.#original_field_names) { + // (Some(a), Some(b)) => { + // if std::any::type_name_of_val(&a) == "usize" { + // Some(a + b) + // } else { + // Some(b) + // } + // }, + // (Some(a), None) => Some(a), + // (None, Some(b)) => Some(b), + // (None, None) => None, + // }, + // )* + // } + // } + // } }; - #[cfg(not(feature = "add"))] - let add_impl = quote!(); let patch_impl = quote! { impl #generics struct_patch::traits::Patch< #name #generics > for #struct_name #generics #where_clause { @@ -208,7 +230,7 @@ impl Patch { #patch_impl - #add_impl + #op_impl }) } diff --git a/struct-patch/examples/add.rs b/struct-patch/examples/add.rs deleted file mode 100644 index 7cd9f7a..0000000 --- a/struct-patch/examples/add.rs +++ /dev/null @@ -1,37 +0,0 @@ -use struct_patch::Patch; - -#[derive(Default, Patch)] -#[patch(attribute(derive(Debug, Default)))] -struct Item { - field_complete: bool, - field_int: usize, - field_string: String, -} - -// Generated by Patch derive macro -// -// #[derive(Debug, Default)] // pass by patch(attribute(...)) -// struct ItemPatch { -// field_complete: Option, -// field_int: Option, -// field_string: Option, -// } - -fn main() { - let mut item = Item::default(); - - let mut patch = Item::new_empty_patch(); - - patch.field_int = Some(7); - - assert_eq!( - format!("{patch:?}"), - "ItemPatch { field_complete: None, field_int: Some(7), field_string: None }" - ); - - item.apply(patch); - - assert_eq!(item.field_complete, false); - assert_eq!(item.field_int, 7); - assert_eq!(item.field_string, ""); -} diff --git a/struct-patch/examples/instance.rs b/struct-patch/examples/instance.rs index df8d1b4..e417915 100644 --- a/struct-patch/examples/instance.rs +++ b/struct-patch/examples/instance.rs @@ -35,27 +35,24 @@ fn main() { assert_eq!(item.field_int, 7); assert_eq!(item.field_string, ""); - #[cfg(feature = "add")] - { - let another_patch = ItemPatch { - field_complete: None, - field_int: None, - field_string: Some("from another patch".into()), - }; - let new_item = item + another_patch; - - assert_eq!(new_item.field_complete, false); - assert_eq!(new_item.field_int, 7); - assert_eq!(new_item.field_string, "from another patch"); - - let the_other_patch = ItemPatch { - field_complete: Some(true), - field_int: None, - field_string: None, - }; - let final_item = the_other_patch + new_item; - assert_eq!(final_item.field_complete, true); - assert_eq!(final_item.field_int, 7); - assert_eq!(final_item.field_string, "from another patch"); - } + let another_patch = ItemPatch { + field_complete: None, + field_int: None, + field_string: Some("from another patch".into()), + }; + let new_item = item << another_patch; + + assert_eq!(new_item.field_complete, false); + assert_eq!(new_item.field_int, 7); + assert_eq!(new_item.field_string, "from another patch"); + + let the_other_patch = ItemPatch { + field_complete: Some(true), + field_int: None, + field_string: None, + }; + let final_item = new_item << the_other_patch; + assert_eq!(final_item.field_complete, true); + assert_eq!(final_item.field_int, 7); + assert_eq!(final_item.field_string, "from another patch"); } diff --git a/struct-patch/src/lib.rs b/struct-patch/src/lib.rs index 385ffbd..35e1b9d 100644 --- a/struct-patch/src/lib.rs +++ b/struct-patch/src/lib.rs @@ -281,9 +281,8 @@ mod tests { ); } - #[cfg(feature = "add")] #[test] - fn test_add() { + fn test_shl() { #[derive(Patch, Debug, PartialEq)] struct Item { field: u32, @@ -300,7 +299,7 @@ mod tests { }; assert_eq!( - item + patch, + item << patch, Item { field: 1, other: String::from("bye") @@ -308,7 +307,6 @@ mod tests { ); } - #[cfg(feature = "add")] #[test] fn test_add_combined() { #[derive(Patch, Debug, PartialEq)]