Small boundary traits for hexagonal architecture in Rust.
Handle<I>: immutable/read-style interaction boundary.HandleMut<I>: mutable/write-style interaction boundary.- Optional async equivalents in
hexkit::r#asyncbehind feature flagasync.
You define your own interaction input/output types and adapters.
use hexkit::{Handle, HandleMut};
struct CreateUser {
name: String,
}
struct ReadUser {
id: u64,
}
#[derive(Default)]
struct UserCore {
next_id: u64,
rows: Vec<(u64, String)>,
}
impl HandleMut<CreateUser> for UserCore {
type Output<'a> = u64;
fn handle_mut(&mut self, input: CreateUser) -> Self::Output<'_> {
self.next_id += 1;
self.rows.push((self.next_id, input.name));
self.next_id
}
}
impl Handle<ReadUser> for UserCore {
type Output<'a> = Option<&'a str>;
fn handle(&self, input: ReadUser) -> Self::Output<'_> {
self.rows
.iter()
.find(|(id, _)| *id == input.id)
.map(|(_, name)| name.as_str())
}
}
fn main() {
let mut core = UserCore::default();
let id = core.handle_mut(CreateUser { name: String::from("lea") });
let name = core.handle(ReadUser { id }).expect("user should exist");
assert_eq!(name, "lea");
}Enable the feature:
[dependencies]
hexkit = { version = "0.1", features = ["async"] }Use:
use hexkit::r#async::{Handle, HandleMut};See examples/README.md for an example map.
Quick start commands:
cargo run --example sync_basic_in_memorycargo run --example canonical_app_skeletoncargo run --example async_basic_email_flow --features async