use dora_node_api::{self, Event, EventStream}; use eyre::bail; #[cxx::bridge] #[allow(clippy::needless_lifetimes)] mod ffi { struct DoraNode { events: Box, send_output: Box, } pub enum DoraEventType { Stop, Input, InputClosed, Error, Unknown, AllInputsClosed, } struct DoraInput { id: String, data: Vec, } struct DoraResult { error: String, } extern "Rust" { type Events; type OutputSender; type DoraEvent<'a>; fn init_dora_node() -> Result; fn next_event(inputs: &mut Box) -> Box>; fn event_type(event: &Box) -> DoraEventType; fn event_as_input(event: Box) -> Result; fn send_output( output_sender: &mut Box, id: String, data: &[u8], ) -> DoraResult; } } fn init_dora_node() -> eyre::Result { let (node, events) = dora_node_api::DoraNode::init_from_env()?; let events = Events(events); let send_output = OutputSender(node); Ok(ffi::DoraNode { events: Box::new(events), send_output: Box::new(send_output), }) } pub struct Events(EventStream); fn next_event(events: &mut Box) -> Box { Box::new(DoraEvent(events.0.recv())) } pub struct DoraEvent<'a>(Option>); fn event_type(event: &DoraEvent) -> ffi::DoraEventType { match &event.0 { Some(event) => match event { Event::Stop => ffi::DoraEventType::Stop, Event::Input { .. } => ffi::DoraEventType::Input, Event::InputClosed { .. } => ffi::DoraEventType::InputClosed, Event::Error(_) => ffi::DoraEventType::Error, _ => ffi::DoraEventType::Unknown, }, None => ffi::DoraEventType::AllInputsClosed, } } fn event_as_input(event: Box) -> eyre::Result { let Some(Event::Input { id, metadata: _, data }) = event.0 else { bail!("not an input event"); }; Ok(ffi::DoraInput { id: id.into(), data: data.map(|d| d.to_owned()).unwrap_or_default(), }) } pub struct OutputSender(dora_node_api::DoraNode); fn send_output(sender: &mut Box, id: String, data: &[u8]) -> ffi::DoraResult { let result = sender .0 .send_output(id.into(), Default::default(), data.len(), |out| { out.copy_from_slice(data) }); let error = match result { Ok(()) => String::new(), Err(err) => format!("{err:?}"), }; ffi::DoraResult { error } }