diffo 0.2.0

Semantic diffing for Rust structs via serde
Documentation
//! Configuration and masking example

use diffo::{diff_with, DiffConfig};
use serde::Serialize;

#[derive(Serialize)]
struct AppConfig {
    version: String,
    database: DatabaseConfig,
    api: ApiConfig,
    metrics: Metrics,
}

#[derive(Serialize)]
struct DatabaseConfig {
    host: String,
    port: u16,
    username: String,
    password: String,
}

#[derive(Serialize)]
struct ApiConfig {
    endpoint: String,
    api_key: String,
    timeout: u64,
}

#[derive(Serialize)]
struct Metrics {
    cpu_usage: f64,
    memory_usage: f64,
    disk_usage: f64,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let old = AppConfig {
        version: "1.0.0".into(),
        database: DatabaseConfig {
            host: "localhost".into(),
            port: 5432,
            username: "admin".into(),
            password: "old_secret_123".into(),
        },
        api: ApiConfig {
            endpoint: "http://api.example.com".into(),
            api_key: "key_abc123".into(),
            timeout: 30,
        },
        metrics: Metrics {
            cpu_usage: 45.2,
            memory_usage: 62.5,
            disk_usage: 78.9,
        },
    };

    let new = AppConfig {
        version: "1.1.0".into(),
        database: DatabaseConfig {
            host: "db.prod.example.com".into(),
            port: 5432,
            username: "admin".into(),
            password: "new_secret_456".into(),
        },
        api: ApiConfig {
            endpoint: "https://api.example.com".into(),
            api_key: "key_xyz789".into(),
            timeout: 60,
        },
        metrics: Metrics {
            cpu_usage: 45.200001, // Very small change
            memory_usage: 65.0,   // Larger change
            disk_usage: 78.9,     // No change
        },
    };

    println!("=== Without Configuration ===\n");
    let diff = diffo::diff(&old, &new)?;
    println!("{}", diff.to_pretty());

    println!("\n=== With Configuration (Masking + Float Tolerance) ===\n");
    let config = DiffConfig::new()
        .mask("*.password")
        .mask("*.api_key")
        .float_tolerance("metrics.*", 0.01); // Tolerate 1% difference

    let diff = diff_with(&old, &new, &config)?;
    println!("{}", diff.to_pretty());

    println!("\n=== Configuration Summary ===");
    println!("- Masked fields: password, api_key");
    println!("- Float tolerance: 0.01 for metrics.*");
    println!(
        "- cpu_usage changed by {:.6} (within tolerance)",
        (45.200001_f64 - 45.2_f64).abs()
    );
    println!("- Changes detected: {}", diff.len());

    Ok(())
}