Skip to main content

kore/
effects.rs

1//! KORE Effect System - Track side effects at compile time
2
3use crate::span::Span;
4use crate::error::{KoreError, KoreResult};
5use std::collections::HashSet;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8pub enum Effect {
9    Pure,      // No side effects
10    IO,        // File/Network/Console
11    Async,     // Can await
12    GPU,       // Runs on graphics hardware
13    Reactive,  // Triggers UI updates
14    Unsafe,    // Breaks safety guarantees
15    Alloc,     // Memory allocation
16    Panic,     // Can abort
17}
18
19impl Effect {
20    pub fn from_str(s: &str) -> Option<Self> {
21        match s {
22            "Pure" => Some(Effect::Pure),
23            "IO" => Some(Effect::IO),
24            "Async" => Some(Effect::Async),
25            "GPU" => Some(Effect::GPU),
26            "Reactive" => Some(Effect::Reactive),
27            "Unsafe" => Some(Effect::Unsafe),
28            _ => None,
29        }
30    }
31}
32
33#[derive(Debug, Clone, Default, PartialEq, Eq)]
34pub struct EffectSet {
35    pub effects: HashSet<Effect>,
36}
37
38impl EffectSet {
39    pub fn new() -> Self { Self { effects: HashSet::new() } }
40    pub fn pure() -> Self { Self::new().with(Effect::Pure) }
41    
42    pub fn with(mut self, e: Effect) -> Self {
43        self.effects.insert(e);
44        self
45    }
46    
47    pub fn is_pure(&self) -> bool {
48        self.effects.is_empty() || self.effects.iter().all(|e| *e == Effect::Pure)
49    }
50    
51    pub fn can_call(&self, callee: &EffectSet) -> bool {
52        if callee.is_pure() { return true; }
53        if self.is_pure() { return false; }
54        if self.effects.contains(&Effect::Unsafe) { return true; }
55        callee.effects.iter().all(|e| self.effects.contains(e))
56    }
57}
58
59pub fn check_effect_call(caller: &EffectSet, callee: &EffectSet, span: Span) -> KoreResult<()> {
60    if !caller.can_call(callee) {
61        return Err(KoreError::effect_error(
62            format!("Effect violation: {:?} cannot call {:?}", caller.effects, callee.effects),
63            span,
64        ));
65    }
66    Ok(())
67}
68