use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use rill_core::math::Transcendental;
use rill_core::queues::CommandEnum;
use rill_core::time::ClockTick;
use rill_core_actor::{ActorRef, ActorSystem};
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>>>,
}
impl<T: Transcendental, const BUF: usize> GraphConstructor<T, BUF> {
pub fn new(node_factory: Arc<Mutex<NodeFactory<T, BUF>>>) -> Self {
Self { node_factory }
}
#[allow(clippy::type_complexity)]
pub fn run(
&self,
def: &GraphDef,
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 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()));
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(graph) => {
let _ = graph_tx.send(graph.handle());
let mut state = graph.into_processing_state();
let tick = ClockTick::default();
let _ = state.process_block(&tick);
while running.load(Ordering::Acquire) {
std::thread::park();
}
}
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))
}
}