<div align="center">
<img src="./logo.png" alt="Layered Logo" width="96">
# Layered
[](https://crates.io/crates/layered)
[](https://docs.rs/layered)
[](https://crates.io/crates/layered)
[](https://github.com/microsoft/oxidizer/actions/workflows/main.yml)
[](https://codecov.io/gh/microsoft/oxidizer)
[](../../LICENSE)
<a href="../.."><img src="../../logo.svg" alt="This crate was developed as part of the Oxidizer project" width="20"></a>
</div>
## Layered Services
Build composable async services with layered middleware.
This crate provides the [`Service`][__link0] trait and a layer system for adding cross-cutting
concerns like timeouts, retries, and logging.
### Why not Tower?
[Tower][__link1] predates `async fn` in traits, requiring manual `Future` types
or boxing and `poll_ready` back-pressure semantics. Tower’s `&mut self` also requires cloning
for concurrent requests. This crate uses `async fn` with `&self`, enabling simpler middleware
and natural concurrency. Tower interop is available via the `tower-service` feature.
### Quick Start
A [`Service`][__link2] transforms an input into an output asynchronously:
```rust
use layered::Service;
struct Greeter;
impl Service<String> for Greeter {
type Out = String;
async fn execute(&self, name: String) -> Self::Out {
format!("Hello, {name}!")
}
}
```
Use [`Execute`][__link3] to turn any async function into a service:
```rust
use layered::{Execute, Service};
});
assert_eq!(greeter.execute("World".into()).await, "Hello, World!");
```
### Key Concepts
* **Service**: An async function `In → Out` that processes inputs.
* **Middleware**: A service that wraps another service to add behavior (logging, timeouts, retries).
* **Layer**: A factory that wraps any service with middleware. Stack layers using tuples
like `(layer1, layer2, service)`.
### Layers and Middleware
A [`Layer`][__link4] wraps a service with additional behavior:
```rust
use layered::{Execute, Layer, Service, Stack};
// A simple logging layer
struct LogLayer;
impl<S> Layer<S> for LogLayer {
type Service = LogService<S>;
fn layer(&self, inner: S) -> Self::Service {
LogService(inner)
}
}
struct LogService<S>(S);
impl<S, In: Send + std::fmt::Display> Service<In> for LogService<S>
where
S: Service<In>,
{
type Out = S::Out;
async fn execute(&self, input: In) -> Self::Out {
println!("Input: {input}");
self.0.execute(input).await
}
}
// Stack layers with the service (layers apply outer to inner)
let service = (
LogLayer,
Execute::new(|x: i32| async move { x * 2 }),
).build();
let result = service.execute(21).await;
```
### Thread Safety
All services must implement [`Send`][__link5] and [`Sync`][__link6], and returned futures must be [`Send`][__link7].
This ensures compatibility with multi-threaded async runtimes like Tokio.
### Features
* **`intercept`**: Enables [`Intercept`][__link8] middleware
* **`dynamic-service`**: Enables [`DynamicService`][__link9] for type erasure
* **`tower-service`**: Enables Tower interoperability via the [`tower`][__link10] module
<hr/>
<sub>
This crate was developed as part of <a href="../..">The Oxidizer Project</a>. Browse this crate's <a href="https://github.com/microsoft/oxidizer/tree/main/crates/layered">source code</a>.
</sub>
[__cargo_doc2readme_dependencies_info]: ggGkYW0CYXSEGy4k8ldDFPOhG2VNeXtD5nnKG6EPY6OfW5wBG8g18NOFNdxpYXKEGzJtJrZVyApYG61Etog82u5CG8YRisc2odPYG-_MVLrG5Ab5YWSBgmdsYXllcmVkZTAuMi4w
[__link0]: https://docs.rs/layered/0.2.0/layered/?search=Service
[__link1]: https://docs.rs/tower
[__link10]: https://docs.rs/layered/0.2.0/layered/tower/index.html
[__link2]: https://docs.rs/layered/0.2.0/layered/?search=Service
[__link3]: https://docs.rs/layered/0.2.0/layered/?search=Execute
[__link4]: https://docs.rs/layered/0.2.0/layered/?search=Layer
[__link5]: https://doc.rust-lang.org/stable/std/marker/trait.Send.html
[__link6]: https://doc.rust-lang.org/stable/std/marker/trait.Sync.html
[__link7]: https://doc.rust-lang.org/stable/std/marker/trait.Send.html
[__link8]: https://docs.rs/layered/0.2.0/layered/?search=Intercept
[__link9]: https://docs.rs/layered/0.2.0/layered/?search=DynamicService