capsula_core/
context.rs

1use crate::error::{CapsulaError, CoreResult};
2use clap::ValueEnum;
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum, Serialize, Deserialize)]
7#[serde(rename_all = "lowercase")]
8pub enum ContextPhase {
9    Pre,
10    Post,
11}
12
13#[derive(Debug, Clone)]
14pub struct RuntimeParams {
15    pub phase: ContextPhase,
16    pub run_dir: Option<std::path::PathBuf>,
17    pub project_root: std::path::PathBuf,
18}
19
20pub trait Context {
21    type Output: super::captured::Captured;
22    fn run(&self, params: &RuntimeParams) -> CoreResult<Self::Output>;
23}
24
25/// Engine-facing trait (object-safe, heterogenous)
26pub trait ContextErased: Send + Sync {
27    fn run_erased(
28        &self,
29        parmas: &RuntimeParams,
30    ) -> Result<Box<dyn super::captured::Captured>, CapsulaError>;
31}
32
33impl<T> ContextErased for T
34where
35    T: Context + Send + Sync + 'static,
36{
37    fn run_erased(
38        &self,
39        params: &RuntimeParams,
40    ) -> Result<Box<dyn super::captured::Captured>, CapsulaError> {
41        let out = <T as Context>::run(self, params)?;
42        Ok(Box::new(out))
43    }
44}
45
46/// Factory trait for creating contexts from configuration
47pub trait ContextFactory: Send + Sync {
48    /// The type key this factory handles (e.g., "cwd", "git", "file")
49    fn key(&self) -> &'static str;
50
51    /// Create a context instance from JSON configuration
52    fn create_context(
53        &self,
54        config: &Value,
55        project_root: &std::path::Path,
56    ) -> CoreResult<Box<dyn ContextErased>>;
57}