#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Class {
Hot,
Deliberate,
}
impl Class {
#[must_use]
pub const fn word(self) -> &'static str {
match self {
Self::Hot => "hot",
Self::Deliberate => "deliberate",
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Route {
pub wire: &'static str,
pub kind: &'static str,
pub action: &'static str,
pub class: Class,
}
pub const ENVELOPES: &[&str] = &["hello", "session.pass", "query.check", "query.words"];
const fn hot(wire: &'static str, kind: &'static str, action: &'static str) -> Route {
Route {
wire,
kind,
action,
class: Class::Hot,
}
}
const fn deliberate(wire: &'static str, kind: &'static str, action: &'static str) -> Route {
Route {
wire,
kind,
action,
class: Class::Deliberate,
}
}
pub const ROUTES: &[Route] = &[
hot("branches.list", "database", "read"),
hot("collections.list", "database", "read"),
hot("documents.get", "collection", "read"),
hot("documents.list", "collection", "read"),
hot("history.list", "branch", "read"),
hot("head.follow", "branch", "read"),
hot("branch.review", "branch", "read"),
hot("branch.review_counts", "branch", "read"),
hot("branch.merge_prepare", "branch", "read"),
hot("branch.merge_dangling", "branch", "read"),
hot("mutation.receipt", "database", "read"),
deliberate("drafts.run", "database", "serve"),
hot("counts.rebuild", "branch", "write"),
hot("counts.audit", "branch", "read"),
hot("edge.out", "collection", "read"),
hot("edge.in", "collection", "read"),
hot("graph.export", "database", "read"),
hot("vectors.get", "collection", "read"),
hot("vectors.list", "collection", "read"),
hot("vectors.search", "collection", "query"),
hot("vectors.search_text", "collection", "query"),
hot("store.stats", "database", "read"),
hot("vectors.fields", "database", "read"),
hot("embed.rewalk_longer", "collection", "write"),
hot("relations.list", "database", "read"),
hot("query.run", "database", "query"),
hot("changes.list", "database", "read"),
hot("collection.put", "database", "write"),
hot("document.put", "collection", "write"),
hot("document.append_prune", "collection", "write"),
hot("document.delete", "collection", "write"),
deliberate("branch.fork", "database", "branch"),
deliberate("branch.discard", "database", "branch"),
deliberate("branch.merge", "branch", "merge"),
hot("mutation.apply", "branch", "write"),
hot("edge.put", "collection", "write"),
hot("edge.delete", "collection", "write"),
hot("index.declare", "collection", "write"),
hot("vector.declare", "collection", "write"),
hot("vector.put", "collection", "write"),
hot("vector.delete", "collection", "write"),
hot("documents.put_many", "collection", "write"),
hot("documents.delete_many", "collection", "write"),
hot("vectors.put_many", "collection", "write"),
hot("edges.put_many", "collection", "write"),
hot("relation.put", "database", "write"),
hot("relation.delete", "database", "write"),
];
#[must_use]
pub fn route(wire: &str) -> Option<&'static Route> {
ROUTES.iter().find(|route| route.wire == wire)
}
#[must_use]
pub fn render() -> String {
let mut out = String::from(
"# Haematite served route matrix\n\n\
Rendered from `crates/haematite-cli/src/serve/route_matrix.rs` and checked against it by\n\
`route_matrix_tests.rs`; edit the rows, never this file. A hot route is decided from\n\
the caller's Lys pass alone; a deliberate route asks Lys live and is refused \"Lys\n\
could not be asked\" when it cannot (PERMISSIONS-ACROSS-THE-STACK D2). `hello` and\n\
`session.pass` carry no resource. A mutation is decided by its change kind and, for\n\
a change to the branch's data, by `mutation.apply` on the branch it writes.\n\n\
| Route | Resource | Action | Class |\n\
| --- | --- | --- | --- |\n",
);
for route in ROUTES {
for cell in [
"| `",
route.wire,
"` | haematite.",
route.kind,
" | ",
route.action,
" | ",
route.class.word(),
" |\n",
] {
out.push_str(cell);
}
}
out
}
#[cfg(test)]
#[path = "route_matrix_tests.rs"]
mod tests;