daedalus_runtime/
lib.rs

1//! Runtime orchestration scaffolding. See `PLAN.md` for the detailed roadmap.
2//! Transforms planner `ExecutionPlan` into a runnable `RuntimePlan` with edge policies and schedulable segments.
3
4pub mod capabilities;
5pub mod config;
6mod convert;
7pub mod debug;
8pub mod executor;
9pub mod fanin;
10pub mod graph_builder;
11pub mod handler_registry;
12pub mod handles;
13pub mod host_bridge;
14pub mod io;
15mod plan;
16mod perf;
17#[cfg(feature = "plugins")]
18pub mod plugins;
19mod scheduler;
20pub mod snapshot;
21pub mod state;
22
23/// Apply a plugin prefix to a node id without duplicating overlapping segments.
24///
25/// Examples:
26/// - prefix `ai`, id `ai:run` => `ai:run`
27/// - prefix `cv:aruco`, id `cv:decode_grid` => `cv:aruco:decode_grid`
28/// - prefix `cv`, id `aruco:decode_grid` => `cv:aruco:decode_grid`
29///
30/// ```
31/// use daedalus_runtime::apply_node_prefix;
32/// assert_eq!(apply_node_prefix("ai", "ai:run"), "ai:run");
33/// assert_eq!(apply_node_prefix("cv", "aruco:decode_grid"), "cv:aruco:decode_grid");
34/// ```
35pub fn apply_node_prefix(prefix: &str, id: &str) -> String {
36    let prefix = prefix.trim_matches(':').trim();
37    let id = id.trim_matches(':').trim();
38
39    if prefix.is_empty() {
40        return id.to_string();
41    }
42    if id.is_empty() {
43        return prefix.to_string();
44    }
45
46    let prefix_parts: Vec<&str> = prefix
47        .split(':')
48        .map(str::trim)
49        .filter(|p| !p.is_empty())
50        .collect();
51    let id_parts: Vec<&str> = id
52        .split(':')
53        .map(str::trim)
54        .filter(|p| !p.is_empty())
55        .collect();
56
57    if prefix_parts.is_empty() {
58        return id.to_string();
59    }
60    if id_parts.is_empty() {
61        return prefix.to_string();
62    }
63
64    let max_overlap = std::cmp::min(prefix_parts.len(), id_parts.len());
65    let mut overlap = 0usize;
66    while overlap < max_overlap && prefix_parts[overlap] == id_parts[overlap] {
67        overlap += 1;
68    }
69
70    if overlap == prefix_parts.len() {
71        // Already fully prefixed.
72        return id.to_string();
73    }
74
75    let mut out: Vec<&str> =
76        Vec::with_capacity(prefix_parts.len() + id_parts.len().saturating_sub(overlap));
77    out.extend_from_slice(&prefix_parts);
78    out.extend_from_slice(&id_parts[overlap..]);
79    out.join(":")
80}
81
82pub use config::*;
83pub use convert::{ConversionRegistry, convert_arc};
84pub use executor::{
85    EdgePayload, ExecuteError, ExecutionTelemetry, Executor, MetricsLevel, NodeError, NodeHandler,
86    NodeMetrics,
87};
88pub use fanin::FanIn;
89pub use handles::{NodeHandle, PortHandle};
90pub use host_bridge::{
91    HOST_BRIDGE_META_KEY, HostBridgeHandle, HostBridgeManager, HostBridgeSerialized,
92    HostBridgeSerializedPayload, bridge_handler,
93};
94pub use io::{NodeIo, register_output_mover};
95pub use plan::{BackpressureStrategy, EdgePolicyKind, RuntimeNode, RuntimePlan, RuntimeSegment};
96pub use scheduler::{SchedulerConfig, build_runtime};