From 370c4f0e5fdace73a6dc9dddb6a50287d9c0ea5b Mon Sep 17 00:00:00 2001 From: huncholane Date: Sat, 14 Mar 2026 14:41:39 -0700 Subject: [PATCH] docs: add readmes to the examples --- examples/async_source/README.md | 22 ++++++++++++++ examples/custom_file_format/README.md | 27 ++++++++++++++++ examples/custom_str_format/README.md | 22 ++++++++++++++ examples/env-list/README.md | 22 ++++++++++++++ examples/glob/README.md | 27 ++++++++++++++++ examples/hierarchical-env/README.md | 44 +++++++++++++++++++++++++++ examples/simple/README.md | 31 +++++++++++++++++++ examples/watch/README.md | 34 +++++++++++++++++++++ 8 files changed, 229 insertions(+) create mode 100644 examples/async_source/README.md create mode 100644 examples/custom_file_format/README.md create mode 100644 examples/custom_str_format/README.md create mode 100644 examples/env-list/README.md create mode 100644 examples/glob/README.md create mode 100644 examples/hierarchical-env/README.md create mode 100644 examples/simple/README.md create mode 100644 examples/watch/README.md diff --git a/examples/async_source/README.md b/examples/async_source/README.md new file mode 100644 index 00000000..3d909fc6 --- /dev/null +++ b/examples/async_source/README.md @@ -0,0 +1,22 @@ +# Async Source + +Demonstrates loading configuration from an async source — in this case, an HTTP endpoint. + +## Usage + +```sh +cargo run --example async_source --features="json async" +``` + +## How it works + +1. Starts a local HTTP server on `localhost:5001` that serves JSON configuration +2. Implements the `AsyncSource` trait with a custom `HttpSource` struct +3. The client waits 3 seconds for the server to start, then fetches configuration via HTTP +4. Parses the JSON response into a `Config` using a custom `Format` implementation + +## Key concepts + +- **`AsyncSource` trait** — defines how to asynchronously collect configuration values +- **Custom `Format`** — parses the HTTP response body into config values +- Uses `warp` for the server and `reqwest` for the client diff --git a/examples/custom_file_format/README.md b/examples/custom_file_format/README.md new file mode 100644 index 00000000..52aef0a5 --- /dev/null +++ b/examples/custom_file_format/README.md @@ -0,0 +1,27 @@ +# Custom File Format + +Shows how to implement a custom file format for config-rs by parsing PEM certificate files. + +## Usage + +```sh +cargo run --example custom_file_format +``` + +## How it works + +1. Implements the `Format` and `FileStoredFormat` traits for a custom `Pem` format +2. The parser scans PEM file contents for "PUBLIC" or "PRIVATE" keywords to determine the key type +3. Loads `files/public.pem` and `files/private.pem` as optional configuration sources +4. Deserializes into a `Settings` struct with `public_key` and `private_key` fields + +## Key concepts + +- **`Format` trait** — defines how to parse raw file contents into configuration values +- **`FileStoredFormat` trait** — associates file extensions with the format so files can be auto-detected +- **Optional sources** — using `.required(false)` so the app doesn't fail if a file is missing + +## Files + +- `files/public.pem` — RSA public key +- `files/private.pem` — RSA private key diff --git a/examples/custom_str_format/README.md b/examples/custom_str_format/README.md new file mode 100644 index 00000000..cd076c22 --- /dev/null +++ b/examples/custom_str_format/README.md @@ -0,0 +1,22 @@ +# Custom String Format + +Shows how to implement a custom format for parsing configuration from an in-memory string rather than a file. + +## Usage + +```sh +cargo run --example custom_str_format +``` + +## How it works + +1. Implements the `Format` and `FileStoredFormat` traits for a custom `MyFormat` +2. The parser only recognizes the string `"good"` as valid configuration, producing a single key-value pair +3. Uses `File::from_str()` to load configuration from a string literal instead of a file path +4. Demonstrates error handling — a warning is printed for unrecognized input + +## Key concepts + +- **`File::from_str()`** — load configuration from a string rather than the filesystem +- **Custom parsing logic** — the `Format` trait can implement arbitrary parsing +- **Error handling** — gracefully handle malformed configuration data diff --git a/examples/env-list/README.md b/examples/env-list/README.md new file mode 100644 index 00000000..8fdddde5 --- /dev/null +++ b/examples/env-list/README.md @@ -0,0 +1,22 @@ +# Environment Variable Lists + +Demonstrates parsing space-separated environment variables into a `Vec`. + +## Usage + +```sh +APP_LIST="Hello World" cargo run --example env-list +``` + +## How it works + +1. Sets up an `Environment` source with the `APP` prefix +2. Enables `try_parsing(true)` so values are parsed beyond plain strings +3. Configures `list_separator(" ")` to split values on spaces +4. Deserializes into an `AppConfig` struct with a `list: Vec` field + +## Key concepts + +- **`list_separator()`** — defines the delimiter for splitting environment variable values into lists +- **`try_parsing()`** — enables automatic type parsing of environment variable values +- **`separator()`** — maps underscores in env var names to nested config keys diff --git a/examples/glob/README.md b/examples/glob/README.md new file mode 100644 index 00000000..071cc813 --- /dev/null +++ b/examples/glob/README.md @@ -0,0 +1,27 @@ +# Glob + +Demonstrates three approaches to loading and merging multiple configuration files. + +## Usage + +```sh +cargo run --example glob +``` + +## How it works + +Three strategies are shown for combining files from `conf/`: + +1. **Individual calls** — add each file one at a time with `add_source()` +2. **Vector of files** — pass a `Vec` as a single source +3. **Glob pattern** — use the `glob` crate to match `conf/*` and collect files dynamically + +All three produce the same merged `HashMap`. Files are merged in order, with later files overriding earlier ones. + +## Configuration files + +- `conf/00-default.toml` — base defaults +- `conf/05-some.yml` — YAML overrides +- `conf/99-extra.json` — final JSON overrides + +The numeric prefixes control load order and therefore priority. diff --git a/examples/hierarchical-env/README.md b/examples/hierarchical-env/README.md new file mode 100644 index 00000000..718e0863 --- /dev/null +++ b/examples/hierarchical-env/README.md @@ -0,0 +1,44 @@ +# Hierarchical Environment + +A real-world pattern for layered configuration with environment-specific overrides. + +## Usage + +```sh +# Development mode (default) +cargo run --example hierarchical-env + +# Production mode +RUN_MODE=production cargo run --example hierarchical-env + +# Override individual values +APP_DEBUG=false cargo run --example hierarchical-env +``` + +## How it works + +Configuration is loaded in layers, with each layer overriding the previous: + +1. `config/default.toml` — base configuration shared across all environments +2. `config/{RUN_MODE}.toml` — environment-specific overrides (e.g., `development.toml`, `production.toml`) +3. `config/local.toml` — optional local overrides (not checked into version control) +4. Environment variables with `APP_` prefix — runtime overrides +5. Programmatic overrides — hardcoded values set in code + +## Configuration structure + +```rust +struct Settings { + debug: bool, + database: Database, // url + sparkpost: Sparkpost, // key, token, url, version + twitter: Twitter, // consumer_token, consumer_secret + braintree: Braintree, // merchant_id, public_key, private_key +} +``` + +## Key concepts + +- **Layered configuration** — build up settings from multiple sources with clear priority +- **Environment-specific files** — different defaults for development vs. production +- **Local overrides** — developer-specific settings that aren't committed to the repo diff --git a/examples/simple/README.md b/examples/simple/README.md new file mode 100644 index 00000000..204514ad --- /dev/null +++ b/examples/simple/README.md @@ -0,0 +1,31 @@ +# Simple + +A minimal example showing how to load configuration from a file and environment variables. + +## Usage + +```sh +cargo run --example simple +``` + +Override values with environment variables: + +```sh +APP_DEBUG=true APP_KEY="new-key" cargo run --example simple +``` + +## How it works + +1. Loads `Settings.toml` as the base configuration +2. Overlays any environment variables prefixed with `APP_` +3. Deserializes the result into a `HashMap` + +## Configuration + +**Settings.toml:** + +```toml +debug = false +priority = 32 +key = "189rjfadoisfj8923fjio" +``` diff --git a/examples/watch/README.md b/examples/watch/README.md new file mode 100644 index 00000000..acdf5ed3 --- /dev/null +++ b/examples/watch/README.md @@ -0,0 +1,34 @@ +# Watch + +Demonstrates hot-reloading configuration when a file changes on disk. + +## Usage + +```sh +cargo run --example watch +``` + +Then edit `examples/watch/Settings.toml` in another terminal — the running process will detect the change and reload automatically. + +## How it works + +1. Loads initial configuration from `Settings.toml` into a static `RwLock` +2. Uses the `notify` crate to watch the file for modifications (polling every 2 seconds) +3. On file change events, re-reads the configuration and updates the shared state +4. The main loop continuously prints current settings to the terminal + +## Configuration + +**Settings.toml:** + +```toml +debug = false +port = 3223 +host = "0.0.0.0" +``` + +## Key concepts + +- **`RwLock`** — thread-safe shared configuration that can be read concurrently +- **`notify` crate** — cross-platform filesystem event watching +- **Hot-reload pattern** — update configuration without restarting the application