use enum_dispatch::enum_dispatch; use std::fmt; use crate::library; use crate::library::*; use crate::types::{Type, TypeSignature}; /// an instantiable Node, parametrized by its connected input types #[enum_dispatch] pub trait ConcreteNode { fn max_inputs(&self) -> usize; // set of possible input type combinations given current connections fn signatures_matching(&self, connected: &[Option]) -> Vec; fn signature(&self, connected: &[Option]) -> TypeSignature; fn compile( &self, signature: TypeSignature, inputs: Vec, outputs: Vec, f: &mut dyn fmt::Write, ) -> fmt::Result; fn show_body(&mut self, ui: &mut egui::Ui) -> egui::Response { ui.response() } } #[enum_dispatch(ConcreteNode)] #[derive(Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub enum AnyNode { Constant(library::AnyConstant), Conversion(library::Conversion), Input(library::Input), Builtin(library::BuiltinFunction), Output(library::Output), } impl NodeIndex for AnyNode { const TITLE: &'static str = ""; fn all() -> impl Iterator { (library::AnyConstant::all().map(AnyNode::from)) .chain(library::Conversion::all().map(AnyNode::from)) .chain(library::Input::all().map(AnyNode::from)) .chain(library::Output::all().map(AnyNode::from)) .chain(library::BuiltinFunction::all().map(AnyNode::from)) } fn pick_node(ui: &mut egui::Ui) -> Option { ui.label("Add node"); let a = library::AnyConstant::pick_node(ui).map(AnyNode::from); let b = library::Conversion::pick_node(ui).map(AnyNode::from); let c = library::Input::pick_node(ui).map(AnyNode::from); let d = library::Output::pick_node(ui).map(AnyNode::from); let e = library::BuiltinFunction::pick_node(ui).map(AnyNode::from); a.or(b).or(c).or(d).or(e) } } impl fmt::Display for AnyNode { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Constant(x) => fmt::Display::fmt(x, f), Self::Conversion(x) => fmt::Display::fmt(x, f), Self::Input(x) => fmt::Display::fmt(x, f), Self::Builtin(x) => fmt::Display::fmt(x, f), Self::Output(x) => fmt::Display::fmt(x, f), } } }