aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrederick Mayle <fmayle@google.com>2022-12-09 18:27:28 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2022-12-09 18:27:28 +0000
commit79173e2c0d662eceacd1feed84ef303e2471b1dd (patch)
treed96293100261c58fcaa7023504f7717ba8604480
parente59a73e955cab538261ae9b9bf64fd02a7cc2c2d (diff)
parentd23326017413043f14310af13109b326873737dc (diff)
downloadmerge-79173e2c0d662eceacd1feed84ef303e2471b1dd.tar.gz
import merge-0.1.0 am: d6b6c53f3e am: b02ae3cc33 am: d233260174
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/merge/+/2336343 Change-Id: I8000735d340042a60004d56a7092f22831170e8b Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--CHANGELOG.md9
-rw-r--r--Cargo.lock372
-rw-r--r--Cargo.toml51
-rw-r--r--Cargo.toml.orig34
l---------LICENSE1
-rw-r--r--LICENSES/Apache-2.0.txt202
-rw-r--r--METADATA19
-rw-r--r--MODULE_LICENSE_APACHE20
-rw-r--r--OWNERS2
-rw-r--r--README.md98
-rw-r--r--examples/args.rs43
-rw-r--r--examples/user.rs31
-rw-r--r--src/lib.rs223
-rw-r--r--tests/compile.rs9
-rw-r--r--tests/compile/derive-enum.rs13
-rw-r--r--tests/compile/derive-enum.stderr7
-rw-r--r--tests/compile/derive-invalid-attribute.rs12
-rw-r--r--tests/compile/derive-invalid-attribute.stderr5
-rw-r--r--tests/compile/derive-invalid-skip.rs12
-rw-r--r--tests/compile/derive-invalid-skip.stderr5
-rw-r--r--tests/compile/derive-invalid-strategy.rs16
-rw-r--r--tests/compile/derive-invalid-strategy.stderr13
-rw-r--r--tests/compile/derive-missing-strategy.rs12
-rw-r--r--tests/compile/derive-missing-strategy.stderr5
-rw-r--r--tests/compile/derive-no-strategy.rs12
-rw-r--r--tests/compile/derive-no-strategy.stderr5
-rw-r--r--tests/compile/derive-u8.rs12
-rw-r--r--tests/compile/derive-u8.stderr7
-rw-r--r--tests/derive.rs540
-rw-r--r--tests/impls.rs16
-rw-r--r--tests/strategies.rs122
31 files changed, 1908 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..5e52de0
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,9 @@
+<!---
+SPDX-FileCopyrightText: 2020 Robin Krahl <robin.krahl@ireas.org>
+SPDX-License-Identifier: CC0-1.0
+-->
+
+# v0.1.0 (2020-09-01)
+
+Initial release providing the `Merge` trait and some merge strategies in the
+`bool`, `num`, `ord` and `vec` modules.
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..7ffd14e
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,372 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+# SPDX-FileCopyrightText: 2020 Robin Krahl <robin.krahl@ireas.org>
+# SPDX-License-Identifier: CC0-1.0
+[[package]]
+name = "ansi_term"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "bitflags"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "clap"
+version = "2.33.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "envy"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "glob"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "heck"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "itoa"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "libc"
+version = "0.2.76"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "merge"
+version = "0.1.0"
+dependencies = [
+ "envy 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "merge_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)",
+ "structopt 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "trybuild 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "merge_derive"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro-error 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "proc-macro-error"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro-error-attr 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)",
+ "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "serde"
+version = "1.0.114"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.114"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.57"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "strsim"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "structopt"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "structopt-derive 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "structopt-derive"
+version = "0.4.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro-error 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "syn-mid"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "toml"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "trybuild"
+version = "1.0.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)",
+ "termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "vec_map"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "version_check"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[metadata]
+"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+"checksum autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+"checksum clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)" = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
+"checksum envy 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f938a4abd5b75fe3737902dbc2e79ca142cc1526827a9e40b829a086758531a9"
+"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
+"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
+"checksum hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9"
+"checksum itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
+"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+"checksum libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)" = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3"
+"checksum merge_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "209d075476da2e63b4b29e72a2ef627b840589588e71400a25e3565c4f849d07"
+"checksum num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
+"checksum proc-macro-error 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fc175e9777c3116627248584e8f8b3e2987405cabe1c0adf7d1dd28f09dc7880"
+"checksum proc-macro-error-attr 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3cc9795ca17eb581285ec44936da7fc2335a3f34f2ddd13118b6f4d515435c50"
+"checksum proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12"
+"checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
+"checksum ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
+"checksum serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)" = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3"
+"checksum serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)" = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e"
+"checksum serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)" = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c"
+"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
+"checksum structopt 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc388d94ffabf39b5ed5fadddc40147cb21e605f53db6f8f36a625d27489ac5"
+"checksum structopt-derive 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5e2513111825077552a6751dfad9e11ce0fba07d7276a3943a037d7e93e64c5f"
+"checksum syn 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)" = "4cdb98bcb1f9d81d07b536179c269ea15999b5d14ea958196413869445bb5250"
+"checksum syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a"
+"checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
+"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
+"checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a"
+"checksum trybuild 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)" = "bbe777c4e2060f44d83892be1189f96200be8ed3d99569d5c2d5ee26e62c0ea9"
+"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
+"checksum unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
+"checksum unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
+"checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
+"checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
+"checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+"checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..0ced552
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,51 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+edition = "2018"
+name = "merge"
+version = "0.1.0"
+authors = ["Robin Krahl <robin.krahl@ireas.org>"]
+exclude = [".builds/*"]
+description = "Merge multiple values into one"
+keywords = ["merge", "macros", "derive"]
+categories = ["rust-patterns"]
+license = "Apache-2.0 OR MIT"
+repository = "https://git.sr.ht/~ireas/merge-rs"
+[dependencies.merge_derive]
+version = "0.1.0"
+optional = true
+
+[dependencies.num-traits]
+version = "0.2.12"
+optional = true
+[dev-dependencies.envy]
+version = "0.4"
+
+[dev-dependencies.serde]
+version = "1.0"
+features = ["derive"]
+
+[dev-dependencies.structopt]
+version = "0.3"
+
+[dev-dependencies.toml]
+version = "0.5"
+
+[dev-dependencies.trybuild]
+version = "1.0"
+
+[features]
+default = ["derive", "num", "std"]
+derive = ["merge_derive"]
+num = ["num-traits"]
+std = []
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644
index 0000000..aac6575
--- /dev/null
+++ b/Cargo.toml.orig
@@ -0,0 +1,34 @@
+# SPDX-FileCopyrightText: 2020 Robin Krahl <robin.krahl@ireas.org>
+# SPDX-License-Identifier: CC0-1.0
+
+[package]
+name = "merge"
+version = "0.1.0"
+authors = ["Robin Krahl <robin.krahl@ireas.org>"]
+edition = "2018"
+description = "Merge multiple values into one"
+repository = "https://git.sr.ht/~ireas/merge-rs"
+keywords = ["merge", "macros", "derive"]
+categories = ["rust-patterns"]
+license = "Apache-2.0 OR MIT"
+exclude = [".builds/*"]
+
+[dependencies]
+merge_derive = { path = "merge_derive", version = "0.1.0", optional = true }
+num-traits = { version = "0.2.12", optional = true }
+
+[dev-dependencies]
+envy = "0.4"
+toml = "0.5"
+trybuild = "1.0"
+structopt = "0.3"
+
+[dev-dependencies.serde]
+version = "1.0"
+features = ["derive"]
+
+[features]
+default = ["derive", "num", "std"]
+derive = ["merge_derive"]
+num = ["num-traits"]
+std = []
diff --git a/LICENSE b/LICENSE
new file mode 120000
index 0000000..5431dc1
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1 @@
+LICENSES/Apache-2.0.txt \ No newline at end of file
diff --git a/LICENSES/Apache-2.0.txt b/LICENSES/Apache-2.0.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/LICENSES/Apache-2.0.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..3204e4f
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,19 @@
+name: "merge"
+description: "Merge multiple values into one"
+third_party {
+ url {
+ type: HOMEPAGE
+ value: "https://crates.io/crates/merge"
+ }
+ url {
+ type: ARCHIVE
+ value: "https://static.crates.io/crates/merge/merge-0.1.0.crate"
+ }
+ version: "0.1.0"
+ license_type: NOTICE
+ last_upgrade_date {
+ year: 2022
+ month: 11
+ day: 28
+ }
+}
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..4e1e118
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,2 @@
+include platform/prebuilts/rust:master:/OWNERS
+fmayle@google.com
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..1bdb16a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,98 @@
+<!---
+Copyright (C) 2020 Robin Krahl <robin.krahl@ireas.org>
+SPDX-License-Identifier: CC0-1.0
+-->
+
+# merge-rs
+
+The `merge` crate provides the `Merge` trait that can be used to merge multiple
+values into one:
+
+```rust
+trait Merge {
+ fn merge(&mut self, other: Self);
+}
+```
+
+`Merge` is implemented for `Option` and can be derived for structs:
+
+<!-- should be kept in sync with examples/user.rs -->
+```rust
+use merge::Merge;
+
+#[derive(Merge)]
+struct User {
+ // Fields with the skip attribute are skipped by Merge
+ #[merge(skip)]
+ pub name: &'static str,
+
+ // The Merge implementation for Option replaces its value if it is None
+ pub location: Option<&'static str>,
+
+ // The strategy attribute is used to customize the merge behavior
+ #[merge(strategy = merge::vec::append)]
+ pub groups: Vec<&'static str>,
+}
+
+let defaults = User {
+ name: "",
+ location: Some("Internet"),
+ groups: vec!["rust"],
+};
+let mut ferris = User {
+ name: "Ferris",
+ location: None,
+ groups: vec!["mascot"],
+};
+ferris.merge(defaults);
+
+assert_eq!("Ferris", ferris.name);
+assert_eq!(Some("Internet"), ferris.location);
+assert_eq!(vec!["mascot", "rust"], ferris.groups);
+```
+
+A merge strategy is a function with the signature `fn merge<T>(left: &mut T,
+right: T)` that merges `right` into `left`. The `merge` crate provides
+strategies for the most common types, but you can also define your own
+strategies.
+
+The trait can be used to merge configuration from different sources, for
+example environment variables, multiple configuration files and command-line
+arguments, see the `args.rs` example.
+
+## Features
+
+This crate has the following features:
+
+- `derive` (default): Enables the derive macro for the `Merge` trait using the
+ `merge_derive` crate.
+- `num` (default): Enables the merge strategies in the `num` module that
+ require the `num_traits` crate.
+- `std` (default): Enables the merge strategies in the `vec` module that
+ require the standard library. If this feature is not set, `merge` is a
+ `no_std` library.
+
+## Minimum Supported Rust Version
+
+This crate supports Rust 1.36.0 or later.
+
+## Contact
+
+For bug reports, patches, feature requests and other messages, please send a
+mail to [~ireas/public-inbox@lists.sr.ht][] using the `[merge-rs]` prefix in
+the subject.
+
+## License
+
+This project is dual-licensed under the [Apache-2.0][] and [MIT][] licenses.
+The documentation and configuration files contained in this repository are
+licensed under the [Creative Commons Zero][CC0] license. You can find a copy
+of the license texts in the `LICENSES` directory.
+
+`merge-rs` complies with [version 3.0 of the REUSE specification][reuse].
+
+[~ireas/public-inbox@lists.sr.ht]: mailto:~ireas/public-inbox@lists.sr.ht
+[Apache-2.0]: https://opensource.org/licenses/Apache-2.0
+[MIT]: https://opensource.org/licenses/MIT
+[CC0]: https://creativecommons.org/publicdomain/zero/1.0/
+[reuse]: https://reuse.software/practices/3.0/
diff --git a/examples/args.rs b/examples/args.rs
new file mode 100644
index 0000000..616a1d4
--- /dev/null
+++ b/examples/args.rs
@@ -0,0 +1,43 @@
+// SPDX-FileCopyrightText: 2020 Robin Krahl <robin.krahl@ireas.org>
+// SPDX-License-Identifier: CC0-1.0
+
+use merge::Merge;
+use serde::Deserialize;
+use structopt::StructOpt;
+
+#[derive(Debug, Default, Deserialize, Merge, StructOpt)]
+#[serde(default)]
+struct Args {
+ #[structopt(short, long)]
+ #[merge(strategy = merge::bool::overwrite_false)]
+ debug: bool,
+
+ input: Option<String>,
+
+ output: Option<String>,
+}
+
+fn get_config() -> Option<Args> {
+ let path: &std::path::Path = "args.toml".as_ref();
+ if path.is_file() {
+ let s = std::fs::read_to_string(path).expect("Could not read configuration file");
+ Some(toml::from_str(&s).expect("Could not parse configuration"))
+ } else {
+ None
+ }
+}
+
+fn get_env() -> Args {
+ envy::prefixed("ARGS_")
+ .from_env()
+ .expect("Could not read environment variables")
+}
+
+fn main() {
+ let mut args = Args::from_args();
+ args.merge(get_env());
+ if let Some(config) = get_config() {
+ args.merge(config);
+ }
+ println!("{:?}", args);
+}
diff --git a/examples/user.rs b/examples/user.rs
new file mode 100644
index 0000000..60161d7
--- /dev/null
+++ b/examples/user.rs
@@ -0,0 +1,31 @@
+// SPDX-FileCopyrightText: 2020 Robin Krahl <robin.krahl@ireas.org>
+// SPDX-License-Identifier: CC0-1.0
+
+use merge::Merge;
+
+#[derive(Merge)]
+struct User {
+ #[merge(skip)]
+ pub name: &'static str,
+ pub location: Option<&'static str>,
+ #[merge(strategy = merge::vec::append)]
+ pub groups: Vec<&'static str>,
+}
+
+fn main() {
+ let defaults = User {
+ name: "",
+ location: Some("Internet"),
+ groups: vec!["rust"],
+ };
+ let mut ferris = User {
+ name: "Ferris",
+ location: None,
+ groups: vec!["mascot"],
+ };
+ ferris.merge(defaults);
+
+ assert_eq!("Ferris", ferris.name);
+ assert_eq!(Some("Internet"), ferris.location);
+ assert_eq!(vec!["mascot", "rust"], ferris.groups);
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..2deebca
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,223 @@
+// SPDX-FileCopyrightText: 2020 Robin Krahl <robin.krahl@ireas.org>
+// SPDX-License-Identifier: Apache-2.0 or MIT
+
+//! Provides [`Merge`][], a trait for objects that can be merged.
+//!
+//! # Usage
+//!
+//! ```
+//! trait Merge {
+//! fn merge(&mut self, other: Self);
+//! }
+//! ```
+//!
+//! The [`Merge`][] trait can be used to merge two objects of the same type into one. The intended
+//! use case is merging configuration from different sources, for example environment variables,
+//! multiple configuration files and command-line arguments, see the [`args.rs`][] example.
+//!
+//! `Merge` is implemented for `Option` and can be derived for structs. When deriving the `Merge`
+//! trait for a struct, you can provide custom merge strategies for the fields that don’t implement
+//! `Merge`. A merge strategy is a function with the signature `fn merge<T>(left: &mut T, right:
+//! T)` that merges `right` into `left`. The submodules of this crate provide strategies for the
+//! most common types, but you can also define your own strategies.
+//!
+//! ## Features
+//!
+//! This crate has the following features:
+//!
+//! - `derive` (default): Enables the derive macro for the `Merge` trait using the `merge_derive`
+//! crate.
+//! - `num` (default): Enables the merge strategies in the `num` module that require the
+//! `num_traits` crate.
+//! - `std` (default): Enables the merge strategies in the `vec` module that require the standard
+//! library. If this feature is not set, `merge` is a `no_std` library.
+//!
+//! # Example
+//!
+//! ```
+//! use merge::Merge;
+//!
+//! #[derive(Merge)]
+//! struct User {
+//! // Fields with the skip attribute are skipped by Merge
+//! #[merge(skip)]
+//! pub name: &'static str,
+//!
+//! // The Merge implementation for Option replaces its value if it is None
+//! pub location: Option<&'static str>,
+//!
+//! // The strategy attribute is used to customize the merge behavior
+//! #[merge(strategy = merge::vec::append)]
+//! pub groups: Vec<&'static str>,
+//! }
+//!
+//! let defaults = User {
+//! name: "",
+//! location: Some("Internet"),
+//! groups: vec!["rust"],
+//! };
+//! let mut ferris = User {
+//! name: "Ferris",
+//! location: None,
+//! groups: vec!["mascot"],
+//! };
+//! ferris.merge(defaults);
+//!
+//! assert_eq!("Ferris", ferris.name);
+//! assert_eq!(Some("Internet"), ferris.location);
+//! assert_eq!(vec!["mascot", "rust"], ferris.groups);
+//! ```
+//!
+//! [`Merge`]: trait.Merge.html
+//! [`args.rs`]: https://git.sr.ht/~ireas/merge-rs/tree/master/examples/args.rs
+
+#![cfg_attr(not(feature = "std"), no_std)]
+
+#[cfg(feature = "derive")]
+pub use merge_derive::*;
+
+/// A trait for objects that can be merged.
+///
+/// # Deriving
+///
+/// `Merge` can be derived for structs if the `derive` feature is enabled. The generated
+/// implementation calls the `merge` method for all fields, or the merge strategy function if set.
+/// You can use these field attributes to configure the generated implementation:
+/// - `skip`: Skip this field in the `merge` method.
+/// - `strategy = f`: Call `f(self.field, other.field)` instead of calling the `merge` function for
+/// this field.
+///
+/// # Examples
+///
+/// Using the `Merge` implementation for `Option`:
+///
+/// ```
+/// use merge::Merge as _;
+///
+/// let mut val = None;
+/// val.merge(Some(42));
+/// assert_eq!(Some(42), val);
+/// ```
+///
+/// Deriving `Merge` for a struct:
+///
+/// ```
+/// use merge::Merge;
+///
+/// #[derive(Debug, PartialEq, Merge)]
+/// struct S {
+/// option: Option<usize>,
+///
+/// #[merge(skip)]
+/// s: String,
+///
+/// #[merge(strategy = merge::bool::overwrite_false)]
+/// flag: bool,
+/// }
+///
+/// let mut val = S {
+/// option: None,
+/// s: "some ignored value".to_owned(),
+/// flag: false,
+/// };
+/// val.merge(S {
+/// option: Some(42),
+/// s: "some other ignored value".to_owned(),
+/// flag: true,
+/// });
+/// assert_eq!(S {
+/// option: Some(42),
+/// s: "some ignored value".to_owned(),
+/// flag: true,
+/// }, val);
+/// ```
+pub trait Merge {
+ /// Merge another object into this object.
+ fn merge(&mut self, other: Self);
+}
+
+impl<T> Merge for Option<T> {
+ fn merge(&mut self, mut other: Self) {
+ if !self.is_some() {
+ *self = other.take();
+ }
+ }
+}
+
+/// Merge strategies for boolean types.
+pub mod bool {
+ /// Overwrite left with right if the value of left is false.
+ pub fn overwrite_false(left: &mut bool, right: bool) {
+ if !*left {
+ *left = right;
+ }
+ }
+
+ /// Overwrite left with right if the value of left is true.
+ pub fn overwrite_true(left: &mut bool, right: bool) {
+ if *left {
+ *left = right;
+ }
+ }
+}
+
+/// Merge strategies for numeric types.
+///
+/// These strategies are only available if the `num` feature is enabled.
+#[cfg(feature = "num")]
+pub mod num {
+ /// Set left to the saturated some of left and right.
+ pub fn saturating_add<T: num_traits::SaturatingAdd>(left: &mut T, right: T) {
+ *left = left.saturating_add(&right);
+ }
+
+ /// Overwrite left with right if the value of left is zero.
+ pub fn overwrite_zero<T: num_traits::Zero>(left: &mut T, right: T) {
+ if left.is_zero() {
+ *left = right;
+ }
+ }
+}
+
+/// Merge strategies for types that form a total order.
+pub mod ord {
+ use core::cmp;
+
+ /// Set left to the maximum of left and right.
+ pub fn max<T: cmp::Ord>(left: &mut T, right: T) {
+ if cmp::Ord::cmp(left, &right) == cmp::Ordering::Less {
+ *left = right;
+ }
+ }
+
+ /// Set left to the minimum of left and right.
+ pub fn min<T: cmp::Ord>(left: &mut T, right: T) {
+ if cmp::Ord::cmp(left, &right) == cmp::Ordering::Greater {
+ *left = right;
+ }
+ }
+}
+
+/// Merge strategies for vectors.
+///
+/// These strategies are only available if the `std` feature is enabled.
+#[cfg(feature = "std")]
+pub mod vec {
+ /// Overwrite left with right if left is empty.
+ pub fn overwrite_empty<T>(left: &mut Vec<T>, mut right: Vec<T>) {
+ if left.is_empty() {
+ left.append(&mut right);
+ }
+ }
+
+ /// Append the contents of right to left.
+ pub fn append<T>(left: &mut Vec<T>, mut right: Vec<T>) {
+ left.append(&mut right);
+ }
+
+ /// Prepend the contents of right to left.
+ pub fn prepend<T>(left: &mut Vec<T>, mut right: Vec<T>) {
+ right.append(left);
+ *left = right;
+ }
+}
diff --git a/tests/compile.rs b/tests/compile.rs
new file mode 100644
index 0000000..aa1bda7
--- /dev/null
+++ b/tests/compile.rs
@@ -0,0 +1,9 @@
+// SPDX-FileCopyrightText: 2020 Robin Krahl <robin.krahl@ireas.org>
+// SPDX-License-Identifier: Apache-2.0 or MIT
+
+#[test]
+#[ignore]
+fn test_compile_fail() {
+ let t = trybuild::TestCases::new();
+ t.compile_fail("tests/compile/*.rs");
+}
diff --git a/tests/compile/derive-enum.rs b/tests/compile/derive-enum.rs
new file mode 100644
index 0000000..6c4f9b2
--- /dev/null
+++ b/tests/compile/derive-enum.rs
@@ -0,0 +1,13 @@
+// SPDX-FileCopyrightText: 2020 Robin Krahl <robin.krahl@ireas.org>
+// SPDX-License-Identifier: Apache-2.0 or MIT
+
+use merge::Merge;
+
+#[derive(Merge)]
+enum E {
+ V1,
+ V2,
+ V3,
+}
+
+fn main() {}
diff --git a/tests/compile/derive-enum.stderr b/tests/compile/derive-enum.stderr
new file mode 100644
index 0000000..4783549
--- /dev/null
+++ b/tests/compile/derive-enum.stderr
@@ -0,0 +1,7 @@
+error: merge::Merge can only be derived for structs
+ --> $DIR/derive-enum.rs:6:10
+ |
+6 | #[derive(Merge)]
+ | ^^^^^
+ |
+ = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/compile/derive-invalid-attribute.rs b/tests/compile/derive-invalid-attribute.rs
new file mode 100644
index 0000000..cbc3e54
--- /dev/null
+++ b/tests/compile/derive-invalid-attribute.rs
@@ -0,0 +1,12 @@
+// SPDX-FileCopyrightText: 2020 Robin Krahl <robin.krahl@ireas.org>
+// SPDX-License-Identifier: Apache-2.0 or MIT
+
+use merge::Merge;
+
+#[derive(Merge)]
+struct S {
+ #[merge(ignore)]
+ field1: Option<u8>,
+}
+
+fn main() {}
diff --git a/tests/compile/derive-invalid-attribute.stderr b/tests/compile/derive-invalid-attribute.stderr
new file mode 100644
index 0000000..ee1b2c6
--- /dev/null
+++ b/tests/compile/derive-invalid-attribute.stderr
@@ -0,0 +1,5 @@
+error: Unexpected attribute: ignore
+ --> $DIR/derive-invalid-attribute.rs:8:13
+ |
+8 | #[merge(ignore)]
+ | ^^^^^^
diff --git a/tests/compile/derive-invalid-skip.rs b/tests/compile/derive-invalid-skip.rs
new file mode 100644
index 0000000..78ed93c
--- /dev/null
+++ b/tests/compile/derive-invalid-skip.rs
@@ -0,0 +1,12 @@
+// SPDX-FileCopyrightText: 2020 Robin Krahl <robin.krahl@ireas.org>
+// SPDX-License-Identifier: Apache-2.0 or MIT
+
+use merge::Merge;
+
+#[derive(Merge)]
+struct S {
+ #[merge(skip = true)]
+ field1: u8,
+}
+
+fn main() {}
diff --git a/tests/compile/derive-invalid-skip.stderr b/tests/compile/derive-invalid-skip.stderr
new file mode 100644
index 0000000..65679f9
--- /dev/null
+++ b/tests/compile/derive-invalid-skip.stderr
@@ -0,0 +1,5 @@
+error: expected `,`
+ --> $DIR/derive-invalid-skip.rs:8:18
+ |
+8 | #[merge(skip = true)]
+ | ^
diff --git a/tests/compile/derive-invalid-strategy.rs b/tests/compile/derive-invalid-strategy.rs
new file mode 100644
index 0000000..46dc259
--- /dev/null
+++ b/tests/compile/derive-invalid-strategy.rs
@@ -0,0 +1,16 @@
+// SPDX-FileCopyrightText: 2020 Robin Krahl <robin.krahl@ireas.org>
+// SPDX-License-Identifier: Apache-2.0 or MIT
+
+use merge::Merge;
+
+#[derive(Merge)]
+struct S {
+ #[merge(strategy = my_custom_merge_strategy)]
+ field1: u8,
+}
+
+fn my_custom_merge_strategy(left: u8, right: u8) -> u8 {
+ left + right
+}
+
+fn main() {}
diff --git a/tests/compile/derive-invalid-strategy.stderr b/tests/compile/derive-invalid-strategy.stderr
new file mode 100644
index 0000000..ecdd085
--- /dev/null
+++ b/tests/compile/derive-invalid-strategy.stderr
@@ -0,0 +1,13 @@
+error[E0308]: mismatched types
+ --> $DIR/derive-invalid-strategy.rs:8:24
+ |
+8 | #[merge(strategy = my_custom_merge_strategy)]
+ | ________________________^
+9 | | field1: u8,
+ | |__________^ expected `u8`, found `&mut u8`
+ |
+help: consider removing the borrow
+ |
+8 | #[merge(strategy = my_custom_merge_strategy)]
+9 | field1: u8,
+ |
diff --git a/tests/compile/derive-missing-strategy.rs b/tests/compile/derive-missing-strategy.rs
new file mode 100644
index 0000000..c9c1073
--- /dev/null
+++ b/tests/compile/derive-missing-strategy.rs
@@ -0,0 +1,12 @@
+// SPDX-FileCopyrightText: 2020 Robin Krahl <robin.krahl@ireas.org>
+// SPDX-License-Identifier: Apache-2.0 or MIT
+
+use merge::Merge;
+
+#[derive(Merge)]
+struct S {
+ #[merge(strategy = my_custom_merge_strategy)]
+ field1: u8,
+}
+
+fn main() {}
diff --git a/tests/compile/derive-missing-strategy.stderr b/tests/compile/derive-missing-strategy.stderr
new file mode 100644
index 0000000..9fb1a03
--- /dev/null
+++ b/tests/compile/derive-missing-strategy.stderr
@@ -0,0 +1,5 @@
+error[E0425]: cannot find function `my_custom_merge_strategy` in this scope
+ --> $DIR/derive-missing-strategy.rs:8:24
+ |
+8 | #[merge(strategy = my_custom_merge_strategy)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
diff --git a/tests/compile/derive-no-strategy.rs b/tests/compile/derive-no-strategy.rs
new file mode 100644
index 0000000..10b95fa
--- /dev/null
+++ b/tests/compile/derive-no-strategy.rs
@@ -0,0 +1,12 @@
+// SPDX-FileCopyrightText: 2020 Robin Krahl <robin.krahl@ireas.org>
+// SPDX-License-Identifier: Apache-2.0 or MIT
+
+use merge::Merge;
+
+#[derive(Merge)]
+struct S {
+ #[merge(strategy)]
+ field1: u8,
+}
+
+fn main() {}
diff --git a/tests/compile/derive-no-strategy.stderr b/tests/compile/derive-no-strategy.stderr
new file mode 100644
index 0000000..9da8914
--- /dev/null
+++ b/tests/compile/derive-no-strategy.stderr
@@ -0,0 +1,5 @@
+error: expected `=`
+ --> $DIR/derive-no-strategy.rs:8:12
+ |
+8 | #[merge(strategy)]
+ | ^^^^^^^^^^
diff --git a/tests/compile/derive-u8.rs b/tests/compile/derive-u8.rs
new file mode 100644
index 0000000..25bfd9b
--- /dev/null
+++ b/tests/compile/derive-u8.rs
@@ -0,0 +1,12 @@
+// SPDX-FileCopyrightText: 2020 Robin Krahl <robin.krahl@ireas.org>
+// SPDX-License-Identifier: Apache-2.0 or MIT
+
+use merge::Merge;
+
+#[derive(Merge)]
+struct S {
+ field1: Option<u8>,
+ field2: u8,
+}
+
+fn main() {}
diff --git a/tests/compile/derive-u8.stderr b/tests/compile/derive-u8.stderr
new file mode 100644
index 0000000..de3b5c2
--- /dev/null
+++ b/tests/compile/derive-u8.stderr
@@ -0,0 +1,7 @@
+error[E0277]: the trait bound `u8: merge::Merge` is not satisfied
+ --> $DIR/derive-u8.rs:9:5
+ |
+9 | field2: u8,
+ | ^^^^^^ the trait `merge::Merge` is not implemented for `u8`
+ |
+ = note: required by `merge::Merge::merge`
diff --git a/tests/derive.rs b/tests/derive.rs
new file mode 100644
index 0000000..0ac4163
--- /dev/null
+++ b/tests/derive.rs
@@ -0,0 +1,540 @@
+// SPDX-FileCopyrightText: 2020 Robin Krahl <robin.krahl@ireas.org>
+// SPDX-License-Identifier: Apache-2.0 or MIT
+
+#![cfg(feature = "derive")]
+
+use merge::Merge;
+
+fn test<T: std::fmt::Debug + Merge + PartialEq>(expected: T, mut left: T, right: T) {
+ left.merge(right);
+ assert_eq!(expected, left);
+}
+
+#[test]
+fn test_one_option_field() {
+ #[derive(Debug, Merge, PartialEq)]
+ struct S {
+ field1: Option<usize>,
+ }
+
+ impl S {
+ pub fn new(field1: Option<usize>) -> S {
+ S { field1 }
+ }
+ }
+
+ test(S::new(Some(1)), S::new(Some(1)), S::new(Some(2)));
+ test(S::new(Some(1)), S::new(Some(1)), S::new(None));
+ test(S::new(Some(2)), S::new(None), S::new(Some(2)));
+ test(S::new(None), S::new(None), S::new(None));
+}
+
+#[test]
+fn test_two_option_fields() {
+ #[derive(Debug, Merge, PartialEq)]
+ struct S {
+ field1: Option<usize>,
+ field2: Option<usize>,
+ }
+
+ impl S {
+ pub fn new(field1: Option<usize>, field2: Option<usize>) -> S {
+ S { field1, field2 }
+ }
+ }
+
+ // left.field1 == Some(1)
+ // right.field1 == Some(2)
+ test(
+ S::new(Some(1), Some(1)),
+ S::new(Some(1), Some(1)),
+ S::new(Some(2), Some(2)),
+ );
+ test(
+ S::new(Some(1), Some(1)),
+ S::new(Some(1), Some(1)),
+ S::new(Some(2), None),
+ );
+ test(
+ S::new(Some(1), Some(2)),
+ S::new(Some(1), None),
+ S::new(Some(2), Some(2)),
+ );
+ test(
+ S::new(Some(1), None),
+ S::new(Some(1), None),
+ S::new(Some(2), None),
+ );
+
+ // left.field1 == Some(1)
+ // right.field1 == None
+ test(
+ S::new(Some(1), Some(1)),
+ S::new(Some(1), Some(1)),
+ S::new(None, Some(2)),
+ );
+ test(
+ S::new(Some(1), Some(1)),
+ S::new(Some(1), Some(1)),
+ S::new(None, None),
+ );
+ test(
+ S::new(Some(1), Some(2)),
+ S::new(Some(1), None),
+ S::new(None, Some(2)),
+ );
+ test(
+ S::new(Some(1), None),
+ S::new(Some(1), None),
+ S::new(None, None),
+ );
+
+ // left.field1 == None
+ // right.field1 == Some(2)
+ test(
+ S::new(Some(2), Some(1)),
+ S::new(None, Some(1)),
+ S::new(Some(2), Some(2)),
+ );
+ test(
+ S::new(Some(2), Some(1)),
+ S::new(None, Some(1)),
+ S::new(Some(2), None),
+ );
+ test(
+ S::new(Some(2), Some(2)),
+ S::new(None, None),
+ S::new(Some(2), Some(2)),
+ );
+ test(
+ S::new(Some(2), None),
+ S::new(None, None),
+ S::new(Some(2), None),
+ );
+
+ // left.field1 == None
+ // right.field1 == None
+ test(
+ S::new(None, Some(1)),
+ S::new(None, Some(1)),
+ S::new(None, Some(2)),
+ );
+ test(
+ S::new(None, Some(1)),
+ S::new(None, Some(1)),
+ S::new(None, None),
+ );
+ test(
+ S::new(None, Some(2)),
+ S::new(None, None),
+ S::new(None, Some(2)),
+ );
+ test(S::new(None, None), S::new(None, None), S::new(None, None));
+}
+
+#[test]
+fn test_skip_valid() {
+ #[derive(Debug, Merge, PartialEq)]
+ struct S {
+ field1: Option<usize>,
+ #[merge(skip)]
+ field2: Option<usize>,
+ }
+
+ impl S {
+ pub fn new(field1: Option<usize>, field2: Option<usize>) -> S {
+ S { field1, field2 }
+ }
+ }
+
+ // left.field1 == Some(1)
+ // right.field1 == Some(2)
+ test(
+ S::new(Some(1), Some(1)),
+ S::new(Some(1), Some(1)),
+ S::new(Some(2), Some(2)),
+ );
+ test(
+ S::new(Some(1), Some(1)),
+ S::new(Some(1), Some(1)),
+ S::new(Some(2), None),
+ );
+ test(
+ S::new(Some(1), None),
+ S::new(Some(1), None),
+ S::new(Some(2), Some(2)),
+ );
+ test(
+ S::new(Some(1), None),
+ S::new(Some(1), None),
+ S::new(Some(2), None),
+ );
+
+ // left.field1 == Some(1)
+ // right.field1 == None
+ test(
+ S::new(Some(1), Some(1)),
+ S::new(Some(1), Some(1)),
+ S::new(None, Some(2)),
+ );
+ test(
+ S::new(Some(1), Some(1)),
+ S::new(Some(1), Some(1)),
+ S::new(None, None),
+ );
+ test(
+ S::new(Some(1), None),
+ S::new(Some(1), None),
+ S::new(None, Some(2)),
+ );
+ test(
+ S::new(Some(1), None),
+ S::new(Some(1), None),
+ S::new(None, None),
+ );
+
+ // left.field1 == None
+ // right.field1 == Some(2)
+ test(
+ S::new(Some(2), Some(1)),
+ S::new(None, Some(1)),
+ S::new(Some(2), Some(2)),
+ );
+ test(
+ S::new(Some(2), Some(1)),
+ S::new(None, Some(1)),
+ S::new(Some(2), None),
+ );
+ test(
+ S::new(Some(2), None),
+ S::new(None, None),
+ S::new(Some(2), Some(2)),
+ );
+ test(
+ S::new(Some(2), None),
+ S::new(None, None),
+ S::new(Some(2), None),
+ );
+
+ // left.field1 == None
+ // right.field1 == None
+ test(
+ S::new(None, Some(1)),
+ S::new(None, Some(1)),
+ S::new(None, Some(2)),
+ );
+ test(
+ S::new(None, Some(1)),
+ S::new(None, Some(1)),
+ S::new(None, None),
+ );
+ test(
+ S::new(None, None),
+ S::new(None, None),
+ S::new(None, Some(2)),
+ );
+ test(S::new(None, None), S::new(None, None), S::new(None, None));
+}
+
+#[test]
+fn test_skip_invalid() {
+ #[derive(Debug, Merge, PartialEq)]
+ struct S {
+ field1: Option<usize>,
+ #[merge(skip)]
+ field2: usize,
+ }
+
+ impl S {
+ pub fn new(field1: Option<usize>, field2: usize) -> S {
+ S { field1, field2 }
+ }
+ }
+
+ // left.field1 == Some(1)
+ // right.field1 == Some(2)
+ test(S::new(Some(1), 1), S::new(Some(1), 1), S::new(Some(2), 2));
+ test(S::new(Some(1), 1), S::new(Some(1), 1), S::new(Some(2), 0));
+ test(S::new(Some(1), 0), S::new(Some(1), 0), S::new(Some(2), 2));
+ test(S::new(Some(1), 0), S::new(Some(1), 0), S::new(Some(2), 0));
+
+ // left.field1 == Some(1)
+ // right.field1 == None
+ test(S::new(Some(1), 1), S::new(Some(1), 1), S::new(None, 2));
+ test(S::new(Some(1), 1), S::new(Some(1), 1), S::new(None, 0));
+ test(S::new(Some(1), 0), S::new(Some(1), 0), S::new(None, 2));
+ test(S::new(Some(1), 0), S::new(Some(1), 0), S::new(None, 0));
+
+ // left.field1 == None
+ // right.field1 == Some(2)
+ test(S::new(Some(2), 1), S::new(None, 1), S::new(Some(2), 2));
+ test(S::new(Some(2), 1), S::new(None, 1), S::new(Some(2), 0));
+ test(S::new(Some(2), 0), S::new(None, 0), S::new(Some(2), 2));
+ test(S::new(Some(2), 0), S::new(None, 0), S::new(Some(2), 0));
+
+ // left.field1 == None
+ // right.field1 == None
+ test(S::new(None, 1), S::new(None, 1), S::new(None, 2));
+ test(S::new(None, 1), S::new(None, 1), S::new(None, 0));
+ test(S::new(None, 0), S::new(None, 0), S::new(None, 2));
+ test(S::new(None, 0), S::new(None, 0), S::new(None, 0));
+}
+
+#[test]
+fn test_strategy_usize_add() {
+ #[derive(Debug, Merge, PartialEq)]
+ struct S {
+ #[merge(strategy = add)]
+ field1: usize,
+ }
+
+ impl S {
+ pub fn new(field1: usize) -> S {
+ S { field1 }
+ }
+ }
+
+ fn add(left: &mut usize, right: usize) {
+ *left = *left + right;
+ }
+
+ test(S::new(0), S::new(0), S::new(0));
+ test(S::new(1), S::new(1), S::new(0));
+ test(S::new(1), S::new(0), S::new(1));
+ test(S::new(2), S::new(1), S::new(1));
+}
+
+#[test]
+fn test_strategy_vec_append() {
+ #[derive(Debug, Merge, PartialEq)]
+ struct S {
+ #[merge(strategy = append)]
+ field1: Vec<usize>,
+ }
+
+ impl S {
+ pub fn new(field1: Vec<usize>) -> S {
+ S { field1 }
+ }
+ }
+
+ fn append(left: &mut Vec<usize>, mut right: Vec<usize>) {
+ left.append(&mut right);
+ }
+
+ test(
+ S::new(vec![0, 1, 2, 3]),
+ S::new(vec![0, 1]),
+ S::new(vec![2, 3]),
+ );
+ test(
+ S::new(vec![0, 1, 2, 3]),
+ S::new(vec![0, 1, 2, 3]),
+ S::new(vec![]),
+ );
+ test(
+ S::new(vec![0, 1, 2, 3]),
+ S::new(vec![]),
+ S::new(vec![0, 1, 2, 3]),
+ );
+}
+
+#[test]
+fn test_unnamed_fields() {
+ #[derive(Debug, Merge, PartialEq)]
+ struct S(Option<usize>, Option<usize>);
+
+ impl S {
+ pub fn new(field1: Option<usize>, field2: Option<usize>) -> S {
+ S(field1, field2)
+ }
+ }
+
+ // left.field1 == Some(1)
+ // right.field1 == Some(2)
+ test(
+ S::new(Some(1), Some(1)),
+ S::new(Some(1), Some(1)),
+ S::new(Some(2), Some(2)),
+ );
+ test(
+ S::new(Some(1), Some(1)),
+ S::new(Some(1), Some(1)),
+ S::new(Some(2), None),
+ );
+ test(
+ S::new(Some(1), Some(2)),
+ S::new(Some(1), None),
+ S::new(Some(2), Some(2)),
+ );
+ test(
+ S::new(Some(1), None),
+ S::new(Some(1), None),
+ S::new(Some(2), None),
+ );
+
+ // left.field1 == Some(1)
+ // right.field1 == None
+ test(
+ S::new(Some(1), Some(1)),
+ S::new(Some(1), Some(1)),
+ S::new(None, Some(2)),
+ );
+ test(
+ S::new(Some(1), Some(1)),
+ S::new(Some(1), Some(1)),
+ S::new(None, None),
+ );
+ test(
+ S::new(Some(1), Some(2)),
+ S::new(Some(1), None),
+ S::new(None, Some(2)),
+ );
+ test(
+ S::new(Some(1), None),
+ S::new(Some(1), None),
+ S::new(None, None),
+ );
+
+ // left.field1 == None
+ // right.field1 == Some(2)
+ test(
+ S::new(Some(2), Some(1)),
+ S::new(None, Some(1)),
+ S::new(Some(2), Some(2)),
+ );
+ test(
+ S::new(Some(2), Some(1)),
+ S::new(None, Some(1)),
+ S::new(Some(2), None),
+ );
+ test(
+ S::new(Some(2), Some(2)),
+ S::new(None, None),
+ S::new(Some(2), Some(2)),
+ );
+ test(
+ S::new(Some(2), None),
+ S::new(None, None),
+ S::new(Some(2), None),
+ );
+
+ // left.field1 == None
+ // right.field1 == None
+ test(
+ S::new(None, Some(1)),
+ S::new(None, Some(1)),
+ S::new(None, Some(2)),
+ );
+ test(
+ S::new(None, Some(1)),
+ S::new(None, Some(1)),
+ S::new(None, None),
+ );
+ test(
+ S::new(None, Some(2)),
+ S::new(None, None),
+ S::new(None, Some(2)),
+ );
+ test(S::new(None, None), S::new(None, None), S::new(None, None));
+}
+
+#[test]
+fn test_unnamed_fields_skip() {
+ #[derive(Debug, Merge, PartialEq)]
+ struct S(Option<usize>, #[merge(skip)] Option<usize>);
+
+ impl S {
+ pub fn new(field1: Option<usize>, field2: Option<usize>) -> S {
+ S(field1, field2)
+ }
+ }
+
+ // left.field1 == Some(1)
+ // right.field1 == Some(2)
+ test(
+ S::new(Some(1), Some(1)),
+ S::new(Some(1), Some(1)),
+ S::new(Some(2), Some(2)),
+ );
+ test(
+ S::new(Some(1), Some(1)),
+ S::new(Some(1), Some(1)),
+ S::new(Some(2), None),
+ );
+ test(
+ S::new(Some(1), None),
+ S::new(Some(1), None),
+ S::new(Some(2), Some(2)),
+ );
+ test(
+ S::new(Some(1), None),
+ S::new(Some(1), None),
+ S::new(Some(2), None),
+ );
+
+ // left.field1 == Some(1)
+ // right.field1 == None
+ test(
+ S::new(Some(1), Some(1)),
+ S::new(Some(1), Some(1)),
+ S::new(None, Some(2)),
+ );
+ test(
+ S::new(Some(1), Some(1)),
+ S::new(Some(1), Some(1)),
+ S::new(None, None),
+ );
+ test(
+ S::new(Some(1), None),
+ S::new(Some(1), None),
+ S::new(None, Some(2)),
+ );
+ test(
+ S::new(Some(1), None),
+ S::new(Some(1), None),
+ S::new(None, None),
+ );
+
+ // left.field1 == None
+ // right.field1 == Some(2)
+ test(
+ S::new(Some(2), Some(1)),
+ S::new(None, Some(1)),
+ S::new(Some(2), Some(2)),
+ );
+ test(
+ S::new(Some(2), Some(1)),
+ S::new(None, Some(1)),
+ S::new(Some(2), None),
+ );
+ test(
+ S::new(Some(2), None),
+ S::new(None, None),
+ S::new(Some(2), Some(2)),
+ );
+ test(
+ S::new(Some(2), None),
+ S::new(None, None),
+ S::new(Some(2), None),
+ );
+
+ // left.field1 == None
+ // right.field1 == None
+ test(
+ S::new(None, Some(1)),
+ S::new(None, Some(1)),
+ S::new(None, Some(2)),
+ );
+ test(
+ S::new(None, Some(1)),
+ S::new(None, Some(1)),
+ S::new(None, None),
+ );
+ test(
+ S::new(None, None),
+ S::new(None, None),
+ S::new(None, Some(2)),
+ );
+ test(S::new(None, None), S::new(None, None), S::new(None, None));
+}
diff --git a/tests/impls.rs b/tests/impls.rs
new file mode 100644
index 0000000..d8378e5
--- /dev/null
+++ b/tests/impls.rs
@@ -0,0 +1,16 @@
+// SPDX-FileCopyrightText: 2020 Robin Krahl <robin.krahl@ireas.org>
+// SPDX-License-Identifier: Apache-2.0 or MIT
+
+use merge::Merge;
+
+fn test<T: std::fmt::Debug + Merge + PartialEq>(expected: T, mut left: T, right: T) {
+ left.merge(right);
+ assert_eq!(expected, left);
+}
+
+#[test]
+fn test_option() {
+ test(Some(1), Some(1), Some(2));
+ test(Some(2), None, Some(2));
+ test(None::<usize>, None, None);
+}
diff --git a/tests/strategies.rs b/tests/strategies.rs
new file mode 100644
index 0000000..3a35ea2
--- /dev/null
+++ b/tests/strategies.rs
@@ -0,0 +1,122 @@
+// SPDX-FileCopyrightText: 2020 Robin Krahl <robin.krahl@ireas.org>
+// SPDX-License-Identifier: Apache-2.0 or MIT
+
+#![cfg(feature = "derive")]
+
+use merge::Merge;
+
+fn test<T: std::fmt::Debug + Merge + PartialEq>(expected: T, mut left: T, right: T) {
+ left.merge(right);
+ assert_eq!(expected, left);
+}
+
+#[test]
+fn test_bool_overwrite_false() {
+ #[derive(Debug, Merge, PartialEq)]
+ struct S(#[merge(strategy = merge::bool::overwrite_false)] bool);
+
+ test(S(false), S(false), S(false));
+ test(S(true), S(false), S(true));
+ test(S(true), S(true), S(false));
+ test(S(true), S(true), S(true));
+}
+
+#[test]
+fn test_bool_overwrite_true() {
+ #[derive(Debug, Merge, PartialEq)]
+ struct S(#[merge(strategy = merge::bool::overwrite_true)] bool);
+
+ test(S(false), S(false), S(false));
+ test(S(false), S(false), S(true));
+ test(S(false), S(true), S(false));
+ test(S(true), S(true), S(true));
+}
+
+#[cfg(feature = "num")]
+#[test]
+fn test_num_saturating_add() {
+ #[derive(Debug, Merge, PartialEq)]
+ struct S(#[merge(strategy = merge::num::saturating_add)] u8);
+
+ test(S(0), S(0), S(0));
+ test(S(1), S(0), S(1));
+ test(S(255), S(255), S(10));
+ test(S(40), S(30), S(10));
+}
+
+#[cfg(feature = "num")]
+#[test]
+fn test_num_overwrite_zero() {
+ #[derive(Debug, Merge, PartialEq)]
+ struct S(#[merge(strategy = merge::num::overwrite_zero)] u8);
+
+ test(S(0), S(0), S(0));
+ test(S(1), S(0), S(1));
+ test(S(255), S(255), S(10));
+}
+
+#[test]
+fn test_ord_max() {
+ #[derive(Debug, Merge, PartialEq)]
+ struct S(#[merge(strategy = merge::ord::max)] u8);
+
+ test(S(2), S(1), S(2));
+ test(S(2), S(2), S(1));
+ test(S(2), S(2), S(2));
+ test(S(2), S(2), S(0));
+ test(S(2), S(0), S(2));
+ test(S(33), S(33), S(11));
+}
+
+#[test]
+fn test_ord_min() {
+ #[derive(Debug, Merge, PartialEq)]
+ struct S(#[merge(strategy = merge::ord::min)] u8);
+
+ test(S(1), S(1), S(2));
+ test(S(1), S(2), S(1));
+ test(S(2), S(2), S(2));
+ test(S(0), S(2), S(0));
+ test(S(0), S(0), S(2));
+ test(S(11), S(33), S(11));
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn test_vec_overwrite_empty() {
+ #[derive(Debug, Merge, PartialEq)]
+ struct S(#[merge(strategy = merge::vec::overwrite_empty)] Vec<u8>);
+
+ test(S(vec![]), S(vec![]), S(vec![]));
+ test(S(vec![1]), S(vec![]), S(vec![1]));
+ test(S(vec![0]), S(vec![0]), S(vec![1]));
+ test(S(vec![255]), S(vec![255]), S(vec![10]));
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn test_vec_append() {
+ #[derive(Debug, Merge, PartialEq)]
+ struct S(#[merge(strategy = merge::vec::append)] Vec<u8>);
+
+ test(S(vec![]), S(vec![]), S(vec![]));
+ test(S(vec![1]), S(vec![]), S(vec![1]));
+ test(S(vec![0, 1]), S(vec![0]), S(vec![1]));
+ test(S(vec![255, 10]), S(vec![255]), S(vec![10]));
+ test(S(vec![0, 1, 2, 3, 4]), S(vec![0, 1, 2]), S(vec![3, 4]));
+ test(S(vec![3, 4, 0, 1, 2]), S(vec![3, 4]), S(vec![0, 1, 2]));
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn test_vec_prepend() {
+ #[derive(Debug, Merge, PartialEq)]
+ struct S(#[merge(strategy = merge::vec::prepend)] Vec<u8>);
+
+ test(S(vec![]), S(vec![]), S(vec![]));
+ test(S(vec![1]), S(vec![]), S(vec![1]));
+ test(S(vec![1, 0]), S(vec![0]), S(vec![1]));
+ test(S(vec![10, 255]), S(vec![255]), S(vec![10]));
+ test(S(vec![3, 4, 0, 1, 2]), S(vec![0, 1, 2]), S(vec![3, 4]));
+ test(S(vec![0, 1, 2, 3, 4]), S(vec![3, 4]), S(vec![0, 1, 2]));
+}