Store session state directly

This commit is contained in:
Michael Mikovsky
2026-06-01 11:30:25 -06:00
parent 8ab72d35b0
commit f2bc2d912d
4 changed files with 21 additions and 28 deletions
+8 -5
View File
@@ -41,7 +41,7 @@ unshell_leaf! {
authors: unshell::alloc::vec!["ASTATIN3"], authors: unshell::alloc::vec!["ASTATIN3"],
}, },
sessions { sessions {
pty: PtySession, pty: PtySessionState,
} }
procedures {} procedures {}
} }
@@ -59,10 +59,14 @@ The example above expands to the equivalent of:
pub struct FakePtyLeaf { pub struct FakePtyLeaf {
state: FakePtyState, state: FakePtyState,
outbox: LeafOutbox, outbox: LeafOutbox,
pty: SessionFamily<<PtySession as Session<FakePtyState>>::State>, pty: SessionFamily<PtySessionState>,
} }
``` ```
Session types are the per-hook state values themselves. There is no separate
zero-sized handler struct; a type like `PtySessionState` implements `Session` and is
stored directly in the generated `SessionFamily`.
The wrapper implements: The wrapper implements:
- `new(state)` - `new(state)`
@@ -149,13 +153,12 @@ Ratatui rendering is a plain feature-gated pass:
leaf.render_ratatui(frame, area, &mut interface); leaf.render_ratatui(frame, area, &mut interface);
``` ```
Session rendering is an associated function because session families are type-level Session rendering is an associated function on the stored session state type:
contracts, not stored objects:
```rust ```rust
fn render_ratatui( fn render_ratatui(
leaf: &LeafState, leaf: &LeafState,
session: &Self::State, session: &Self,
view: &mut SessionView, view: &mut SessionView,
frame: &mut ratatui::Frame<'_>, frame: &mut ratatui::Frame<'_>,
area: ratatui::layout::Rect, area: ratatui::layout::Rect,
+1 -3
View File
@@ -17,9 +17,7 @@ macro_rules! unshell_leaf {
state: $State, state: $State,
outbox: $crate::protocol::LeafOutbox, outbox: $crate::protocol::LeafOutbox,
$( $(
$session_field: $crate::protocol::SessionFamily< $session_field: $crate::protocol::SessionFamily<$Session>,
<$Session as $crate::protocol::Session<$State>>::State,
>,
)* )*
} }
+3 -3
View File
@@ -91,7 +91,7 @@ pub fn dispatch_session<L, S>(
endpoint: &Endpoint, endpoint: &Endpoint,
leaf_id: u32, leaf_id: u32,
leaf: &mut L, leaf: &mut L,
family: &mut SessionFamily<S::State>, family: &mut SessionFamily<S>,
packet: Packet, packet: Packet,
outbox: &mut LeafOutbox, outbox: &mut LeafOutbox,
interface: &mut Option<&mut InterfaceStore>, interface: &mut Option<&mut InterfaceStore>,
@@ -215,7 +215,7 @@ pub fn dispatch_session<L, S>(
pub fn update_session_family<L, S>( pub fn update_session_family<L, S>(
leaf_id: u32, leaf_id: u32,
leaf: &mut L, leaf: &mut L,
family: &mut SessionFamily<S::State>, family: &mut SessionFamily<S>,
interface: &mut Option<&mut InterfaceStore>, interface: &mut Option<&mut InterfaceStore>,
) where ) where
S: Session<L>, S: Session<L>,
@@ -338,7 +338,7 @@ pub fn flush_leaf_outbox(
pub fn flush_session_family<L, S>( pub fn flush_session_family<L, S>(
endpoint: &mut Endpoint, endpoint: &mut Endpoint,
leaf_id: u32, leaf_id: u32,
family: &mut SessionFamily<S::State>, family: &mut SessionFamily<S>,
interface: &mut Option<&mut InterfaceStore>, interface: &mut Option<&mut InterfaceStore>,
) where ) where
S: Session<L>, S: Session<L>,
+9 -17
View File
@@ -9,26 +9,25 @@ use crate::interface::SessionView;
/// ///
/// A session family maps one outer `procedure_id` to many live hook instances. The /// A session family maps one outer `procedure_id` to many live hook instances. The
/// generated leaf owns packet grouping, retry-safe output flushing, and final cleanup; /// generated leaf owns packet grouping, retry-safe output flushing, and final cleanup;
/// the session implementation owns only application behavior. /// the session value owns one hook's application behavior and mutable state.
/// ///
/// # Example /// # Example
/// ///
/// ```rust,ignore /// ```rust,ignore
/// impl Session<MyLeafState> for MySession { /// impl Session<MyLeafState> for MySessionState {
/// const PROCEDURE_ID: u32 = 7; /// const PROCEDURE_ID: u32 = 7;
/// type State = MySessionState;
/// ///
/// fn init( /// fn init(
/// leaf: &mut MyLeafState, /// leaf: &mut MyLeafState,
/// packet: Packet, /// packet: Packet,
/// ctx: &mut SessionInit, /// ctx: &mut SessionInit,
/// ) -> Result<Self::State, SessionInitError> { /// ) -> Result<Self, SessionInitError> {
/// Ok(MySessionState::from_open(leaf, packet, ctx)) /// Ok(MySessionState::from_open(leaf, packet, ctx))
/// } /// }
/// ///
/// fn update( /// fn update(
/// leaf: &mut MyLeafState, /// leaf: &mut MyLeafState,
/// session: &mut Self::State, /// session: &mut Self,
/// incoming: &mut PacketQueue, /// incoming: &mut PacketQueue,
/// ctx: &mut SessionCtx<'_>, /// ctx: &mut SessionCtx<'_>,
/// ) -> SessionStatus { /// ) -> SessionStatus {
@@ -39,23 +38,16 @@ use crate::interface::SessionView;
/// } /// }
/// } /// }
/// ``` /// ```
pub trait Session<L> { pub trait Session<L>: Sized {
/// Outer packet procedure id used by every packet in this session family. /// Outer packet procedure id used by every packet in this session family.
const PROCEDURE_ID: u32; const PROCEDURE_ID: u32;
/// Application state stored for one live hook. /// Creates one session value from a packet whose hook has no active session.
type State;
/// Creates one session state from a packet whose hook has no active session.
/// ///
/// The generated runtime derives all response routing from hook state. Session /// The generated runtime derives all response routing from hook state. Session
/// initialization therefore returns only application state or a protocol-level /// initialization therefore returns only application state or a protocol-level
/// rejection; it never stores or receives a caller reply path. /// rejection; it never stores or receives a caller reply path.
fn init( fn init(leaf: &mut L, packet: Packet, ctx: &mut SessionInit) -> Result<Self, SessionInitError>;
leaf: &mut L,
packet: Packet,
ctx: &mut SessionInit,
) -> Result<Self::State, SessionInitError>;
/// Advances one active hook session. /// Advances one active hook session.
/// ///
@@ -65,7 +57,7 @@ pub trait Session<L> {
/// generated retry rules. /// generated retry rules.
fn update( fn update(
leaf: &mut L, leaf: &mut L,
session: &mut Self::State, session: &mut Self,
incoming: &mut PacketQueue, incoming: &mut PacketQueue,
ctx: &mut SessionCtx<'_>, ctx: &mut SessionCtx<'_>,
) -> SessionStatus; ) -> SessionStatus;
@@ -73,7 +65,7 @@ pub trait Session<L> {
#[cfg(feature = "interface_ratatui")] #[cfg(feature = "interface_ratatui")]
fn render_ratatui( fn render_ratatui(
_: &L, _: &L,
_: &Self::State, _: &Self,
_: &mut SessionView, _: &mut SessionView,
_: &mut ratatui::Frame<'_>, _: &mut ratatui::Frame<'_>,
_: ratatui::layout::Rect, _: ratatui::layout::Rect,