deepmerge 0.1.0

Deep merge functionality with policy-driven merging and derive macro support
Documentation
/// Example demonstrating the new policy-based merge system

use deepmerge::prelude::*;
use std::collections::HashMap;

#[test]
fn test_default_policy_behavior() {
    // Test scalars
    let mut num = 10;
    deep_merge(&mut num, 20);
    assert_eq!(num, 20); // Replace by default
    
    // Test booleans
    let mut flag = false;
    deep_merge(&mut flag, true);
    assert_eq!(flag, true); // Replace by default
    
    // Test strings
    let mut text = String::from("hello");
    deep_merge(&mut text, String::from("world"));
    assert_eq!(text, "world"); // Replace if non-empty
    
    // Test vectors
    let mut vec = vec![1, 2, 3];
    deep_merge(&mut vec, vec![4, 5]);
    assert_eq!(vec, vec![1, 2, 3, 4, 5]); // Append by default
    
    // Test HashMaps
    let mut map = HashMap::from([("a", 1), ("b", 2)]);
    deep_merge(&mut map, HashMap::from([("b", 3), ("c", 4)]));
    assert_eq!(map.get("a"), Some(&1)); // Preserved
    assert_eq!(map.get("b"), Some(&3)); // Overlaid
    assert_eq!(map.get("c"), Some(&4)); // Added
}

#[test]
fn test_custom_policy() {
    use deepmerge::policy::{ScalarAction, SequenceMerge, BoolMerge, NumberMerge};
    
    #[derive(Clone)]
    struct CustomPolicy;
    
    impl Policy for CustomPolicy {
        fn scalar_action(&self) -> ScalarAction {
            ScalarAction::Keep // Keep left values
        }
        
        fn sequence_merge(&self) -> SequenceMerge {
            SequenceMerge::Union // Union with deduplication
        }
        
        fn sequence_dedupe(&self) -> bool {
            true
        }
        
        fn bool_merge(&self) -> BoolMerge {
            BoolMerge::TrueWins // OR behavior
        }
        
        fn number_merge(&self) -> NumberMerge {
            NumberMerge::Max // Take maximum
        }
    }
    
    let policy = CustomPolicy;
    
    // Test numbers with Max strategy
    let mut num = 10;
    deepmerge::deep_merge_with_policy(&mut num, 5, &policy);
    assert_eq!(num, 10); // Max(10, 5) = 10
    
    let mut num = 10;
    deepmerge::deep_merge_with_policy(&mut num, 20, &policy);
    assert_eq!(num, 20); // Max(10, 20) = 20
    
    // Test booleans with TrueWins
    let mut flag = false;
    deepmerge::deep_merge_with_policy(&mut flag, true, &policy);
    assert_eq!(flag, true); // false || true = true
    
    let mut flag = true;
    deepmerge::deep_merge_with_policy(&mut flag, false, &policy);
    assert_eq!(flag, true); // true || false = true
    
    // Test vectors with Union (Vec treats Union as Append without deduplication)
    let mut vec = vec![1, 2, 3];
    deepmerge::deep_merge_with_policy(&mut vec, vec![3, 4, 5], &policy);
    assert_eq!(vec, vec![1, 2, 3, 3, 4, 5]); // Vec doesn't deduplicate without PartialEq
}

#[test]
fn test_non_mutating_merge() {
    // Test the new non-mutating API
    let config1 = HashMap::from([("debug", true), ("verbose", false)]);
    let config2 = HashMap::from([("verbose", true), ("quiet", false)]);
    
    // Using merged() for builder-style
    let result = config1.clone().merged(config2);
    assert_eq!(result.get("debug"), Some(&true));
    assert_eq!(result.get("verbose"), Some(&true)); // Overwritten
    assert_eq!(result.get("quiet"), Some(&false));
    
    // Original unchanged
    assert_eq!(config1.get("verbose"), Some(&false));
}

#[test]
fn test_bool_merge_strategies() {
    use deepmerge::policy::BoolMerge;
    
    #[derive(Clone)]
    struct BoolPolicy {
        strategy: BoolMerge,
    }
    
    impl Policy for BoolPolicy {
        fn bool_merge(&self) -> BoolMerge {
            self.strategy
        }
    }
    
    // Test Replace
    let mut val = true;
    val.merge_with_policy(false, &BoolPolicy { strategy: BoolMerge::Replace });
    assert_eq!(val, false);
    
    // Test Keep
    let mut val = true;
    val.merge_with_policy(false, &BoolPolicy { strategy: BoolMerge::Keep });
    assert_eq!(val, true);
    
    // Test TrueWins
    let mut val = false;
    val.merge_with_policy(true, &BoolPolicy { strategy: BoolMerge::TrueWins });
    assert_eq!(val, true);
    
    let mut val = true;
    val.merge_with_policy(false, &BoolPolicy { strategy: BoolMerge::TrueWins });
    assert_eq!(val, true);
    
    // Test FalseWins
    let mut val = true;
    val.merge_with_policy(false, &BoolPolicy { strategy: BoolMerge::FalseWins });
    assert_eq!(val, false);
    
    let mut val = false;
    val.merge_with_policy(true, &BoolPolicy { strategy: BoolMerge::FalseWins });
    assert_eq!(val, false);
}

#[test]
fn test_btree_containers() {
    use std::collections::{BTreeMap, BTreeSet};
    
    // Test BTreeMap
    let mut btree = BTreeMap::from([("a", 1), ("b", 2)]);
    deep_merge(&mut btree, BTreeMap::from([("b", 3), ("c", 4)]));
    assert_eq!(btree.get("a"), Some(&1));
    assert_eq!(btree.get("b"), Some(&3)); // Overlaid
    assert_eq!(btree.get("c"), Some(&4));
    
    // Test BTreeSet
    let mut set = BTreeSet::from([1, 2, 3]);
    deep_merge(&mut set, BTreeSet::from([3, 4, 5]));
    assert_eq!(set.len(), 5); // Union by default
    assert!(set.contains(&1));
    assert!(set.contains(&5));
}