Skip to main content

robonix_executor/
rtdl_wire.rs

1// SPDX-License-Identifier: MulanPSL-2.0
2// Flat `RtdlEvent` (`lib/executor/msg/RtdlEvent.msg`).
3
4use crate::pb::executor::rtdl_event::RtdlEventEnum;
5use crate::pb::executor::{RtdlEvent, RtdlPlanComplete, RtdlPlanStarted};
6use crate::pb::pilot::rtdl_node_state::RtdlNodeStateEnum;
7use crate::pb::pilot::{CapabilityCallResult, RtdlNodeState};
8
9#[derive(Clone)]
10pub struct NodeEventContext {
11    pub plan_id: String,
12    pub node_index: u32,
13    pub node_kind: u32,
14    pub op_id: String,
15    pub description: String,
16}
17
18pub fn is_terminal_state(state: u32) -> bool {
19    matches!(
20        RtdlNodeStateEnum::try_from(state as i32),
21        Ok(RtdlNodeStateEnum::Succeeded
22            | RtdlNodeStateEnum::Failed
23            | RtdlNodeStateEnum::Canceled
24            | RtdlNodeStateEnum::Timeout)
25    )
26}
27
28pub fn plan_started(plan_id: String) -> RtdlEvent {
29    RtdlEvent {
30        event_kind: RtdlEventEnum::PlanStarted as u32,
31        plan_started: Some(RtdlPlanStarted { plan_id }),
32        ..Default::default()
33    }
34}
35
36pub fn node_state(
37    node: &NodeEventContext,
38    state: u32,
39    operator_detail: String,
40    leaf_result: Option<CapabilityCallResult>,
41) -> RtdlEvent {
42    RtdlEvent {
43        event_kind: RtdlEventEnum::NodeState as u32,
44        node_state: Some(RtdlNodeState {
45            plan_id: node.plan_id.clone(),
46            node_index: node.node_index,
47            node_kind: node.node_kind,
48            state,
49            operator_detail,
50            leaf_result,
51            op_id: node.op_id.clone(),
52            description: node.description.clone(),
53        }),
54        ..Default::default()
55    }
56}
57
58pub fn node_state_from_result(
59    node: &NodeEventContext,
60    result: CapabilityCallResult,
61    state: u32,
62) -> RtdlEvent {
63    node_state(node, state, String::new(), Some(result))
64}
65
66pub fn operator_node_state(node: &NodeEventContext, state: u32, detail: String) -> RtdlEvent {
67    node_state(node, state, detail, None)
68}
69
70pub fn plan_complete(plan_id: String, any_failed: bool) -> RtdlEvent {
71    RtdlEvent {
72        event_kind: RtdlEventEnum::PlanComplete as u32,
73        plan_complete: Some(RtdlPlanComplete {
74            plan_id,
75            any_failed,
76        }),
77        ..Default::default()
78    }
79}
80
81#[cfg(test)]
82mod tests {
83    use super::*;
84
85    #[test]
86    fn node_state_uses_plan_and_node_fields() {
87        let event = node_state(
88            &NodeEventContext {
89                plan_id: "p".into(),
90                node_index: 7,
91                node_kind: 2,
92                op_id: "op_1".into(),
93                description: "take a camera snapshot".into(),
94            },
95            RtdlNodeStateEnum::Running as u32,
96            "operator detail".into(),
97            None,
98        );
99        let ns = event.node_state.unwrap();
100
101        assert_eq!(event.event_kind, RtdlEventEnum::NodeState as u32);
102        assert_eq!(ns.plan_id, "p");
103        assert_eq!(ns.node_index, 7);
104        assert_eq!(ns.node_kind, 2);
105        assert_eq!(ns.state, RtdlNodeStateEnum::Running as u32);
106        assert_eq!(ns.operator_detail, "operator detail");
107        assert!(ns.leaf_result.is_none());
108        assert_eq!(ns.op_id, "op_1");
109        assert_eq!(ns.description, "take a camera snapshot");
110    }
111}