cfgmatic-source 2.2.0

Configuration sources (file, env, remote) for cfgmatic framework
Documentation
//! Basic example for cfgmatic-source.
//!
//! Demonstrates loading configuration from files, environment variables,
//! and memory sources.

use cfgmatic_source::prelude::*;
use serde::Deserialize;

/// Application configuration structure.
#[derive(Debug, Deserialize)]
struct AppConfig {
    server: ServerConfig,
    database: DatabaseConfig,
}

#[derive(Debug, Deserialize)]
struct ServerConfig {
    host: String,
    port: u16,
}

#[derive(Debug, Deserialize)]
struct DatabaseConfig {
    url: String,
    max_connections: u32,
}

fn main() -> Result<()> {
    println!("=== cfgmatic-source Basic Example ===\n");

    // Example 1: Load from memory (for testing)
    memory_source_example()?;

    // Example 2: Load from environment variables
    env_source_example()?;

    // Example 3: Combine multiple sources
    composite_source_example()?;

    println!("\nAll examples completed successfully!");
    Ok(())
}

/// Demonstrates using MemorySource for testing.
fn memory_source_example() -> Result<()> {
    println!("--- Memory Source Example ---");

    let json_config = serde_json::json!({
        "server": {
            "host": "localhost",
            "port": 8080
        },
        "database": {
            "url": "postgres://localhost/mydb",
            "max_connections": 10
        }
    });

    let source = MemorySource::from_json(json_config);
    let loader = Loader::new();

    let config: AppConfig = loader.load_as(&source)?;
    println!("Loaded from memory: {:?}", config);
    println!("Server: {}:{}", config.server.host, config.server.port);

    Ok(())
}

/// Demonstrates using EnvSource for environment variables.
fn env_source_example() -> Result<()> {
    println!("\n--- Environment Source Example ---");

    // Note: This example shows how to use EnvSource.
    // In a real application, you would set actual environment variables.
    let source = EnvSource::builder().prefix("MYAPP").required(false).build();

    let metadata = source.metadata();
    println!(
        "Source: {} (priority: {})",
        metadata.name, metadata.priority
    );
    println!("Format: {:?}", source.detect_format());

    // Try to load (will be empty if no MYAPP_* env vars are set)
    match source.load_raw() {
        Ok(content) if !content.is_empty() => {
            println!("Loaded from environment: {} bytes", content.len());
        }
        _ => {
            println!("No environment variables with MYAPP_ prefix found.");
            println!("Set MYAPP_SERVER_HOST, MYAPP_SERVER_PORT, etc. to test.");
        }
    }

    Ok(())
}

/// Demonstrates combining multiple sources with priorities.
fn composite_source_example() -> Result<()> {
    println!("\n--- Composite Source Example ---");

    // Base configuration (lowest priority)
    let base_config = serde_json::json!({
        "server": {
            "host": "0.0.0.0",
            "port": 3000
        },
        "database": {
            "url": "postgres://localhost/default",
            "max_connections": 5
        }
    });

    // Override configuration (higher priority)
    let override_config = serde_json::json!({
        "server": {
            "port": 8080
        },
        "database": {
            "max_connections": 20
        }
    });

    let base = MemorySource::from_json(base_config);
    let override_src = MemorySource::from_json(override_config);

    let composite = CompositeSource::builder()
        .add_with_priority(base, SourcePriority::new(1)) // Lower priority
        .add_with_priority(override_src, SourcePriority::new(10)) // Higher priority
        .build();

    let loader = Loader::new();
    let config: AppConfig = loader.load_as(&composite)?;

    println!("Merged configuration:");
    println!("  Server: {}:{}", config.server.host, config.server.port);
    println!(
        "  Database: {} (max: {})",
        config.database.url, config.database.max_connections
    );
    println!("  Note: port and max_connections came from override");

    Ok(())
}