mirror of
https://github.com/Astatin3/unshell.git
synced 2026-06-08 22:38:01 -06:00
expand treetest documentation and rationale
This commit is contained in:
@@ -14,6 +14,8 @@ impl Simulation {
|
||||
for node_id in 0..self.nodes.len() {
|
||||
match self.nodes[node_id].rx.try_recv() {
|
||||
Ok(envelope) => {
|
||||
// Record ingress before handing the frame to the protocol
|
||||
// runtime so the trace shows the channel-level hop too.
|
||||
self.record_trace(
|
||||
NodeId(node_id),
|
||||
format!("received frame via {:?}", envelope.ingress),
|
||||
@@ -36,6 +38,7 @@ impl Simulation {
|
||||
|
||||
/// Runs frames until the network becomes idle.
|
||||
pub fn drain(&mut self) -> Result<usize, SimError> {
|
||||
// Count steps so callers can surface how much work one action caused.
|
||||
let mut steps = 0;
|
||||
while self.step()? {
|
||||
steps += 1;
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
//! Construction and mode-management helpers for the simulator.
|
||||
//!
|
||||
//! These helpers are kept separate from runtime packet flow so scenario boot and
|
||||
//! mode transitions remain easy to read and test in isolation.
|
||||
|
||||
use std::collections::{BTreeMap, VecDeque};
|
||||
|
||||
@@ -12,12 +15,28 @@ use super::types::{ChatSession, SimError, SimNode, Simulation};
|
||||
|
||||
impl Simulation {
|
||||
/// Creates a fresh simulation from a scenario definition.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// use treetest::{scenarios::built_in_scenarios, sim::Simulation};
|
||||
///
|
||||
/// let scenario = built_in_scenarios().into_iter().next().unwrap();
|
||||
/// let simulation = Simulation::new(scenario).unwrap();
|
||||
/// assert_eq!(simulation.node(treetest::model::NodeId(0)).display_path(), "/");
|
||||
/// ```
|
||||
pub fn new(scenario: ScenarioDefinition) -> Result<Self, SimError> {
|
||||
// Flatten the recursive scenario description once so the rest of the
|
||||
// simulator can address nodes by stable ids.
|
||||
let tree = DemoTree::from_root(&scenario.root);
|
||||
let mut nodes = Vec::with_capacity(tree.nodes.len());
|
||||
|
||||
for demo_node in &tree.nodes {
|
||||
// Each endpoint gets one mailbox pair. The simulator never opens a
|
||||
// real socket, so every hop is just channel delivery.
|
||||
let (tx, rx) = unbounded();
|
||||
|
||||
// Materialize child routes up front so the protocol runtime can make
|
||||
// longest-prefix decisions without consulting the demo model again.
|
||||
let children = demo_node
|
||||
.children
|
||||
.iter()
|
||||
@@ -26,6 +45,8 @@ impl Simulation {
|
||||
state: ConnectionState::Registered,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Translate demo leaf metadata into protocol-runtime leaf specs.
|
||||
let leaves = demo_node
|
||||
.leaves
|
||||
.iter()
|
||||
@@ -37,6 +58,9 @@ impl Simulation {
|
||||
},
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Parents are stored by path because the protocol runtime reasons in
|
||||
// terms of endpoint paths rather than UI node ids.
|
||||
let parent_path = demo_node
|
||||
.parent
|
||||
.map(|parent_id| tree.node(parent_id).path.clone());
|
||||
@@ -49,6 +73,7 @@ impl Simulation {
|
||||
.map_err(|error| SimError::Protocol(error.to_string()))?;
|
||||
}
|
||||
|
||||
// Store the runtime endpoint alongside topology and mailbox state.
|
||||
nodes.push(SimNode {
|
||||
parent: demo_node.parent,
|
||||
children: demo_node.children.clone(),
|
||||
@@ -58,6 +83,8 @@ impl Simulation {
|
||||
});
|
||||
}
|
||||
|
||||
// The root starts with only its own configuration plus direct-child
|
||||
// awareness, which realistic mode later uses as its initial knowledge.
|
||||
let root_knowledge = RootKnowledge::new(&tree);
|
||||
|
||||
Ok(Self {
|
||||
@@ -65,6 +92,7 @@ impl Simulation {
|
||||
tree,
|
||||
nodes,
|
||||
root_id: NodeId(0),
|
||||
// Tick counting starts at one so trace output reads naturally.
|
||||
next_tick: 1,
|
||||
trace: VecDeque::new(),
|
||||
recorded_events: Vec::new(),
|
||||
@@ -86,6 +114,9 @@ impl Simulation {
|
||||
}
|
||||
|
||||
/// Clears deeper root memory and switches the inspector into realistic mode.
|
||||
///
|
||||
/// Rationale: this mirrors a host that only retains locally configured and
|
||||
/// one-hop information until it learns more by introspection or traffic.
|
||||
pub fn enable_realistic_mode_with_memory_reset(&mut self) {
|
||||
self.root_knowledge.clear_deeper_than_one_hop();
|
||||
self.inspector_mode = InspectorMode::Realistic;
|
||||
|
||||
Reference in New Issue
Block a user