Add crossbeam channel router leaf example

This commit is contained in:
Michael Mikovsky
2026-04-29 22:14:04 -06:00
parent 371f3ae492
commit 71b311065d
12 changed files with 969 additions and 31 deletions
+1 -2
View File
@@ -276,8 +276,7 @@ fn generated_call_procedure_can_query_and_mutate_endpoint_topology() {
.send_call(
path(&["agent"]),
Some(TopologyLeaf::protocol_leaf_name()),
TopologyLeaf::protocol_procedure_id("remove_child")
.expect("suffix should resolve"),
TopologyLeaf::protocol_procedure_id("remove_child").expect("suffix should resolve"),
Some(remove_hook),
encode_call_reply(&ChildRequest {
child_path: path(&["agent", "child"]),
+5 -4
View File
@@ -9,11 +9,11 @@ use crate::protocol::{
CallMessage, DataMessage, FrameBytes, FrameError, HookTarget, PacketHeader, ProtocolFault,
};
use super::endpoint::ForwardedFrame;
use super::{
Endpoint, EndpointError, HookKey, Ingress, LocalEvent, ProtocolEndpoint, ProtocolLeaf,
RouteDecision, RouterLeaf,
};
use super::endpoint::ForwardedFrame;
/// One typed incoming `Call` passed to a leaf procedure.
///
@@ -665,9 +665,10 @@ where
packet.data,
packet.end_hook,
)?;
runtime
.forwarded
.extend(self.process_endpoint_outcome_routed(endpoint_outcome)?.forwarded);
runtime.forwarded.extend(
self.process_endpoint_outcome_routed(endpoint_outcome)?
.forwarded,
);
}
Ok(runtime)
}
@@ -281,7 +281,11 @@ impl ProtocolEndpoint {
/// ```
pub fn upsert_child_route(&mut self, route: ChildRoute) -> Result<(), EndpointError> {
self.validate_direct_child_path(&route.path)?;
if let Some(existing) = self.children.iter_mut().find(|child| child.path == route.path) {
if let Some(existing) = self
.children
.iter_mut()
.find(|child| child.path == route.path)
{
*existing = route;
} else {
self.children.push(route);
@@ -371,23 +375,27 @@ impl ProtocolEndpoint {
fn validate_direct_parent_path(&self, parent_path: &[String]) -> Result<(), EndpointError> {
let Some((_, expected_parent)) = self.path.split_last() else {
return Err(EndpointError::Validation(ValidationError::TopologyInvariant(
"root endpoints cannot declare a parent path",
)));
return Err(EndpointError::Validation(
ValidationError::TopologyInvariant("root endpoints cannot declare a parent path"),
));
};
if parent_path != expected_parent {
return Err(EndpointError::Validation(ValidationError::TopologyInvariant(
"parent path must equal the direct path prefix of this endpoint",
)));
return Err(EndpointError::Validation(
ValidationError::TopologyInvariant(
"parent path must equal the direct path prefix of this endpoint",
),
));
}
Ok(())
}
fn validate_direct_child_path(&self, child_path: &[String]) -> Result<(), EndpointError> {
if child_path.len() != self.path.len() + 1 || !child_path.starts_with(&self.path) {
return Err(EndpointError::Validation(ValidationError::TopologyInvariant(
"child path must be one direct descendant of this endpoint",
)));
return Err(EndpointError::Validation(
ValidationError::TopologyInvariant(
"child path must be one direct descendant of this endpoint",
),
));
}
Ok(())
}
@@ -11,6 +11,6 @@ mod introspection;
mod receive;
pub use core::{
ChildRoute, Endpoint, EndpointError, EndpointOutcome, ForwardedFrame, Ingress, LeafSpec, LocalEvent,
ProtocolEndpoint,
ChildRoute, Endpoint, EndpointError, EndpointOutcome, ForwardedFrame, Ingress, LeafSpec,
LocalEvent, ProtocolEndpoint,
};
+7 -7
View File
@@ -190,13 +190,13 @@ pub trait CallProcedures: LeafDeclaration {
/// use unshell::protocol::tree::{CallProcedures, DispatchError, IncomingCall, ProtocolLeaf};
/// struct ExampleLeaf;
/// impl ProtocolLeaf for ExampleLeaf { fn leaf_name() -> String { "org.example.v1.echo".into() } }
/// impl CallProcedures for ExampleLeaf {
/// type Error = core::convert::Infallible;
/// fn procedure_suffixes() -> &'static [&'static str] { &["invoke"] }
/// fn dispatch_call(&mut self, _endpoint: &mut unshell::protocol::tree::ProtocolEndpoint, _call: IncomingCall) -> Result<unshell::protocol::tree::CallReply, DispatchError<Self::Error>> {
/// Ok(unshell::protocol::tree::CallReply::NoReply)
/// }
/// }
/// impl CallProcedures for ExampleLeaf {
/// type Error = core::convert::Infallible;
/// fn procedure_suffixes() -> &'static [&'static str] { &["invoke"] }
/// fn dispatch_call(&mut self, _endpoint: &mut unshell::protocol::tree::ProtocolEndpoint, _call: IncomingCall) -> Result<unshell::protocol::tree::CallReply, DispatchError<Self::Error>> {
/// Ok(unshell::protocol::tree::CallReply::NoReply)
/// }
/// }
/// # let _ = ExampleLeaf;
/// ```
fn dispatch_call(