//! demo_project — an aura research project: node logic + the exported vocabulary.
//!
//! Every node type this crate provides is registered in `vocabulary()` /
//! `type_ids()` under the `demo_project::` namespace prefix; the `aura` host loads
//! this cdylib per invocation and merges it with the std vocabulary.

use aura_core::{
    Cell, Ctx, FieldSpec, Firing, Node, NodeSchema, PortSpec, PrimitiveBuilder,
    ScalarKind,
};

/// One-input f64 pass-through. Emits `None` until its input has a value.
pub struct Identity {
    out: [Cell; 1],
}

impl Identity {
    pub fn new() -> Self {
        Self { out: [Cell::from_f64(0.0)] }
    }
    pub fn builder() -> PrimitiveBuilder {
        PrimitiveBuilder::new(
            "demo_project::Identity",
            NodeSchema {
                inputs: vec![PortSpec {
                    kind: ScalarKind::F64,
                    firing: Firing::Any,
                    name: "value".into(),
                }],
                output: vec![FieldSpec { name: "value".into(), kind: ScalarKind::F64 }],
                params: vec![],
            },
            |_| Box::new(Identity::new()),
        )
    }
}

impl Default for Identity {
    fn default() -> Self {
        Self::new()
    }
}

impl Node for Identity {
    fn lookbacks(&self) -> Vec<usize> {
        vec![1]
    }
    fn eval(&mut self, ctx: Ctx<'_>) -> Option<&[Cell]> {
        let w = ctx.f64_in(0);
        if w.is_empty() {
            return None;
        }
        self.out[0] = Cell::from_f64(w[0]);
        Some(&self.out)
    }
    fn label(&self) -> String {
        "demo_project::Identity".to_string()
    }
}

fn vocabulary(type_id: &str) -> Option<PrimitiveBuilder> {
    match type_id {
        "demo_project::Identity" => Some(Identity::builder()),
        _ => None,
    }
}

fn type_ids() -> &'static [&'static str] {
    &["demo_project::Identity"]
}

aura_core::aura_project! {
    namespace: "demo_project",
    vocabulary: vocabulary,
    type_ids: type_ids,
}
