nyandere 0.1.2

i help with keeping track of purchases. meow
Documentation
//! Process and understand.
//!
//! What is semantically valid?

pub mod cmd;
pub mod model;
pub mod resolve;

pub use resolve::{Emerge, Resolve};

use std::ops::Deref;

use crate::{
    Map, Name,
    aux::NotOrd,
    error,
    ext::{business::Value, shop::Gtin},
    runtime::{
        cmd::{Output, Run},
        model::{Concept, Entity, Object, Pair},
    },
    syntax::ast::Script,
};

#[derive(NotOrd!, Default)]
pub struct Runtime {
    state: State,
}

impl Runtime {
    #[must_use]
    pub fn state(&self) -> &State {
        &self.state
    }

    #[must_use]
    pub fn to_state(self) -> State {
        self.state
    }
}

impl Runtime {
    /// Initializes an empty runtime.
    ///
    /// Run [`cmd::Create`] to start filling it afterwards.
    #[must_use]
    pub fn new() -> Self {
        Self::default()
    }

    /// Evaluate a whole parsed [`Script`].
    ///
    /// # Error
    ///
    /// Note that in the case of an error,
    /// the runtime is not rolled back
    /// and still holds the state
    /// just before the invalid command.
    pub fn run(&mut self, script: Script) -> Result<(), error::Construction> {
        for stmt in script.0 {
            let cmd = cmd::construct(stmt, &self.state)?;
            if let Some(msg) = self.step(cmd) {
                println!("{msg}");
            }
        }

        Ok(())
    }

    pub fn step(&mut self, cmd: Box<dyn Run>) -> Output {
        cmd.run(&mut self.state)
    }
}

impl Deref for Runtime {
    type Target = State;

    fn deref(&self) -> &Self::Target {
        &self.state
    }
}

// TODO: generate this automatically
/// An index of directly accessible actors.
///
/// # On being complete
///
/// Note that over time,
/// actors might be come inaccessible
/// as their names (or GTIN, in case of a concept)
/// can be shadowed.
/// In this case, they will never become accessible again.
/// ***However***, they will still be referred to
/// when referenced elsewhere.
/// 
/// For example, take this script:
///
/// ```text
/// create concept C price 1€
/// create object O
/// create concept C price 2€
/// ```
///
/// After this script was ran,
/// object `O` still the former concept `C` with price 1€
/// as parent.
/// However, only the latter concept `C` with price 2€
/// can be referred to by its name.
#[derive(NotOrd!, Default)]
pub struct State {
    // not much use -- yet, that is
    pub entities: Map<Name, Entity>,
    pub concepts: Map<Name, Concept>,
    pub concepts_gtin: Map<Gtin, Concept>,
    pub objects: Map<Name, Object>,

    // TODO: think about how to store this smarter.
    // maybe with debit-credit bookkeeping applied as in 2 maps?
    pub balances: Map<Pair, Value>,
}