Skip to main content

taktora_executor/
error.rs

1//! Error types surfaced by the executor.
2
3use crate::task_id::TaskId;
4
5/// Type alias for user-supplied item errors. Boxed `dyn Error` so callers can
6/// plug in any error type without forcing this crate to know about it.
7pub type ItemError = Box<dyn std::error::Error + Send + Sync + 'static>;
8
9/// Top-level error type for the executor.
10#[derive(thiserror::Error, Debug)]
11#[non_exhaustive]
12pub enum ExecutorError {
13    /// An iceoryx2 operation failed. The original error is rendered with
14    /// `{}` because iceoryx2's error types do not collapse into a single
15    /// `From` source.
16    #[error("iceoryx2: {0}")]
17    Iceoryx2(String),
18
19    /// Graph validation failed at `build()` time.
20    #[error("invalid graph: {0}")]
21    InvalidGraph(String),
22
23    /// An item's `declare_triggers` call returned an error or the executor
24    /// rejected it (e.g. a duplicate subscriber attachment).
25    #[error("trigger declaration failed: {0}")]
26    DeclareTriggers(String),
27
28    /// An item returned `Err(...)` or panicked. The original error is wrapped.
29    #[error("item error in task {task_id}: {source}")]
30    Item {
31        /// The task that produced the error.
32        task_id: TaskId,
33        /// The underlying error from the item.
34        #[source]
35        source: ItemError,
36    },
37
38    /// `Executor::run` was called while the executor was already running.
39    #[error("executor already running")]
40    AlreadyRunning,
41
42    /// The runner thread panicked or could not be joined.
43    #[error("runner thread join failed")]
44    RunnerJoin,
45
46    /// Builder API used incorrectly (e.g. missing required field).
47    #[error("builder misuse: {0}")]
48    Builder(String),
49}
50
51impl ExecutorError {
52    /// Convenience constructor for wrapping arbitrary iceoryx2 error values.
53    #[must_use]
54    pub fn iceoryx2(err: impl core::fmt::Display) -> Self {
55        Self::Iceoryx2(err.to_string())
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    #[test]
64    fn item_error_roundtrip() {
65        let source: ItemError = Box::new(std::io::Error::other("boom"));
66        let err = ExecutorError::Item {
67            task_id: "task-1".into(),
68            source,
69        };
70        let s = format!("{err}");
71        assert!(s.contains("task-1"));
72        assert!(s.contains("boom"));
73    }
74
75    #[test]
76    fn iceoryx2_helper_renders_display() {
77        #[derive(Debug, thiserror::Error)]
78        #[error("whatever happened")]
79        struct Whatever;
80        let e = ExecutorError::iceoryx2(Whatever);
81        assert!(matches!(e, ExecutorError::Iceoryx2(_)));
82        assert!(format!("{e}").contains("whatever happened"));
83    }
84}