# rtb-assets
> Part of the [phpboyscout Rust toolkit](https://rust.phpboyscout.uk) —
> small, framework-free crates extracted from
> [rust-tool-base](https://gitlab.com/phpboyscout/rust-tool-base).
Embedded-asset + overlay filesystem abstraction. Unifies compile-time
embedded assets (`rust-embed`), physical directories, and in-memory
fixtures behind one read-only API — last-wins shadowing for blobs,
RFC-7396 deep merge for YAML/JSON, and lexical path-traversal rejection.
```rust
use rtb_assets::Assets;
use std::collections::HashMap;
let assets = Assets::builder()
.memory(
"defaults",
HashMap::from([("greeting.txt".into(), b"hello".to_vec())]),
)
.build();
assert_eq!(assets.open_text("greeting.txt").unwrap(), "hello");
```
- **Docs:** <https://assets.rust.phpboyscout.uk>
- **API reference:** <https://docs.rs/rtb-assets>
- **Crate:** <https://crates.io/crates/rtb-assets>
## Documentation
| [Ship defaults a user can override](https://assets.rust.phpboyscout.uk/tutorials/ship-defaults-a-user-can-override/) | tutorial — from `cargo new` to a working overlay |
| [Merge layered configuration](https://assets.rust.phpboyscout.uk/how-to/merge-layered-configuration/) | how-to — and how to shape a schema that merges well |
| [Diagnose a failed asset lookup](https://assets.rust.phpboyscout.uk/how-to/diagnose-a-failed-asset-lookup/) | how-to — why a read returned nothing |
| [Merge semantics](https://assets.rust.phpboyscout.uk/reference/merge-semantics/) | reference — what merges, what replaces, what deletes |
| [What rtb-assets does not do](https://assets.rust.phpboyscout.uk/explanation/limitations/) | explanation — the deliberate absences, read before adopting |
## Development
`just ci` runs the full local gate (fmt, clippy, nextest, doc, deny).
Tests include a cucumber BDD suite (`tests/bdd.rs`). Releases are cut by
release-plz from Conventional Commits — do not tag manually.
## License
MIT