iocaine 3.0.0

The deadliest poison known to AI
Documentation
// SPDX-FileCopyrightText: 2025 Gergely Nagy
// SPDX-FileContributor: Gergely Nagy
//
// SPDX-License-Identifier: MIT

use serde::{Deserialize, Serialize};
use std::fmt::Display;
use std::path::Path;

use crate::tenx_programmer::TenXProgrammer;

#[cfg(feature = "lua")]
mod elegant_weapons;
#[cfg(feature = "lua")]
mod howl;
mod matchers;
pub mod means_of_production;
mod request;
mod response;

#[cfg(feature = "lua")]
pub use elegant_weapons::ElegantWeapons;
#[cfg(feature = "lua")]
pub use howl::Howl;
pub use matchers::Matcher;
pub use means_of_production::MeansOfProduction;
pub use request::{Request, SharedRequest};
pub use response::Response;

pub type NPC = Box<dyn SexDungeon + Send + Sync + 'static>;

pub trait SexDungeon {
    fn new<P: AsRef<Path>, C: AsRef<Path>, S: Serialize>(
        path: P,
        compiler: Option<C>,
        initial_seed: &str,
        metrics: &TenXProgrammer,
        config: Option<S>,
    ) -> anyhow::Result<Self>
    where
        Self: Sized + Send + Sync + 'static;

    fn can_decide(&self) -> bool;
    fn decide(&self, request: SharedRequest) -> Result<String, anyhow::Error>;
    fn can_output(&self) -> bool;
    fn output(
        &self,
        request: SharedRequest,
        decision: Option<String>,
    ) -> Result<Response, anyhow::Error>;

    fn run_tests(&mut self) -> anyhow::Result<()>;
}

#[derive(Clone, Copy, Debug, Deserialize, Default, Serialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum Language {
    #[default]
    Roto,
    #[cfg(feature = "lua")]
    Lua,
    #[cfg(feature = "lua")]
    Fennel,
}

impl Display for Language {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let lang = match self {
            Self::Roto => "roto",
            #[cfg(feature = "lua")]
            Self::Lua => "lua",
            #[cfg(feature = "lua")]
            Self::Fennel => "fennel",
        };
        write!(f, "{lang}")
    }
}

pub fn create<P: AsRef<Path>, C: AsRef<Path>, S: Serialize>(
    language: Language,
    compiler: Option<C>,
    path: Option<P>,
    initial_seed: &str,
    metrics: &TenXProgrammer,
    config: Option<S>,
) -> anyhow::Result<NPC> {
    let Some(path) = path else {
        #[cfg(feature = "lua")]
        let dungeon: NPC = if language == Language::Lua {
            Box::new(Howl::new_default(initial_seed, metrics, config)?)
        } else {
            Box::new(MeansOfProduction::new_default(
                initial_seed,
                metrics,
                config,
            )?)
        };
        #[cfg(not(feature = "lua"))]
        let dungeon: NPC = Box::new(MeansOfProduction::new_default(
            initial_seed,
            metrics,
            config,
        )?);
        return Ok(dungeon);
    };
    let dungeon: NPC = match language {
        Language::Roto => Box::new(MeansOfProduction::new(
            path,
            compiler,
            initial_seed,
            metrics,
            config,
        )?),
        #[cfg(feature = "lua")]
        Language::Lua => Box::new(Howl::new(path, compiler, initial_seed, metrics, config)?),
        #[cfg(feature = "lua")]
        Language::Fennel => Box::new(ElegantWeapons::new(
            path,
            compiler,
            initial_seed,
            metrics,
            config,
        )?),
    };
    Ok(dungeon)
}