zonfig 0.1.0

A small dynamic configuration loader with file watching and hot reload support.
Documentation
# zonfig

`zonfig` loads JSON, YAML, and TOML config files into Serde types, then keeps a watched config handle up to date while the process is running.

## Features

- JSON, YAML, and TOML support.
- Extension-based format detection, with an explicit format override when needed.
- A cloneable `Config<T>` handle that works well in HTTP application state.
- Hot reload hooks for successful updates and reload errors.
- A cooldown window to avoid repeated reloads during save bursts.

## Load Once

```rust
use serde::Deserialize;

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

fn main() -> Result<(), zonfig::Error> {
    let config: AppConfig = zonfig::load("config.toml")?;

    println!("{}:{}", config.host, config.port);
    Ok(())
}
```

## Watch And Reload

```rust
use serde::Deserialize;

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

#[tokio::main]
async fn main() -> Result<(), zonfig::Error> {
    let config = zonfig::watch::<AppConfig>("config.toml").await?;

    config.with(|current| {
        println!("current config: {}:{}", current.host, current.port);
    });

    config.on_change(|config| {
        println!("config changed: {}:{}", config.host, config.port);
    });

    config.on_error(|error| {
        eprintln!("config reload failed: {error}");
    });

    Ok(())
}
```

`Config<T>` is cheap to clone. Store it in application state and call `with` or `get` whenever a handler needs the current value.

For example:

```rust
#[derive(Clone)]
struct AppState {
    config: zonfig::Config<AppConfig>,
}
```

Set a reload cooldown:

```rust
let config = zonfig::watch_with_options::<AppConfig>(
    "config.toml",
    zonfig::WatchOptions::default()
        .with_cooldown(std::time::Duration::from_millis(500)),
)
.await?;
```

## Notes

- Reads use `ArcSwap`, so `get` returns an `Arc<T>` snapshot without cloning the config.
- A failed reload keeps the last valid config.
- The watcher stays alive until all `Config<T>` handles are dropped.
- This crate intentionally focuses on local files. It does not merge multiple files, read remote config stores, or write config files back to disk.