refactor(merge): use existing merge create

This commit is contained in:
Kristofers Solo 2025-07-10 14:49:25 +03:00
parent 8b82d09318
commit b341b7a661
Signed by: kristoferssolo
GPG Key ID: 8687F2D3EEE6F0ED
15 changed files with 230 additions and 714 deletions

View File

File diff suppressed because one or more lines are too long

107
Cargo.lock generated
View File

@ -17,6 +17,19 @@ version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]]
name = "ahash"
version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
dependencies = [
"cfg-if",
"getrandom 0.3.3",
"once_cell",
"version_check",
"zerocopy",
]
[[package]]
name = "aho-corasick"
version = "1.1.3"
@ -301,15 +314,6 @@ dependencies = [
"powerfmt",
]
[[package]]
name = "derive_macro"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "derive_more"
version = "2.0.1"
@ -933,6 +937,28 @@ version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]]
name = "merge"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56e520ba58faea3487f75df198b1d079644ec226ea3b0507d002c6fa4b8cf93a"
dependencies = [
"merge_derive",
"num-traits",
]
[[package]]
name = "merge_derive"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c8f8ce6efff81cbc83caf4af0905c46e58cb46892f63ad3835e81b47eaf7968"
dependencies = [
"proc-macro-error2",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "miniz_oxide"
version = "0.8.9"
@ -1083,6 +1109,28 @@ dependencies = [
"zerocopy",
]
[[package]]
name = "proc-macro-error-attr2"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
dependencies = [
"proc-macro2",
"quote",
]
[[package]]
name = "proc-macro-error2"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
dependencies = [
"proc-macro-error-attr2",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.95"
@ -1859,6 +1907,7 @@ version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
dependencies = [
"log",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
@ -1887,6 +1936,23 @@ dependencies = [
"syn",
]
[[package]]
name = "tracing-bunyan-formatter"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d637245a0d8774bd48df6482e086c59a8b5348a910c3b0579354045a9d82411"
dependencies = [
"ahash",
"log",
"serde",
"serde_json",
"time",
"tracing",
"tracing-core",
"tracing-log 0.1.4",
"tracing-subscriber",
]
[[package]]
name = "tracing-core"
version = "0.1.34"
@ -1907,6 +1973,17 @@ dependencies = [
"tracing-subscriber",
]
[[package]]
name = "tracing-log"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2"
dependencies = [
"log",
"once_cell",
"tracing-core",
]
[[package]]
name = "tracing-log"
version = "0.2.0"
@ -1933,7 +2010,7 @@ dependencies = [
"thread_local",
"tracing",
"tracing-core",
"tracing-log",
"tracing-log 0.2.0",
]
[[package]]
@ -1958,8 +2035,8 @@ version = "0.1.0"
dependencies = [
"color-eyre",
"crossterm 0.29.0",
"derive_macro",
"dirs",
"merge",
"ratatui",
"serde",
"thiserror 2.0.12",
@ -1967,6 +2044,8 @@ dependencies = [
"toml",
"tracing",
"tracing-appender",
"tracing-bunyan-formatter",
"tracing-log 0.2.0",
"tracing-subscriber",
"transmission-rpc",
"url",
@ -2042,6 +2121,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "want"
version = "0.3.1"

View File

@ -8,15 +8,17 @@ edition = "2021"
[dependencies]
color-eyre = "0.6"
crossterm = "0.29"
ratatui = { version = "0.29" }
tokio = { version = "1", features = ["macros", "rt-multi-thread", "fs"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
thiserror = "2.0"
tracing-appender = "0.2"
serde = { version = "1.0", features = ["derive"] }
toml = "0.9"
dirs = "6.0"
merge = "0.2"
ratatui = { version = "0.29" }
serde = { version = "1.0", features = ["derive"] }
thiserror = "2.0"
tokio = { version = "1", features = ["macros", "rt-multi-thread", "fs"] }
toml = "0.9"
tracing = "0.1"
tracing-appender = "0.2"
tracing-bunyan-formatter = { version = "0.3", default-features = false }
tracing-log = "0.2.0"
tracing-subscriber = { version = "0.3", features = ["registry", "env-filter"] }
transmission-rpc = "0.5"
url = "2.5"
derive_macro = { path = "derive_macro" }

View File

@ -21,3 +21,8 @@ highlight_foreground = "black"
warning_foreground = "yellow"
info_foreground = "blue"
error_foreground = "red"
[log]
traxor = "info"
ratatui = "warn"
transmission_rpc = "warn"

297
derive_macro/Cargo.lock generated
View File

@ -1,297 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "derive_macro"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn",
"trybuild",
]
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "glob"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
[[package]]
name = "hashbrown"
version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
[[package]]
name = "indexmap"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "itoa"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "memchr"
version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]]
name = "proc-macro2"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "ryu"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]]
name = "serde"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
[[package]]
name = "serde_spanned"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
dependencies = [
"serde",
]
[[package]]
name = "syn"
version = "2.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "target-triple"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ac9aa371f599d22256307c24a9d748c041e548cbf599f35d890f9d365361790"
[[package]]
name = "termcolor"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
dependencies = [
"winapi-util",
]
[[package]]
name = "toml"
version = "0.8.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit",
]
[[package]]
name = "toml_datetime"
version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.22.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"toml_write",
"winnow",
]
[[package]]
name = "toml_write"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
[[package]]
name = "trybuild"
version = "1.0.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c9bf9513a2f4aeef5fdac8677d7d349c79fdbcc03b9c86da6e9d254f1e43be2"
dependencies = [
"glob",
"serde",
"serde_derive",
"serde_json",
"target-triple",
"termcolor",
"toml",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "winapi-util"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
version = "0.7.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd"
dependencies = [
"memchr",
]

View File

@ -1,15 +0,0 @@
[package]
name = "derive_macro"
version = "0.1.0"
edition = "2024"
[lib]
crate-type = ["proc-macro"]
[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "2.0", features = ["full", "extra-traits"] }
[dev-dependencies]
trybuild = "1.0"

View File

@ -1,10 +0,0 @@
mod merge;
use proc_macro::TokenStream;
use syn::{DeriveInput, parse_macro_input};
#[proc_macro_derive(Merge)]
pub fn merge_derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
merge::impl_merge_derive(input)
}

View File

@ -1,58 +0,0 @@
use proc_macro::TokenStream;
use quote::quote;
use syn::{Data, DeriveInput, Fields, Type};
pub fn impl_merge_derive(input: DeriveInput) -> TokenStream {
let name = &input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let fields = match input.data {
Data::Struct(data) => match data.fields {
Fields::Named(fields) => fields.named,
_ => unimplemented!("Only named fields are supported for Merge derive macro"),
},
_ => unimplemented!("Only structs are supported for Merge derive macro"),
};
let merge_logic = fields.iter().map(|field| {
let field_name = &field.ident;
let field_type = &field.ty;
// Check if the field is an Option<T>
if let Type::Path(type_path) = field_type {
if let Some(segment) = type_path.path.segments.last() {
if segment.ident == "Option" {
// This is an Option<T> field
return quote! {
if let Some(o_val) = other.#field_name {
if let Some(s_val) = self.#field_name.as_mut() {
// If both are Some, attempt to merge recursively
s_val.merge(o_val);
} else {
// If self is None, take the other's Some value
self.#field_name = Some(o_val);
}
}
// If other is None, self remains unchanged
};
}
}
}
// For non-Option fields, attempt to merge recursively
quote! {
self.#field_name.merge(other.#field_name);
}
});
let expanded = quote! {
impl #impl_generics Merge for #name #ty_generics #where_clause {
fn merge(&mut self, other: Self) {
#(#merge_logic)*
}
}
};
expanded.into()
}

View File

@ -1,14 +1,18 @@
use crate::merge::Merge;
use derive_macro::Merge;
use merge::Merge;
use ratatui::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize, Merge)]
pub struct ColorsConfig {
#[merge(strategy = merge::option::overwrite_none)]
pub highlight_background: Option<String>,
#[merge(strategy = merge::option::overwrite_none)]
pub highlight_foreground: Option<String>,
#[merge(strategy = merge::option::overwrite_none)]
pub warning_foreground: Option<String>,
#[merge(strategy = merge::option::overwrite_none)]
pub info_foreground: Option<String>,
#[merge(strategy = merge::option::overwrite_none)]
pub error_foreground: Option<String>,
}

View File

@ -1,23 +1,37 @@
use crate::merge::Merge;
use derive_macro::Merge;
use merge::Merge;
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize, Merge)]
pub struct KeybindsConfig {
#[merge(strategy = merge::option::overwrite_none)]
pub quit: Option<String>,
#[merge(strategy = merge::option::overwrite_none)]
pub next_tab: Option<String>,
#[merge(strategy = merge::option::overwrite_none)]
pub prev_tab: Option<String>,
#[merge(strategy = merge::option::overwrite_none)]
pub next_torrent: Option<String>,
#[merge(strategy = merge::option::overwrite_none)]
pub prev_torrent: Option<String>,
#[merge(strategy = merge::option::overwrite_none)]
pub switch_tab_1: Option<String>,
#[merge(strategy = merge::option::overwrite_none)]
pub switch_tab_2: Option<String>,
#[merge(strategy = merge::option::overwrite_none)]
pub switch_tab_3: Option<String>,
#[merge(strategy = merge::option::overwrite_none)]
pub toggle_torrent: Option<String>,
#[merge(strategy = merge::option::overwrite_none)]
pub toggle_all: Option<String>,
#[merge(strategy = merge::option::overwrite_none)]
pub delete: Option<String>,
#[merge(strategy = merge::option::overwrite_none)]
pub delete_force: Option<String>,
#[merge(strategy = merge::option::overwrite_none)]
pub select: Option<String>,
#[merge(strategy = merge::option::overwrite_none)]
pub toggle_help: Option<String>,
#[merge(strategy = merge::option::overwrite_none)]
pub move_torrent: Option<String>,
}

View File

@ -1,11 +1,10 @@
mod colors;
mod keybinds;
use crate::merge::Merge;
use color_eyre::Result;
use colors::ColorsConfig;
use derive_macro::Merge;
use keybinds::KeybindsConfig;
use merge::Merge;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;

View File

@ -3,6 +3,5 @@ pub mod config;
pub mod event;
pub mod handler;
pub mod log;
pub mod merge;
pub mod tui;
pub mod ui;

View File

@ -1,21 +0,0 @@
pub trait Merge {
fn merge(&mut self, other: Self);
}
impl Merge for String {
fn merge(&mut self, other: Self) {
*self = other;
}
}
impl Merge for u32 {
fn merge(&mut self, other: Self) {
*self = other;
}
}
impl Merge for bool {
fn merge(&mut self, other: Self) {
*self = other;
}
}

View File

@ -1,286 +0,0 @@
use derive_macro::Merge;
use traxor::merge::Merge;
#[derive(Debug, PartialEq, Merge)]
struct NestedStruct {
value: u32,
name: Option<String>,
}
#[derive(Debug, PartialEq, Merge)]
struct TestStruct {
a: u32,
b: Option<String>,
c: Option<bool>,
nested: NestedStruct,
optional_nested: Option<NestedStruct>,
}
#[test]
fn test_merge_basic_fields() {
let mut s1 = TestStruct {
a: 1,
b: Some("hello".to_string()),
c: None,
nested: NestedStruct {
value: 10,
name: Some("original".to_string()),
},
optional_nested: None,
};
let s2 = TestStruct {
a: 2,
b: Some("world".to_string()),
c: Some(true),
nested: NestedStruct {
value: 20,
name: Some("new".to_string()),
},
optional_nested: Some(NestedStruct {
value: 30,
name: Some("optional".to_string()),
}),
};
s1.merge(s2);
assert_eq!(s1.a, 2);
assert_eq!(s1.b, Some("world".to_string()));
assert_eq!(s1.c, Some(true));
assert_eq!(s1.nested.value, 20);
assert_eq!(s1.nested.name, Some("new".to_string()));
assert_eq!(
s1.optional_nested,
Some(NestedStruct {
value: 30,
name: Some("optional".to_string())
})
);
}
#[test]
fn test_merge_option_none_other() {
let mut s1 = TestStruct {
a: 1,
b: Some("hello".to_string()),
c: Some(false),
nested: NestedStruct {
value: 10,
name: Some("original".to_string()),
},
optional_nested: Some(NestedStruct {
value: 100,
name: Some("existing".to_string()),
}),
};
let s2 = TestStruct {
a: 2,
b: None,
c: None,
nested: NestedStruct {
value: 20,
name: None,
},
optional_nested: None,
};
s1.merge(s2);
assert_eq!(s1.a, 2);
assert_eq!(s1.b, Some("hello".to_string())); // Should remain Some("hello")
assert_eq!(s1.c, Some(false)); // Should remain Some(false)
assert_eq!(s1.nested.value, 20);
assert_eq!(s1.nested.name, Some("original".to_string())); // Should remain original
assert_eq!(
s1.optional_nested,
Some(NestedStruct {
value: 100,
name: Some("existing".to_string())
})
); // Should remain existing
}
#[test]
fn test_merge_option_some_other() {
let mut s1 = TestStruct {
a: 1,
b: None,
c: None,
nested: NestedStruct {
value: 10,
name: None,
},
optional_nested: None,
};
let s2 = TestStruct {
a: 2,
b: Some("world".to_string()),
c: Some(true),
nested: NestedStruct {
value: 20,
name: Some("new".to_string()),
},
optional_nested: Some(NestedStruct {
value: 30,
name: Some("optional".to_string()),
}),
};
s1.merge(s2);
assert_eq!(s1.a, 2);
assert_eq!(s1.b, Some("world".to_string()));
assert_eq!(s1.c, Some(true));
assert_eq!(s1.nested.value, 20);
assert_eq!(s1.nested.name, Some("new".to_string()));
assert_eq!(
s1.optional_nested,
Some(NestedStruct {
value: 30,
name: Some("optional".to_string())
})
);
}
#[test]
fn test_merge_nested_struct_with_none_name() {
let mut s1 = TestStruct {
a: 1,
b: None,
c: None,
nested: NestedStruct {
value: 10,
name: Some("original".to_string()),
},
optional_nested: None,
};
let s2 = TestStruct {
a: 2,
b: None,
c: None,
nested: NestedStruct {
value: 20,
name: None,
},
optional_nested: None,
};
s1.merge(s2);
assert_eq!(s1.nested.value, 20);
assert_eq!(s1.nested.name, Some("original".to_string())); // Should remain original
}
#[test]
fn test_merge_optional_nested_struct_some_to_some() {
let mut s1 = TestStruct {
a: 1,
b: None,
c: None,
nested: NestedStruct {
value: 10,
name: None,
},
optional_nested: Some(NestedStruct {
value: 100,
name: Some("existing".to_string()),
}),
};
let s2 = TestStruct {
a: 2,
b: None,
c: None,
nested: NestedStruct {
value: 20,
name: None,
},
optional_nested: Some(NestedStruct {
value: 200,
name: Some("new_optional".to_string()),
}),
};
s1.merge(s2);
assert_eq!(
s1.optional_nested,
Some(NestedStruct {
value: 200,
name: Some("new_optional".to_string())
})
);
}
#[test]
fn test_merge_optional_nested_struct_none_to_some() {
let mut s1 = TestStruct {
a: 1,
b: None,
c: None,
nested: NestedStruct {
value: 10,
name: None,
},
optional_nested: None,
};
let s2 = TestStruct {
a: 2,
b: None,
c: None,
nested: NestedStruct {
value: 20,
name: None,
},
optional_nested: Some(NestedStruct {
value: 200,
name: Some("new_optional".to_string()),
}),
};
s1.merge(s2);
assert_eq!(
s1.optional_nested,
Some(NestedStruct {
value: 200,
name: Some("new_optional".to_string())
})
);
}
#[test]
fn test_merge_optional_nested_struct_some_to_none() {
let mut s1 = TestStruct {
a: 1,
b: None,
c: None,
nested: NestedStruct {
value: 10,
name: None,
},
optional_nested: Some(NestedStruct {
value: 100,
name: Some("existing".to_string()),
}),
};
let s2 = TestStruct {
a: 2,
b: None,
c: None,
nested: NestedStruct {
value: 20,
name: None,
},
optional_nested: None,
};
s1.merge(s2);
assert_eq!(
s1.optional_nested,
Some(NestedStruct {
value: 100,
name: Some("existing".to_string())
})
); // Should remain existing
}