Skip to main content

Crate cor

Crate cor 

Source
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§

BaseHandler
A pass-through handler that forwards every request to the next handler.
NilHandler
A terminal handler that discards any request it receives.

Traits§

Handler
The core trait for all handlers in the chain.
Linker

Attribute Macros§

handler
Generate the scaffolding for a chain-of-responsibility handler struct.

Derive Macros§

Handler
Derive a pass-through Handler implementation that forwards every request to self.next.