deepmerge/
policy.rs

1//! Policy system for configuring merge behavior
2//!
3//! Policies define default behaviors for different types during merging.
4//! They can be overridden at struct, field, or type level.
5
6
7/// Scalar merge action for primitive types and structs.
8///
9/// This enum determines the fundamental merge strategy for scalar values
10/// and can be used to configure whether structs should be recursively merged
11/// or replaced entirely.
12///
13/// # Examples
14///
15/// ```rust
16/// use deepmerge::prelude::*;
17///
18/// // ScalarAction enum demonstrates merge strategies
19/// let replace_action = ScalarAction::Replace;
20/// let keep_action = ScalarAction::Keep;
21/// let merge_action = ScalarAction::Merge;
22///
23/// // Simple demonstration with basic merge
24/// #[derive(DeepMerge, Debug, PartialEq)]
25/// struct Config {
26///     name: String,
27///     value: i32,
28/// }
29///
30/// let mut config1 = Config { name: "app".to_string(), value: 10 };
31/// let config2 = Config { name: "service".to_string(), value: 20 };
32///
33/// // Default merge behavior - recursively merge fields
34/// config1.merge_with_policy(config2, &DefaultPolicy);
35/// assert_eq!(config1.name, "service"); // String uses Replace by default
36/// assert_eq!(config1.value, 20); // i32 uses Replace by default
37/// ```
38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
39#[non_exhaustive]
40pub enum ScalarAction {
41    /// Replace left with right (default for scalars)
42    Replace,
43    /// Keep left, ignore right
44    Keep,
45    /// Recursively merge (default for structs with `DeepMerge`)
46    Merge,
47}
48
49/// Sequence merge behavior for collections like `Vec<T>`, arrays, and slices.
50///
51/// This enum defines how two sequences should be combined during merging.
52/// Different strategies are useful for different use cases like configuration
53/// merging, data aggregation, or collection operations.
54///
55/// # Examples
56///
57/// ```rust
58/// use deepmerge::prelude::*;
59///
60/// let mut tags1 = vec!["rust", "web"];
61/// let tags2 = vec!["api", "server"];
62///
63/// // Append: add right elements to the end (default)
64/// let policy = ComposedPolicy::new(DefaultPolicy)
65///     .with_sequence_merge(SequenceMerge::Append);
66/// let mut test = tags1.clone();
67/// test.merge_with_policy(tags2.clone(), &policy);
68/// assert_eq!(test, vec!["rust", "web", "api", "server"]);
69///
70/// // Prepend: add right elements to the beginning
71/// let policy = ComposedPolicy::new(DefaultPolicy)
72///     .with_sequence_merge(SequenceMerge::Prepend);
73/// let mut test = tags1.clone();
74/// test.merge_with_policy(tags2.clone(), &policy);
75/// assert_eq!(test, vec!["api", "server", "rust", "web"]);
76///
77/// // Extend: same as Append but optimized for performance
78/// let policy = ComposedPolicy::new(DefaultPolicy)
79///     .with_sequence_merge(SequenceMerge::Extend);
80/// let mut test = tags1.clone();
81/// test.merge_with_policy(tags2.clone(), &policy);
82/// assert_eq!(test, vec!["rust", "web", "api", "server"]);
83/// ```
84///
85/// # Note
86/// 
87/// `Union` and `Intersect` operations may require additional trait bounds
88/// or special handling depending on the element type.
89#[derive(Debug, Clone, Copy, PartialEq, Eq)]
90#[non_exhaustive]
91pub enum SequenceMerge {
92    /// Append right to left (default)
93    Append,
94    /// Prepend right to left
95    Prepend,
96    /// Extend left with right (like `HashMap::extend`)
97    Extend,
98    /// Union of left and right (dedupe)
99    Union,
100    /// Intersection of left and right
101    Intersect,
102}
103
104/// Option merge behavior for `Option<T>` types.
105///
106/// This enum defines how two `Option` values should be combined,
107/// providing different strategies for handling `Some` and `None` values.
108///
109/// # Examples
110///
111/// ```rust
112/// use deepmerge::prelude::*;
113///
114/// // Take: use right if Some, otherwise keep left (default)
115/// let policy = ComposedPolicy::new(DefaultPolicy)
116///     .with_option_merge(OptionMerge::Take);
117/// let mut left = Some(42);
118/// left.merge_with_policy(Some(100), &policy);
119/// assert_eq!(left, Some(100));
120/// 
121/// let mut left = Some(42);
122/// left.merge_with_policy(None, &policy);
123/// assert_eq!(left, Some(42));
124///
125/// // Preserve: always keep left, ignore right
126/// let policy = ComposedPolicy::new(DefaultPolicy)
127///     .with_option_merge(OptionMerge::Preserve);
128/// let mut left = Some(42);
129/// left.merge_with_policy(Some(100), &policy);
130/// assert_eq!(left, Some(42));
131///
132/// // OrLeft: use left if Some, otherwise use right
133/// let policy = ComposedPolicy::new(DefaultPolicy)
134///     .with_option_merge(OptionMerge::OrLeft);
135/// let mut left: Option<i32> = None;
136/// left.merge_with_policy(Some(100), &policy);
137/// assert_eq!(left, Some(100));
138/// ```
139#[derive(Debug, Clone, Copy, PartialEq, Eq)]
140#[non_exhaustive]
141pub enum OptionMerge {
142    /// Take right if Some, else keep left (default)
143    Take,
144    /// Always keep left, ignore right
145    Preserve,
146    /// Take left if Some, else take right
147    OrLeft,
148}
149
150/// Number merge behavior for numeric types.
151///
152/// This enum defines different strategies for combining two numeric values,
153/// supporting arithmetic operations and comparisons.
154///
155/// # Examples
156///
157/// ```rust
158/// use deepmerge::prelude::*;
159///
160/// // Sum: add values together
161/// #[derive(DeepMerge)]
162/// #[merge(policy(number = sum))]
163/// struct Config { score: i32 }
164///
165/// let mut config = Config { score: 10 };
166/// config.merge_with_policy(Config { score: 25 }, &DefaultPolicy);
167/// assert_eq!(config.score, 35);
168///
169/// // Max: keep the larger value  
170/// #[derive(DeepMerge)]
171/// #[merge(policy(number = max))]
172/// struct MaxConfig { value: i32 }
173///
174/// let mut config = MaxConfig { value: 10 };
175/// config.merge_with_policy(MaxConfig { value: 5 }, &DefaultPolicy);
176/// assert_eq!(config.value, 10);
177/// config.merge_with_policy(MaxConfig { value: 15 }, &DefaultPolicy);
178/// assert_eq!(config.value, 15);
179///
180/// // Min: keep the smaller value
181/// #[derive(DeepMerge)]
182/// #[merge(policy(number = min))]
183/// struct MinConfig { value: i32 }
184///
185/// let mut config = MinConfig { value: 10 };
186/// config.merge_with_policy(MinConfig { value: 5 }, &DefaultPolicy);
187/// assert_eq!(config.value, 5);
188/// config.merge_with_policy(MinConfig { value: 15 }, &DefaultPolicy);
189/// assert_eq!(config.value, 5);
190/// ```
191#[derive(Debug, Clone, Copy, PartialEq, Eq)]
192#[non_exhaustive]
193pub enum NumberMerge {
194    /// Replace with right (default)
195    Replace,
196    /// Keep left, ignore right
197    Keep,
198    /// Take maximum of left and right
199    Max,
200    /// Take minimum of left and right
201    Min,
202    /// Sum left and right
203    Sum,
204}
205
206/// Map merge behavior for `HashMap` and `BTreeMap` types.
207///
208/// This enum defines strategies for combining two maps, handling key conflicts
209/// and nested value merging in different ways.
210///
211/// # Examples
212///
213/// ```rust
214/// use std::collections::HashMap;
215/// use deepmerge::prelude::*;
216///
217/// // Overlay: merge recursively, right wins on conflicts (default)
218/// #[derive(DeepMerge)]
219/// #[merge(policy(map = overlay))]
220/// struct Config {
221///     settings: HashMap<String, i32>,
222/// }
223///
224/// let mut config = Config {
225///     settings: [("a".to_string(), 1), ("b".to_string(), 2)].into(),
226/// };
227/// let update = Config {
228///     settings: [("b".to_string(), 3), ("c".to_string(), 4)].into(),
229/// };
230/// config.merge_with_policy(update, &DefaultPolicy);
231/// // Result: {"a": 1, "b": 3, "c": 4}
232/// assert_eq!(config.settings.get("a"), Some(&1));
233/// assert_eq!(config.settings.get("b"), Some(&3)); // right wins
234/// assert_eq!(config.settings.get("c"), Some(&4));
235///
236/// // Left: keep only left entries
237/// #[derive(DeepMerge)]
238/// #[merge(policy(map = left))]
239/// struct LeftConfig {
240///     data: HashMap<String, i32>,
241/// }
242///
243/// let mut config = LeftConfig {
244///     data: [("a".to_string(), 1), ("b".to_string(), 2)].into(),
245/// };
246/// let update = LeftConfig {
247///     data: [("b".to_string(), 3), ("c".to_string(), 4)].into(),
248/// };
249/// config.merge_with_policy(update, &DefaultPolicy);
250/// // Result: {"a": 1, "b": 2} (unchanged)
251/// assert_eq!(config.data.len(), 2);
252/// assert_eq!(config.data.get("c"), None);
253/// ```
254#[derive(Debug, Clone, Copy, PartialEq, Eq)]
255#[non_exhaustive]
256pub enum MapMerge {
257    /// Overlay right entries, merge values recursively (default)
258    Overlay,
259    /// Union of keys, prefer right on conflicts
260    Union,
261    /// Keep only left entries
262    Left,
263    /// Replace with right entries
264    Right,
265}
266
267/// Boolean merge behavior for `bool` types.
268///
269/// This enum defines logical operations for combining two boolean values,
270/// supporting different prioritization strategies.
271///
272/// # Examples
273///
274/// ```rust
275/// use deepmerge::prelude::*;
276///
277/// // TrueWins: logical OR behavior
278/// #[derive(DeepMerge)]
279/// #[merge(policy(bool = true_wins))]
280/// struct Config { enabled: bool }
281///
282/// let mut config = Config { enabled: false };
283/// config.merge_with_policy(Config { enabled: true }, &DefaultPolicy);
284/// assert_eq!(config.enabled, true);
285///
286/// let mut config = Config { enabled: true };
287/// config.merge_with_policy(Config { enabled: false }, &DefaultPolicy);
288/// assert_eq!(config.enabled, true); // true wins
289///
290/// // FalseWins: logical NOR behavior  
291/// #[derive(DeepMerge)]
292/// #[merge(policy(bool = false_wins))]
293/// struct FalseConfig { active: bool }
294///
295/// let mut config = FalseConfig { active: true };
296/// config.merge_with_policy(FalseConfig { active: false }, &DefaultPolicy);
297/// assert_eq!(config.active, false); // false wins
298///
299/// // Keep: ignore right value
300/// #[derive(DeepMerge)]
301/// #[merge(policy(bool = keep))]
302/// struct KeepConfig { flag: bool }
303///
304/// let mut config = KeepConfig { flag: true };
305/// config.merge_with_policy(KeepConfig { flag: false }, &DefaultPolicy);
306/// assert_eq!(config.flag, true); // kept original
307/// ```
308#[derive(Debug, Clone, Copy, PartialEq, Eq)]
309#[non_exhaustive]
310pub enum BoolMerge {
311    /// Replace with right (default)
312    Replace,
313    /// Keep left, ignore right
314    Keep,
315    /// Set to true if either is true
316    TrueWins,
317    /// Set to false if either is false
318    FalseWins,
319}
320
321/// String merge behavior for `String` and `&str` types.
322///
323/// This enum defines different strategies for combining two string values,
324/// including concatenation with optional separators.
325///
326/// # Examples
327///
328/// ```rust
329/// use deepmerge::prelude::*;
330///
331/// // Concat: simple concatenation
332/// #[derive(DeepMerge)]
333/// #[merge(policy(string = concat))]
334/// struct Config { text: String }
335///
336/// let mut config = Config { text: "Hello".to_string() };
337/// config.merge_with_policy(Config { text: " World".to_string() }, &DefaultPolicy);
338/// assert_eq!(config.text, "Hello World");
339///
340/// // ConcatWithSep: concatenation with separator
341/// #[derive(DeepMerge)]
342/// #[merge(policy(string = StringMerge::ConcatWithSep(", ")))]
343/// struct ListConfig { items: String }
344///
345/// let mut config = ListConfig { items: "apple".to_string() };
346/// config.merge_with_policy(ListConfig { items: "banana".to_string() }, &DefaultPolicy);
347/// assert_eq!(config.items, "apple, banana");
348///
349/// // Keep: ignore right value
350/// #[derive(DeepMerge)]
351/// #[merge(policy(string = keep))]
352/// struct KeepConfig { name: String }
353///
354/// let mut config = KeepConfig { name: "original".to_string() };
355/// config.merge_with_policy(KeepConfig { name: "new".to_string() }, &DefaultPolicy);
356/// assert_eq!(config.name, "original");
357///
358/// // Field-level override with path separator
359/// #[derive(DeepMerge)]
360/// struct PathConfig {
361///     #[merge(string = StringMerge::ConcatWithSep(" -> "))]
362///     path: String,
363/// }
364///
365/// let mut config = PathConfig { path: "home".to_string() };
366/// config.merge_with_policy(PathConfig { path: "user".to_string() }, &DefaultPolicy);
367/// assert_eq!(config.path, "home -> user");
368/// ```
369#[derive(Debug, Clone, PartialEq, Eq)]
370#[non_exhaustive]
371pub enum StringMerge {
372    /// Replace left with right (default)
373    Replace,
374    /// Keep left, ignore right
375    Keep,
376    /// Concatenate right to left
377    Concat,
378    /// Concatenate with a separator
379    ConcatWithSep(&'static str),
380}
381
382/// When to apply merge operations (guards/conditions).
383///
384/// This enum provides conditional logic for determining whether a merge
385/// operation should be performed, enabling fine-grained control over when
386/// values are actually merged.
387///
388/// # Examples
389///
390/// ```rust
391/// use deepmerge::prelude::*;
392///
393/// // NonEmpty: only merge when right value is non-empty
394/// #[derive(DeepMerge)]
395/// #[merge(policy(condition = non_empty))]
396/// struct Config { text: String }
397/// 
398/// let mut config = Config { text: "original".to_string() };
399/// config.merge_with_policy(Config { text: "".to_string() }, &DefaultPolicy);
400/// assert_eq!(config.text, "original"); // empty string ignored
401/// 
402/// config.merge_with_policy(Config { text: "new".to_string() }, &DefaultPolicy);
403/// assert_eq!(config.text, "new"); // non-empty string merged
404///
405/// // NonDefault: only merge when right is not default value
406/// #[derive(DeepMerge)]
407/// #[merge(policy(condition = non_default))]
408/// struct DefaultConfig { value: i32 }
409/// 
410/// let mut config = DefaultConfig { value: 42 };
411/// config.merge_with_policy(DefaultConfig { value: 0 }, &DefaultPolicy); // 0 is default for i32
412/// assert_eq!(config.value, 42); // default ignored
413/// 
414/// config.merge_with_policy(DefaultConfig { value: 99 }, &DefaultPolicy);
415/// assert_eq!(config.value, 99); // non-default merged
416///
417/// // Some: only merge when Option is Some
418/// #[derive(DeepMerge)]
419/// #[merge(policy(condition = some))]
420/// struct OptConfig { data: Option<i32> }
421/// 
422/// let mut config = OptConfig { data: Some(42) };
423/// config.merge_with_policy(OptConfig { data: None }, &DefaultPolicy);
424/// assert_eq!(config.data, Some(42)); // None ignored
425/// 
426/// config.merge_with_policy(OptConfig { data: Some(99) }, &DefaultPolicy);
427/// assert_eq!(config.data, Some(99)); // Some merged
428///
429/// // Changed: only merge when values differ
430/// #[derive(DeepMerge)]
431/// #[merge(policy(condition = changed))]
432/// struct ChangeConfig { count: i32 }
433/// 
434/// let mut config = ChangeConfig { count: 42 };
435/// config.merge_with_policy(ChangeConfig { count: 42 }, &DefaultPolicy);
436/// assert_eq!(config.count, 42); // same value ignored
437/// 
438/// config.merge_with_policy(ChangeConfig { count: 99 }, &DefaultPolicy);
439/// assert_eq!(config.count, 99); // different value merged
440/// ```
441#[derive(Debug)]
442pub enum Condition {
443    /// Always apply (default)
444    Always,
445    /// Only when right is non-empty (for collections/strings)
446    NonEmpty,
447    /// Only when right is not the default value
448    NonDefault,
449    /// Only when right is Some (for Options)
450    Some,
451    /// Only when right differs from left
452    Changed,
453    /// Only when right differs from left according to a custom key extractor function
454    /// This stores a function that can extract comparable keys from values
455    /// The function signature should be fn(&T) -> K where K: `PartialEq`
456    ChangedBy(fn()),
457}
458
459impl Clone for Condition {
460    fn clone(&self) -> Self {
461        match self {
462            Condition::Always => Condition::Always,
463            Condition::NonEmpty => Condition::NonEmpty,
464            Condition::NonDefault => Condition::NonDefault,
465            Condition::Some => Condition::Some,
466            Condition::Changed => Condition::Changed,
467            Condition::ChangedBy(f) => Condition::ChangedBy(*f),
468        }
469    }
470}
471
472impl PartialEq for Condition {
473    fn eq(&self, other: &Self) -> bool {
474        match (self, other) {
475            (Condition::Always, Condition::Always)
476            | (Condition::NonEmpty, Condition::NonEmpty)
477            | (Condition::NonDefault, Condition::NonDefault)
478            | (Condition::Some, Condition::Some)
479            | (Condition::Changed, Condition::Changed) => true,
480            (Condition::ChangedBy(f1), Condition::ChangedBy(f2)) => core::ptr::eq(std::ptr::from_ref::<fn()>(f1), std::ptr::from_ref::<fn()>(f2)),
481            _ => false,
482        }
483    }
484}
485
486impl Eq for Condition {}
487
488/// Policy trait defining default merge behaviors
489pub trait Policy: Clone {
490    /// Default action for scalars
491    fn scalar_action(&self) -> ScalarAction {
492        ScalarAction::Replace
493    }
494
495    /// Default action for structs that implement `DeepMerge`
496    fn struct_action(&self) -> ScalarAction {
497        ScalarAction::Merge
498    }
499
500    /// Default strategy for Options
501    fn option_merge(&self) -> OptionMerge {
502        OptionMerge::Take
503    }
504
505    /// Default strategy for sequences (Vec, arrays, etc.)
506    fn sequence_merge(&self) -> SequenceMerge {
507        SequenceMerge::Append
508    }
509
510    /// Whether to deduplicate sequences by default
511    fn sequence_dedupe(&self) -> bool {
512        false
513    }
514
515    /// Default strategy for maps (`HashMap`, `BTreeMap`, etc.)
516    fn map_merge(&self) -> MapMerge {
517        MapMerge::Overlay
518    }
519
520    /// Default strategy for numbers
521    fn number_merge(&self) -> NumberMerge {
522        NumberMerge::Replace
523    }
524
525    /// Default strategy for booleans
526    fn bool_merge(&self) -> BoolMerge {
527        BoolMerge::Replace
528    }
529
530    /// Default strategy for strings
531    fn string_merge(&self) -> StringMerge {
532        StringMerge::Replace
533    }
534
535    /// Default when condition
536    fn when_condition(&self) -> Condition {
537        Condition::Always
538    }
539}
540
541/// Default policy with sensible defaults
542#[derive(Debug, Clone, Copy, Default)]
543pub struct DefaultPolicy;
544
545impl Policy for DefaultPolicy {
546    // Uses all the default implementations
547}
548
549/// Policy that always replaces (no merging)
550#[derive(Debug, Clone, Copy, Default)]
551pub struct StrictReplacePolicy;
552
553impl Policy for StrictReplacePolicy {
554    fn struct_action(&self) -> ScalarAction {
555        ScalarAction::Replace
556    }
557    
558    fn map_merge(&self) -> MapMerge {
559        MapMerge::Right
560    }
561}
562
563/// Policy that preserves left values
564#[derive(Debug, Clone, Copy, Default)]
565pub struct PreservePolicy;
566
567impl Policy for PreservePolicy {
568    fn scalar_action(&self) -> ScalarAction {
569        ScalarAction::Keep
570    }
571    
572    fn struct_action(&self) -> ScalarAction {
573        ScalarAction::Keep
574    }
575    
576    fn option_merge(&self) -> OptionMerge {
577        OptionMerge::Preserve
578    }
579    
580    fn sequence_merge(&self) -> SequenceMerge {
581        SequenceMerge::Extend // Keep left, ignore right
582    }
583    
584    fn map_merge(&self) -> MapMerge {
585        MapMerge::Left
586    }
587    
588    fn number_merge(&self) -> NumberMerge {
589        NumberMerge::Keep // Preserve left values
590    }
591    
592    fn bool_merge(&self) -> BoolMerge {
593        BoolMerge::Keep
594    }
595    
596    fn string_merge(&self) -> StringMerge {
597        StringMerge::Keep
598    }
599    
600    fn when_condition(&self) -> Condition {
601        Condition::Always // But we'll ignore the merge anyway due to other settings
602    }
603}
604
605/// Policy that deduplicates collections
606#[derive(Debug, Clone, Copy, Default)]
607pub struct DedupeCollectionsPolicy;
608
609impl Policy for DedupeCollectionsPolicy {
610    fn sequence_merge(&self) -> SequenceMerge {
611        SequenceMerge::Union
612    }
613    
614    fn sequence_dedupe(&self) -> bool {
615        true
616    }
617}
618
619/// Composed policy that overrides specific behaviors from a base policy
620/// Used by the derive macro to implement field-level policy overrides
621#[derive(Debug, Clone)]
622pub struct ComposedPolicy<P: Policy> {
623    /// The base policy to use when no override is specified
624    pub base: P,
625    /// Override for scalar merge behavior 
626    pub scalar_action: Option<ScalarAction>,
627    /// Override for struct merge behavior
628    pub struct_action: Option<ScalarAction>,
629    /// Override for Option<T> merge behavior
630    pub option_merge: Option<OptionMerge>,
631    /// Override for sequence (Vec, arrays) merge behavior
632    pub sequence_merge: Option<SequenceMerge>,
633    /// Whether to deduplicate sequences after merging
634    pub sequence_dedupe: Option<bool>,
635    /// Override for HashMap/BTreeMap merge behavior
636    pub map_merge: Option<MapMerge>,
637    /// Override for numeric type merge behavior
638    pub number_merge: Option<NumberMerge>,
639    /// Override for boolean merge behavior
640    pub bool_merge: Option<BoolMerge>,
641    /// Override for string merge behavior
642    pub string_merge: Option<StringMerge>,
643    /// Condition for when to apply the merge
644    pub when_condition: Option<Condition>,
645}
646
647impl<P: Policy> ComposedPolicy<P> {
648    /// Create a new composed policy with the given base policy and no overrides
649    pub fn new(base: P) -> Self {
650        Self {
651            base,
652            scalar_action: None,
653            struct_action: None,
654            option_merge: None,
655            sequence_merge: None,
656            sequence_dedupe: None,
657            map_merge: None,
658            number_merge: None,
659            bool_merge: None,
660            string_merge: None,
661            when_condition: None,
662        }
663    }
664    
665    /// Set the scalar action for this policy
666    #[must_use]
667    pub fn with_scalar_action(mut self, action: ScalarAction) -> Self {
668        self.scalar_action = Some(action);
669        self
670    }
671    
672    /// Set the struct action for this policy
673    #[must_use]
674    pub fn with_struct_action(mut self, action: ScalarAction) -> Self {
675        self.struct_action = Some(action);
676        self
677    }
678    
679    /// Set the option merge strategy
680    #[must_use]
681    pub fn with_option_merge(mut self, merge: OptionMerge) -> Self {
682        self.option_merge = Some(merge);
683        self
684    }
685    
686    /// Set the sequence merge strategy
687    #[must_use]
688    pub fn with_sequence_merge(mut self, merge: SequenceMerge) -> Self {
689        self.sequence_merge = Some(merge);
690        self
691    }
692    
693    /// Set whether to deduplicate sequences
694    #[must_use]
695    pub fn with_sequence_dedupe(mut self, dedupe: bool) -> Self {
696        self.sequence_dedupe = Some(dedupe);
697        self
698    }
699    
700    /// Set the map merge strategy
701    #[must_use]
702    pub fn with_map_merge(mut self, merge: MapMerge) -> Self {
703        self.map_merge = Some(merge);
704        self
705    }
706    
707    /// Set the number merge strategy
708    #[must_use]
709    pub fn with_number_merge(mut self, merge: NumberMerge) -> Self {
710        self.number_merge = Some(merge);
711        self
712    }
713    
714    /// Set the boolean merge strategy
715    #[must_use]
716    pub fn with_bool_merge(mut self, merge: BoolMerge) -> Self {
717        self.bool_merge = Some(merge);
718        self
719    }
720    
721    /// Set the string merge strategy
722    #[must_use]
723    pub fn with_string_merge(mut self, merge: StringMerge) -> Self {
724        self.string_merge = Some(merge);
725        self
726    }
727    
728    /// Set the when condition
729    #[must_use]
730    pub fn with_when_condition(mut self, condition: Condition) -> Self {
731        self.when_condition = Some(condition);
732        self
733    }
734}
735
736impl<P: Policy> Policy for ComposedPolicy<P> {
737    fn scalar_action(&self) -> ScalarAction {
738        self.scalar_action.unwrap_or_else(|| self.base.scalar_action())
739    }
740    
741    fn struct_action(&self) -> ScalarAction {
742        self.struct_action.unwrap_or_else(|| self.base.struct_action())
743    }
744    
745    fn option_merge(&self) -> OptionMerge {
746        self.option_merge.unwrap_or_else(|| self.base.option_merge())
747    }
748    
749    fn sequence_merge(&self) -> SequenceMerge {
750        self.sequence_merge.unwrap_or_else(|| self.base.sequence_merge())
751    }
752    
753    fn sequence_dedupe(&self) -> bool {
754        self.sequence_dedupe.unwrap_or_else(|| self.base.sequence_dedupe())
755    }
756    
757    fn map_merge(&self) -> MapMerge {
758        self.map_merge.unwrap_or_else(|| self.base.map_merge())
759    }
760    
761    fn number_merge(&self) -> NumberMerge {
762        self.number_merge.unwrap_or_else(|| self.base.number_merge())
763    }
764    
765    fn bool_merge(&self) -> BoolMerge {
766        self.bool_merge.unwrap_or_else(|| self.base.bool_merge())
767    }
768    
769    fn string_merge(&self) -> StringMerge {
770        self.string_merge.clone().unwrap_or_else(|| self.base.string_merge())
771    }
772    
773    fn when_condition(&self) -> Condition {
774        self.when_condition.clone().unwrap_or_else(|| self.base.when_condition())
775    }
776}
777
778/// Result of a merge operation indicating what changed
779#[derive(Debug, Clone, Copy, PartialEq, Eq)]
780pub enum MergeOutcome {
781    /// Nothing was changed during the merge
782    Unchanged,
783    /// Something was changed during the merge
784    Changed,
785}
786
787impl MergeOutcome {
788    /// Check if the merge changed anything
789    #[must_use]
790    pub fn is_changed(&self) -> bool {
791        matches!(self, MergeOutcome::Changed)
792    }
793    
794    /// Check if the merge left everything unchanged
795    #[must_use]
796    pub fn is_unchanged(&self) -> bool {
797        matches!(self, MergeOutcome::Unchanged)
798    }
799}
800
801/// Merge trait with policy parameter
802pub trait DeepMerge<P: Policy = DefaultPolicy>: Sized {
803    /// Merge another instance into this one using the specified policy
804    fn merge_with_policy(&mut self, other: Self, policy: &P);
805    
806    /// Merge another instance by reference using the specified policy
807    /// This avoids moving the source when possible
808    fn merge_ref(&mut self, src: &Self, policy: &P)
809    where
810        Self: Clone,
811    {
812        self.merge_with_policy(src.clone(), policy);
813    }
814    
815    /// Merge and report whether anything changed
816    fn merge_with_policy_reporting(&mut self, other: Self, policy: &P) -> MergeOutcome {
817        // Default implementation just merges and reports changed
818        // Individual types can override for more precise change detection
819        self.merge_with_policy(other, policy);
820        MergeOutcome::Changed
821    }
822    
823    /// Merge by reference and report whether anything changed
824    fn merge_ref_reporting(&mut self, src: &Self, policy: &P) -> MergeOutcome
825    where
826        Self: Clone,
827    {
828        self.merge_with_policy_reporting(src.clone(), policy)
829    }
830    
831    /// Non-mutating merge using the specified policy
832    #[must_use]
833    fn merged_with_policy(mut self, other: Self, policy: &P) -> Self {
834        self.merge_with_policy(other, policy);
835        self
836    }
837}
838
839/// Merge trait for merging from other types, including references
840/// This allows merging from U into Self without requiring Clone on U
841pub trait DeepMergeFrom<U, P: Policy = DefaultPolicy> {
842    /// Merge from another type/reference using the specified policy
843    fn merge_from_with_policy(&mut self, other: U, policy: &P);
844    
845    /// Merge from another type/reference and report whether anything changed
846    fn merge_from_with_policy_reporting(&mut self, other: U, policy: &P) -> MergeOutcome {
847        // Default implementation just merges and reports changed
848        // Individual types can override for more precise change detection
849        self.merge_from_with_policy(other, policy);
850        MergeOutcome::Changed
851    }
852}
853
854/// Extension trait for convenience methods when using `DefaultPolicy`
855/// 
856/// This trait provides shorthand methods for common merge operations
857/// without requiring explicit policy arguments.
858pub trait DeepMergeDefault: DeepMerge<DefaultPolicy> {
859    /// Merge using the default policy
860    fn merge(&mut self, other: Self) {
861        self.merge_with_policy(other, &DefaultPolicy);
862    }
863    
864    /// Merge by reference using the default policy
865    fn merge_ref(&mut self, src: &Self)
866    where
867        Self: Clone,
868    {
869        DeepMerge::merge_ref(self, src, &DefaultPolicy);
870    }
871    
872    /// Merge and report changes using the default policy
873    fn merge_reporting(&mut self, other: Self) -> MergeOutcome {
874        self.merge_with_policy_reporting(other, &DefaultPolicy)
875    }
876    
877    /// Merge by reference and report changes using the default policy
878    fn merge_ref_reporting(&mut self, src: &Self) -> MergeOutcome
879    where
880        Self: Clone,
881    {
882        DeepMerge::merge_ref_reporting(self, src, &DefaultPolicy)
883    }
884    
885    /// Non-mutating merge using the default policy
886    #[must_use]
887    fn merged(self, other: Self) -> Self {
888        self.merged_with_policy(other, &DefaultPolicy)
889    }
890}
891
892// Blanket impl for all types that implement DeepMerge<DefaultPolicy>
893impl<T: DeepMerge<DefaultPolicy>> DeepMergeDefault for T {}
894
895/// Extension trait for `DeepMergeFrom` convenience methods when using `DefaultPolicy`
896pub trait DeepMergeFromDefault<U>: DeepMergeFrom<U, DefaultPolicy> {
897    /// Merge from another type/reference using the default policy
898    fn merge_from(&mut self, other: U) {
899        self.merge_from_with_policy(other, &DefaultPolicy);
900    }
901    
902    /// Merge from another type/reference and report changes using the default policy
903    fn merge_from_reporting(&mut self, other: U) -> MergeOutcome {
904        self.merge_from_with_policy_reporting(other, &DefaultPolicy)
905    }
906}
907
908// Blanket impl for all types that implement DeepMergeFrom<U, DefaultPolicy>
909impl<T: DeepMergeFrom<U, DefaultPolicy>, U> DeepMergeFromDefault<U> for T {}
910
911// Bridge implementation: DeepMerge -> DeepMergeFrom for owned types
912impl<T: DeepMerge<P>, P: Policy> DeepMergeFrom<T, P> for T {
913    fn merge_from_with_policy(&mut self, other: T, policy: &P) {
914        self.merge_with_policy(other, policy);
915    }
916    
917    fn merge_from_with_policy_reporting(&mut self, other: T, policy: &P) -> MergeOutcome {
918        self.merge_with_policy_reporting(other, policy)
919    }
920}
921
922// Bridge implementation: DeepMerge -> DeepMergeFrom for references (requires Clone)
923impl<T: DeepMerge<P> + Clone, P: Policy> DeepMergeFrom<&T, P> for T {
924    fn merge_from_with_policy(&mut self, other: &T, policy: &P) {
925        self.merge_ref(other, policy);
926    }
927    
928    fn merge_from_with_policy_reporting(&mut self, other: &T, policy: &P) -> MergeOutcome {
929        self.merge_ref_reporting(other, policy)
930    }
931}