Skip to main content

ryo_executor/executor/
traits.rs

1//! Executor trait: Action を実行するインターフェース
2
3use super::context::ExecutionContext;
4use crate::decider::{Action, ActionKind, ActionResult};
5use std::fmt;
6
7/// Executor のエラー型
8#[derive(Debug)]
9pub enum ExecutorError {
10    /// サポートされていない ActionKind
11    UnsupportedAction(ActionKind),
12    /// コマンド実行エラー
13    CommandFailed(String),
14    /// ファイルが見つからない
15    FileNotFound(String),
16    /// タイムアウト
17    Timeout,
18    /// その他のエラー
19    Other(String),
20}
21
22impl fmt::Display for ExecutorError {
23    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24        match self {
25            Self::UnsupportedAction(kind) => write!(f, "Unsupported action: {:?}", kind),
26            Self::CommandFailed(msg) => write!(f, "Command failed: {}", msg),
27            Self::FileNotFound(path) => write!(f, "File not found: {}", path),
28            Self::Timeout => write!(f, "Execution timeout"),
29            Self::Other(msg) => write!(f, "{}", msg),
30        }
31    }
32}
33
34impl std::error::Error for ExecutorError {}
35
36/// Executor trait: Action を実行して ActionResult を返す
37pub trait Executor: Send + Sync {
38    /// Action を実行
39    fn execute(
40        &self,
41        action: &Action,
42        ctx: &ExecutionContext,
43    ) -> Result<ActionResult, ExecutorError>;
44
45    /// このExecutorがサポートする ActionKind の一覧
46    fn supported_kinds(&self) -> &[ActionKind];
47
48    /// このActionを実行可能か
49    fn can_execute(&self, action: &Action) -> bool {
50        self.supported_kinds().contains(&action.kind)
51    }
52
53    /// 名前(デバッグ用)
54    fn name(&self) -> &'static str {
55        "Executor"
56    }
57}
58
59/// 複数の Executor をチェーンする
60pub struct CompositeExecutor {
61    executors: Vec<Box<dyn Executor>>,
62}
63
64impl CompositeExecutor {
65    /// 新しい CompositeExecutor を作成
66    pub fn new() -> Self {
67        Self {
68            executors: Vec::new(),
69        }
70    }
71
72    /// Executor を追加
73    pub fn with<E: Executor + 'static>(mut self, executor: E) -> Self {
74        self.executors.push(Box::new(executor));
75        self
76    }
77}
78
79impl Default for CompositeExecutor {
80    fn default() -> Self {
81        Self::new()
82    }
83}
84
85impl Executor for CompositeExecutor {
86    fn execute(
87        &self,
88        action: &Action,
89        ctx: &ExecutionContext,
90    ) -> Result<ActionResult, ExecutorError> {
91        // 最初に処理可能な Executor を使う
92        for executor in &self.executors {
93            if executor.can_execute(action) {
94                return executor.execute(action, ctx);
95            }
96        }
97        Err(ExecutorError::UnsupportedAction(action.kind))
98    }
99
100    fn supported_kinds(&self) -> &[ActionKind] {
101        // 全 Executor のサポートを集約(簡略化のため空を返す)
102        &[]
103    }
104
105    fn can_execute(&self, action: &Action) -> bool {
106        self.executors.iter().any(|e| e.can_execute(action))
107    }
108
109    fn name(&self) -> &'static str {
110        "CompositeExecutor"
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117
118    #[test]
119    fn test_executor_error_display() {
120        let err = ExecutorError::UnsupportedAction(ActionKind::Read);
121        assert!(err.to_string().contains("Unsupported"));
122
123        let err = ExecutorError::FileNotFound("test.rs".to_string());
124        assert!(err.to_string().contains("test.rs"));
125    }
126}