#policy #deep

no-std deepmerge

Deep merge functionality with policy-driven merging and derive macro support

1 unstable release

Uses new Rust 2024

0.1.0 Sep 10, 2025

#176 in Configuration

MIT/Apache

135KB
2K SLoC

DeepMerge

A flexible deep merge library for Rust with policy-driven merging and derive macros featuring typed attributes.

Features

  • Policy-driven merging: Configure how different types should be merged
  • Derive macro support: Automatically implement DeepMerge for your structs
  • Typed attributes: Use identifiers instead of string literals for better compile-time checking
  • Flexible attribute syntax: Mix string literals, identifiers, and path expressions
  • Precedence rules: Field-level > struct-level > caller-provided policies
  • Multiple merge strategies: Append, prepend, union, concatenation, replacement, and more
  • No-std compatible: Works without the standard library (with alloc)

Quick Start

Add this to your Cargo.toml:

[dependencies]
deepmerge = { version = "0.1", features = ["derive"] }

Usage Examples

Basic Usage with Typed Attributes

use deepmerge::prelude::*;

// Use clean identifier syntax instead of string literals
#[derive(DeepMerge, Debug)]
#[merge(policy(string = concat, sequence = append, bool = true_wins))]
struct Config {
    pub title: String,
    pub tags: Vec<String>,
    pub enabled: bool,
    
    // Field-level override
    #[merge(string = keep)]
    pub version: String,
}

let mut config = Config {
    title: "My App".to_string(),
    tags: vec!["web".to_string()],
    enabled: false,
    version: "1.0".to_string(),
};

let update = Config {
    title: " v2".to_string(),
    tags: vec!["api".to_string()],
    enabled: true,
    version: "2.0".to_string(),
};

config.merge_with_policy(update, &DefaultPolicy);

// Results:
// title: "My App v2" (concatenated)
// tags: ["web", "api"] (appended)  
// enabled: true (true wins)
// version: "1.0" (kept original due to field-level override)

Supported Attribute Syntax

use deepmerge::prelude::*;

#[derive(DeepMerge)]
#[merge(policy(
    // String literals (traditional)
    string = "concat",
    
    // Identifiers (new, cleaner syntax) 
    sequence = append,
    bool = true_wins,
    number = sum,
    
    // Mixed syntax is supported
    map = "overlay"
))]
struct FlexibleConfig { /* ... */ }

Available Merge Policies

String Policies: concat, keep, replace
Sequence Policies: append, prepend, union, extend, intersect
Boolean Policies: true_wins, false_wins, replace, keep
Number Policies: sum, max, min, replace, keep
Map Policies: overlay, union, left, right
Option Policies: take, preserve, or_left

Policy Precedence

Policies are applied in this order of precedence:

  1. Field-level attributes (highest priority)
  2. Struct-level attributes
  3. Caller-provided policies (lowest priority)

Advanced Features

Future Path Expression Support

The infrastructure is ready for advanced path expressions:

// Coming soon:
// #[merge(policy(string = StringMerge::ConcatWithSep(", ")))]

Condition Policies with Key Extractors

// Coming soon:
// #[merge(policy(condition = changed, changed_by = "key_extractor_fn"))]

Feature Flags

  • derive (default): Enable the derive macro
  • std (default): Enable standard library support
  • alloc (default): Enable allocation support
  • indexmap: Add support for IndexMap types

License

Licensed under either of:

  • Apache License, Version 2.0
  • MIT License

at your option.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Dependencies

~0–600KB
~12K SLoC