Expand description
§cor
A compile-time Chain of Responsibility pattern library for Rust.
Handlers are composed into statically-typed chains with zero dynamic dispatch overhead in the chain structure. Each handler either processes a request or forwards it to the next handler.
§Quick start
use cor::{Handler, NilHandler, chain, append_chain, handler};
#[derive(Clone)]
struct LogRequest {
level: LogLevel,
message: String,
}
#[derive(Clone, PartialEq)]
enum LogLevel {
Info,
Warning,
Error,
Log
}
#[handler]
struct InfoHandler<T> {}
impl<N: Handler<LogRequest>> Handler<LogRequest> for InfoHandler<LogRequest, N> {
fn handle(&self, request: LogRequest) {
if request.level == LogLevel::Info {
println!("[INFO] {}", request.message);
} else {
self.next.handle(request);
}
}
}
#[handler]
struct WarningHandler<T> {}
impl<N: Handler<LogRequest>> Handler<LogRequest> for WarningHandler<LogRequest, N> {
fn handle(&self, request: LogRequest) {
if request.level == LogLevel::Warning {
println!("[WARN] {}", request.message);
} else {
self.next.handle(request);
}
}
}
#[handler]
struct ErrorHandler<T> {}
impl<N: Handler<LogRequest>> Handler<LogRequest> for ErrorHandler<LogRequest, N>
{
fn handle(&self, request: LogRequest) {
if request.level == LogLevel::Error {
println!("[ERROR] {}", request.message);
} else {
self.next.handle(request);
}
}
}
#[handler]
struct LogHandler<T> {}
impl<N: Handler<LogRequest>> Handler<LogRequest> for LogHandler<LogRequest, N> {
fn handle(&self, request: LogRequest) {
if request.level == LogLevel::Log {
println!("[LOG] {}", request.message);
} else {
self.next.handle(request);
}
}
}
let base_handler = NilHandler::new();
let logger = chain![InfoHandler, WarningHandler, ErrorHandler];
logger.handle(LogRequest {
level: LogLevel::Info,
message: "Server started on port 8080".into(),
});
let extended_chain = append_chain![LogHandler; logger];
extended_chain.handle(LogRequest {
level: LogLevel::Log,
message: "Server started on port 8080".into(),
});§How it works
The #[handler] attribute macro generates a struct with a
next field and a new(next) constructor. You provide the routing logic by
writing your own Handler<T> implementation.
The chain! macro composes handler types right-to-left, terminating with a
base_handler variable (typically a NilHandler) that the caller brings
into scope. Each entry is a handler type whose new takes the next handler
as its final argument, producing a fully nested type at compile time.
Macros§
- append_
chain - chain
- Compose handler types into a nested chain.
Structs§
- Base
Handler - A pass-through handler that forwards every request to the next handler.
- NilHandler
- A terminal handler that discards any request it receives.
Traits§
Attribute Macros§
- handler
- Generate the scaffolding for a chain-of-responsibility handler struct.