use std::sync::atomic::AtomicBool;
use std::sync::{Arc, Mutex};
use rill_core::math::Transcendental;
use rill_core::queues::CommandEnum;
use rill_core::traits::ParamValue;
use rill_core_actor::{ActorRef, ActorSystem};
use crate::backend_factory::BackendFactory;
use crate::serialization::GraphDef;
use crate::{GraphBuilder, NodeFactory};
#[derive(Debug, Clone)]
pub enum GraphBuildError {
BuildFailed(String),
}
pub struct GraphConstructor<T: Transcendental, const BUF: usize> {
node_factory: Arc<Mutex<NodeFactory<T, BUF>>>,
backend_factory: Arc<BackendFactory<T>>,
}
impl<T: Transcendental, const BUF: usize> GraphConstructor<T, BUF> {
pub fn new(
node_factory: Arc<Mutex<NodeFactory<T, BUF>>>,
backend_factory: Arc<BackendFactory<T>>,
) -> Self {
Self {
node_factory,
backend_factory,
}
}
#[allow(clippy::type_complexity)]
pub fn run(
&self,
def: &GraphDef,
default_backend: Option<(String, std::collections::HashMap<String, ParamValue>)>,
system: &Arc<ActorSystem>,
parent_ref: ActorRef<CommandEnum>,
running: Arc<AtomicBool>,
) -> Result<(std::thread::JoinHandle<()>, ActorRef<CommandEnum>), GraphBuildError> {
let nf = Arc::clone(&self.node_factory);
let bf = Arc::clone(&self.backend_factory);
let def = def.clone();
let sys = Arc::clone(system);
let (graph_tx, graph_rx) = std::sync::mpsc::channel();
let handle = std::thread::spawn(move || {
let mut builder = GraphBuilder::new(Arc::new(nf.lock().unwrap().clone()), bf);
if let Some((ref name, ref params)) = default_backend {
builder.set_default_backend(name.clone(), params.clone());
}
builder.set_parent_ref(parent_ref);
if let Err(e) = def.populate(&mut builder) {
log::error!("graph populate: {e}");
return;
}
match builder.build(&sys) {
Ok(mut graph) => {
let _ = graph_tx.send(graph.handle());
graph.run(running).ok();
}
Err(e) => log::error!("graph build: {e:?}"),
}
});
let graph_ref = graph_rx
.recv()
.map_err(|e| GraphBuildError::BuildFailed(format!("graph handle: {e}")))?;
Ok((handle, graph_ref))
}
}