mirror of
https://github.com/Astatin3/unshell.git
synced 2026-06-08 22:38:01 -06:00
Remove the old leaf declaration path
Delete the deprecated Leaf derive path, migrate the remaining tests and example to leaf!, and add direct coverage for endpoint-only, TUI-only, and shared-host leaf declarations.
This commit is contained in:
@@ -17,4 +17,4 @@ pub mod protocol;
|
||||
pub use protocol::*;
|
||||
|
||||
#[cfg(test)]
|
||||
pub use unshell_macros::{Leaf, Procedure, procedures};
|
||||
pub use unshell_macros::{Procedure, leaf, procedures};
|
||||
|
||||
@@ -8,18 +8,22 @@ use crate::protocol::tree::{
|
||||
decode_call_input, encode_call_reply,
|
||||
};
|
||||
use crate::protocol::{PacketType, decode_frame};
|
||||
use crate::{Leaf, procedures};
|
||||
use crate::{leaf, procedures};
|
||||
|
||||
fn path(parts: &[&str]) -> Vec<String> {
|
||||
parts.iter().map(|part| (*part).to_owned()).collect()
|
||||
}
|
||||
|
||||
#[derive(Leaf)]
|
||||
#[leaf(id = "org.example.v1.echo")]
|
||||
struct EchoLeaf {
|
||||
prefix: String,
|
||||
}
|
||||
|
||||
leaf! {
|
||||
id = "org.example.v1.echo",
|
||||
endpoint_struct = EchoLeaf,
|
||||
procedures = ["echo"],
|
||||
}
|
||||
|
||||
#[derive(Archive, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
struct EchoRequest {
|
||||
text: String,
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
use alloc::{string::String, vec};
|
||||
|
||||
use crate::leaf;
|
||||
use crate::protocol::tree::{LeafBinding, LeafDeclaration, ProcedureMetadata, ProtocolLeaf};
|
||||
|
||||
struct EndpointHost;
|
||||
struct Open;
|
||||
struct Reset;
|
||||
|
||||
impl ProcedureMetadata for Open {
|
||||
type Leaf = EndpointHost;
|
||||
const PROCEDURE_SUFFIX: &'static str = "open";
|
||||
}
|
||||
|
||||
impl ProcedureMetadata for Reset {
|
||||
type Leaf = EndpointHost;
|
||||
const PROCEDURE_SUFFIX: &'static str = "reset";
|
||||
}
|
||||
|
||||
leaf! {
|
||||
id = "org.example.v1.demo",
|
||||
procedures = [Open, Reset],
|
||||
endpoint_struct = EndpointHost,
|
||||
}
|
||||
|
||||
struct EndpointHalf;
|
||||
struct TuiHalf;
|
||||
struct Connect;
|
||||
|
||||
impl ProcedureMetadata for Connect {
|
||||
type Leaf = EndpointHalf;
|
||||
const PROCEDURE_SUFFIX: &'static str = "connect";
|
||||
}
|
||||
|
||||
leaf! {
|
||||
name = "chat",
|
||||
org = "org",
|
||||
product = "example",
|
||||
version = "v2",
|
||||
procedures = [Connect],
|
||||
endpoint_struct = EndpointHalf,
|
||||
tui_struct = TuiHalf,
|
||||
}
|
||||
|
||||
struct TuiOnly;
|
||||
struct Tail;
|
||||
|
||||
impl ProcedureMetadata for Tail {
|
||||
type Leaf = TuiOnly;
|
||||
const PROCEDURE_SUFFIX: &'static str = "tail";
|
||||
}
|
||||
|
||||
leaf! {
|
||||
id = "org.example.v1.transcript",
|
||||
procedures = [Tail],
|
||||
tui_struct = TuiOnly,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn leaf_declaration_generates_endpoint_host_metadata() {
|
||||
assert_eq!(EndpointHost::protocol_leaf_name(), "org.example.v1.demo");
|
||||
assert_eq!(
|
||||
EndpointHost::protocol_leaf_spec().procedures,
|
||||
vec![
|
||||
String::from("org.example.v1.demo.open"),
|
||||
String::from("org.example.v1.demo.reset"),
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
<EndpointHost as LeafBinding>::Declaration::leaf_name(),
|
||||
"org.example.v1.demo"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn leaf_declaration_shares_metadata_between_endpoint_and_tui_hosts() {
|
||||
assert_eq!(
|
||||
EndpointHalf::protocol_leaf_name(),
|
||||
TuiHalf::protocol_leaf_name()
|
||||
);
|
||||
assert_eq!(
|
||||
EndpointHalf::protocol_leaf_spec().procedures,
|
||||
TuiHalf::protocol_leaf_spec().procedures
|
||||
);
|
||||
assert_eq!(
|
||||
<EndpointHalf as LeafBinding>::Declaration::procedure_id("connect"),
|
||||
Some(String::from("org.example.v2.chat.connect"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn leaf_declaration_supports_tui_only_hosts() {
|
||||
assert_eq!(TuiOnly::protocol_leaf_name(), "org.example.v1.transcript");
|
||||
assert_eq!(
|
||||
<TuiOnly as LeafDeclaration>::procedure_id("tail"),
|
||||
Some(String::from("org.example.v1.transcript.tail"))
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
mod call;
|
||||
mod leaf_decl;
|
||||
mod procedure;
|
||||
mod protocol;
|
||||
mod tree;
|
||||
|
||||
@@ -6,18 +6,23 @@ use crate::protocol::tree::{
|
||||
ProcedureEffect, ProcedureRuntime, ProcedureStore, ProtocolEndpoint, encode_call_reply,
|
||||
};
|
||||
use crate::protocol::{PacketType, decode_frame};
|
||||
use crate::{Leaf, Procedure};
|
||||
use crate::{Procedure, leaf};
|
||||
|
||||
fn path(parts: &[&str]) -> Vec<String> {
|
||||
parts.iter().map(|part| (*part).to_owned()).collect()
|
||||
}
|
||||
|
||||
#[derive(Default, Leaf)]
|
||||
#[leaf(id = "org.example.v1.stream")]
|
||||
#[derive(Default)]
|
||||
struct StreamLeaf {
|
||||
sessions: BTreeMap<HookKey, ProcedureOpen>,
|
||||
}
|
||||
|
||||
leaf! {
|
||||
id = "org.example.v1.stream",
|
||||
procedures = [ProcedureOpen],
|
||||
endpoint_struct = StreamLeaf,
|
||||
}
|
||||
|
||||
impl ProcedureStore<ProcedureOpen> for StreamLeaf {
|
||||
fn procedure_sessions(&mut self) -> &mut BTreeMap<HookKey, ProcedureOpen> {
|
||||
&mut self.sessions
|
||||
@@ -67,10 +72,7 @@ fn procedure_runtime_routes_data_to_stored_session() {
|
||||
path(&["agent"]),
|
||||
Some(Vec::new()),
|
||||
Vec::new(),
|
||||
vec![crate::protocol::tree::LeafSpec {
|
||||
name: StreamLeaf::protocol_leaf_name(),
|
||||
procedures: vec![ProcedureOpen::protocol_procedure_id()],
|
||||
}],
|
||||
vec![StreamLeaf::protocol_leaf_spec()],
|
||||
);
|
||||
let mut runtime =
|
||||
ProcedureRuntime::<StreamLeaf, ProcedureOpen>::new(endpoint, StreamLeaf::default());
|
||||
@@ -139,12 +141,17 @@ fn procedure_runtime_routes_data_to_stored_session() {
|
||||
assert!(runtime.leaf_mut().procedure_sessions().is_empty());
|
||||
}
|
||||
|
||||
#[derive(Default, Leaf)]
|
||||
#[leaf(id = "org.example.v1.duplex")]
|
||||
#[derive(Default)]
|
||||
struct DuplexLeaf {
|
||||
sessions: BTreeMap<HookKey, DuplexProcedure>,
|
||||
}
|
||||
|
||||
leaf! {
|
||||
id = "org.example.v1.duplex",
|
||||
procedures = [DuplexProcedure],
|
||||
endpoint_struct = DuplexLeaf,
|
||||
}
|
||||
|
||||
impl ProcedureStore<DuplexProcedure> for DuplexLeaf {
|
||||
fn procedure_sessions(&mut self) -> &mut BTreeMap<HookKey, DuplexProcedure> {
|
||||
&mut self.sessions
|
||||
@@ -197,10 +204,7 @@ fn procedure_runtime_keeps_session_after_local_end_until_explicit_close() {
|
||||
path(&["agent"]),
|
||||
Some(Vec::new()),
|
||||
Vec::new(),
|
||||
vec![crate::protocol::tree::LeafSpec {
|
||||
name: DuplexLeaf::protocol_leaf_name(),
|
||||
procedures: vec![DuplexProcedure::protocol_procedure_id()],
|
||||
}],
|
||||
vec![DuplexLeaf::protocol_leaf_spec()],
|
||||
);
|
||||
let mut runtime =
|
||||
ProcedureRuntime::<DuplexLeaf, DuplexProcedure>::new(endpoint, DuplexLeaf::default());
|
||||
|
||||
@@ -46,7 +46,7 @@ use super::{
|
||||
/// struct Open;
|
||||
/// impl ProcedureMetadata for Open {
|
||||
/// type Leaf = ExampleLeaf;
|
||||
/// fn procedure_suffix() -> &'static str { "open" }
|
||||
/// const PROCEDURE_SUFFIX: &'static str = "open";
|
||||
/// }
|
||||
/// assert_eq!(Open::procedure_id(), "org.example.v1.shell.open");
|
||||
/// ```
|
||||
@@ -55,7 +55,12 @@ pub trait ProcedureMetadata: Sized {
|
||||
type Leaf: ProtocolLeaf;
|
||||
|
||||
/// Returns the local suffix used to derive the full canonical `procedure_id`.
|
||||
fn procedure_suffix() -> &'static str;
|
||||
const PROCEDURE_SUFFIX: &'static str;
|
||||
|
||||
/// Returns the local suffix used to derive the full canonical `procedure_id`.
|
||||
fn procedure_suffix() -> &'static str {
|
||||
Self::PROCEDURE_SUFFIX
|
||||
}
|
||||
|
||||
/// Returns the canonical `procedure_id` for this procedure.
|
||||
fn procedure_id() -> String {
|
||||
@@ -81,8 +86,7 @@ pub trait ProcedureMetadata: Sized {
|
||||
/// struct Open;
|
||||
/// impl ProcedureMetadata for Open {
|
||||
/// type Leaf = ExampleLeaf;
|
||||
///
|
||||
/// fn procedure_suffix() -> &'static str { "open" }
|
||||
/// const PROCEDURE_SUFFIX: &'static str = "open";
|
||||
/// }
|
||||
/// fn _compat<T: StatefulProcedureMetadata<ExampleLeaf>>() {}
|
||||
/// _compat::<Open>();
|
||||
@@ -133,15 +137,20 @@ pub trait ProcedureStore<P> {
|
||||
/// ```rust
|
||||
/// use std::collections::BTreeMap;
|
||||
/// use std::string::String;
|
||||
/// use unshell::{Leaf, Procedure};
|
||||
/// use unshell::{Procedure, leaf};
|
||||
/// use unshell::protocol::tree::{Call, HookKey, Procedure, ProcedureEffect, ProcedureStore};
|
||||
///
|
||||
/// #[derive(Default, Leaf)]
|
||||
/// #[leaf(id = "org.example.v1.stream")]
|
||||
/// #[derive(Default)]
|
||||
/// struct StreamLeaf {
|
||||
/// sessions: BTreeMap<HookKey, OpenProcedure>,
|
||||
/// }
|
||||
///
|
||||
/// leaf! {
|
||||
/// id = "org.example.v1.stream",
|
||||
/// procedures = [OpenProcedure],
|
||||
/// endpoint_struct = StreamLeaf,
|
||||
/// }
|
||||
///
|
||||
/// impl ProcedureStore<OpenProcedure> for StreamLeaf {
|
||||
/// fn procedure_sessions(&mut self) -> &mut BTreeMap<HookKey, OpenProcedure> {
|
||||
/// &mut self.sessions
|
||||
|
||||
Reference in New Issue
Block a user