use super::{Effect, EffectHandlerRef};
use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EffectContext {
effects: Vec<Effect>,
handlers: Vec<EffectHandlerRef>,
}
impl EffectContext {
pub fn new() -> Self {
Self {
effects: Vec::new(),
handlers: Vec::new(),
}
}
pub fn pure() -> Self {
Self {
effects: vec![Effect::Pure],
handlers: Vec::new(),
}
}
pub fn add_effect(&mut self, effect: Effect) {
if !self.effects.contains(&effect) {
self.effects.push(effect);
self.effects.sort();
}
}
pub fn add_handler(&mut self, handler: EffectHandlerRef) {
self.handlers.push(handler);
}
pub fn effects(&self) -> &[Effect] {
&self.effects
}
pub fn handlers(&self) -> &[EffectHandlerRef] {
&self.handlers
}
pub fn is_pure(&self) -> bool {
self.effects.len() == 1 && self.effects[0] == Effect::Pure
}
pub fn has_effect(&self, effect: &Effect) -> bool {
self.effects.contains(effect)
}
pub fn with_effects(&self, effects: Vec<Effect>) -> Self {
let mut new_context = self.clone();
for effect in effects {
new_context.add_effect(effect);
}
new_context
}
pub fn without_effects(&self, effects: Vec<Effect>) -> Self {
let mut new_effects = self.effects.clone();
for effect in effects {
new_effects.retain(|e| e != &effect);
}
Self {
effects: new_effects,
handlers: self.handlers.clone(),
}
}
pub fn combine(&self, other: &EffectContext) -> EffectContext {
let mut combined = self.clone();
for effect in &other.effects {
combined.add_effect(effect.clone());
}
for handler in &other.handlers {
combined.add_handler(handler.clone());
}
combined
}
pub fn find_handler(&self, effect: &Effect) -> Option<&EffectHandlerRef> {
self.handlers.iter().find(|h| h.handler().can_handle(effect))
}
}
impl Default for EffectContext {
fn default() -> Self {
Self::new()
}
}
impl fmt::Display for EffectContext {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.is_pure() {
write!(f, "Pure")
} else {
write!(f, "[")?;
for (i, effect) in self.effects.iter().enumerate() {
if i > 0 { write!(f, ", ")?; }
write!(f, "{effect}")?;
}
write!(f, "]")
}
}
}