multilinear 0.6.0

Interactive story simulation using constrained parallel aspects
Documentation
use bit_set::BitSet;
use event_simulation::EditableSimulationInfo;
use std::ops::Deref;

use crate::{
    Aspect, Change, EventEdit, From, InvalidChangeError, MultilinearInfo, MultilinearState, To,
};

/// A wrapper type for `MultilinearInfo` which only supports safe edits that don't invalidate existing simulation states.
pub struct EditMultilinearInfo<'a> {
    info: &'a mut MultilinearInfo,
}

impl Deref for EditMultilinearInfo<'_> {
    type Target = MultilinearInfo;
    fn deref(&self) -> &MultilinearInfo {
        self.info
    }
}

impl<'a> EditMultilinearInfo<'a> {
    pub(crate) fn new(info: &'a mut MultilinearInfo) -> Self {
        Self { info }
    }

    /// Adds a new aspect to the multilinear system and returns its identifier.
    pub fn add_aspect(&mut self) -> Aspect {
        self.info.add_aspect()
    }

    /// Adds a new event to the multilinear system and returns an editable event info.
    pub fn add_event(&mut self) -> EventEdit<'_> {
        self.info.add_event()
    }

    /// Adds a new event with multiple change sets and returns the editable event info.
    pub fn add_event_with_changes(
        &mut self,
        changes: &[&[Change]],
    ) -> Result<EventEdit<'_>, InvalidChangeError> {
        let mut event = self.info.add_event();
        for &change_set in changes {
            event.add_change(change_set)?;
        }
        Ok(event)
    }
}

impl EditableSimulationInfo for MultilinearInfo {
    type Edit<'a> = EditMultilinearInfo<'a>;

    unsafe fn edit(&mut self) -> EditMultilinearInfo<'_> {
        EditMultilinearInfo::new(self)
    }

    unsafe fn refresh_state(&self, state: &mut MultilinearState) {
        state.values.resize(self.aspects.len(), 0);

        state.callables = BitSet::new();
        state.revertables = BitSet::new();

        for (index, event) in self.events.iter().enumerate() {
            if event.check_action::<From>(&state.values) {
                state.callables.insert(index);
            }
            if event.check_action::<To>(&state.values) {
                state.revertables.insert(index);
            }
        }
    }
}