Add root-default endpoint creation macro

This commit is contained in:
Michael Mikovsky
2026-04-26 15:36:45 -06:00
parent f16be8d64a
commit 99d1097f2a
6 changed files with 122 additions and 14 deletions
@@ -135,6 +135,7 @@ impl ProtocolEndpoint {
.collect::<Vec<_>>();
Self {
local_id: None,
routing: CompiledRoutes::new(&path, &registered_child_paths, parent_path.is_some()),
path,
children,
@@ -147,6 +148,52 @@ impl ProtocolEndpoint {
}
}
#[must_use]
/// Creates a root-assumed endpoint with one local identifier and predeclared leaves.
///
/// What it is: a convenience constructor for the common bootstrap state where an endpoint has
/// one local name but has not yet been assigned a non-root path by a parent connection.
///
/// Why it exists: endpoint creation should not require every caller to manually pass an empty
/// path, no parent, and no children just to host one or more known leaves.
///
/// # Example
/// ```rust
/// use unshell::protocol::tree::{LeafSpec, ProtocolEndpoint};
/// let endpoint = ProtocolEndpoint::root(
/// "worker",
/// vec![LeafSpec {
/// name: "service".into(),
/// procedures: vec!["example.service.v1.invoke".into()],
/// }],
/// );
/// assert!(endpoint.path().is_empty());
/// assert_eq!(endpoint.local_id(), Some("worker"));
/// ```
pub fn root(local_id: impl Into<String>, leaves: Vec<LeafSpec>) -> Self {
let mut endpoint = Self::new(Vec::new(), None, Vec::new(), leaves);
endpoint.local_id = Some(local_id.into());
endpoint
}
#[must_use]
/// Returns the endpoint's local bootstrap identifier, if one was assigned.
///
/// What it is: a lightweight label separate from the protocol path.
///
/// Why it exists: a freshly created endpoint may know its own local identity before a parent
/// connection assigns its final tree path.
///
/// # Example
/// ```rust
/// use unshell::protocol::tree::ProtocolEndpoint;
/// let endpoint = ProtocolEndpoint::root("worker", Vec::new());
/// assert_eq!(endpoint.local_id(), Some("worker"));
/// ```
pub fn local_id(&self) -> Option<&str> {
self.local_id.as_deref()
}
/// Registers a procedure that is handled directly by the endpoint.
///
/// Endpoint-level procedures exist for protocol services that are not attached to one leaf,
@@ -286,6 +286,7 @@ pub trait Endpoint {
/// ```
#[derive(Debug, Default)]
pub struct ProtocolEndpoint {
pub(crate) local_id: Option<String>,
pub(crate) path: Vec<String>,
pub(crate) children: Vec<ChildRoute>,
pub(crate) routing: CompiledRoutes,
@@ -92,6 +92,34 @@ pub trait LeafDeclaration: ProtocolLeaf {
}
}
/// Returns the canonical `LeafSpec` for one concrete leaf host value.
///
/// What it is: a tiny typed helper that uses a host value only for type inference.
///
/// Why it exists: endpoint-construction macros can accept ordinary host expressions like
/// `RemoteShell::default()` and still derive the compile-time `LeafSpec` without the caller
/// spelling the leaf type twice.
///
/// # Example
/// ```rust
/// use unshell::protocol::tree::{LeafDeclaration, ProtocolLeaf, leaf_spec_of};
/// struct ExampleLeaf;
/// impl ProtocolLeaf for ExampleLeaf {
/// fn leaf_name() -> String { "org.example.v1.echo".into() }
/// }
/// impl LeafDeclaration for ExampleLeaf {
/// fn procedure_suffixes() -> &'static [&'static str] { &["invoke"] }
/// }
/// let spec = leaf_spec_of(&ExampleLeaf);
/// assert_eq!(spec.name, "org.example.v1.echo");
/// ```
pub fn leaf_spec_of<L>(_: &L) -> LeafSpec
where
L: LeafDeclaration,
{
L::leaf_spec()
}
/// Declares that one host struct is bound to one compile-time leaf declaration.
///
/// What it is: a trait that links a concrete host type, such as an endpoint or
+3 -1
View File
@@ -24,7 +24,9 @@ pub use endpoint::{
ProtocolEndpoint,
};
pub use hook::{ActiveHook, HookConflict, HookKey, HookTable, PendingHook};
pub use leaf::{CallProcedures, LeafBinding, LeafDeclaration, ProtocolLeaf, derive_leaf_name};
pub use leaf::{
CallProcedures, LeafBinding, LeafDeclaration, ProtocolLeaf, derive_leaf_name, leaf_spec_of,
};
pub use procedure::{
Procedure, ProcedureEffect, ProcedureMetadata, ProcedureRuntime, ProcedureRuntimeError,
ProcedureRuntimeOutcome, ProcedureStore, StatefulProcedureMetadata,