From b2577acf141a409fa61b7c710a9cb6a9cc9b134d Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Fri, 5 Aug 2022 20:11:42 +0200 Subject: [PATCH] Implement API functions for reading inputs and sending outputs --- Cargo.lock | 1 + apis/c/node/Cargo.toml | 1 + apis/c/node/src/lib.rs | 103 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 96 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6b460a9c..94078b0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -701,6 +701,7 @@ name = "dora-node-api-c" version = "0.1.0" dependencies = [ "dora-node-api", + "eyre", "futures", ] diff --git a/apis/c/node/Cargo.toml b/apis/c/node/Cargo.toml index 791ad4d1..fdde7b99 100644 --- a/apis/c/node/Cargo.toml +++ b/apis/c/node/Cargo.toml @@ -10,4 +10,5 @@ crate-type = ["staticlib"] [dependencies] dora-node-api = { path = "../../rust/node" } +eyre = "0.6.8" futures = "0.3.21" diff --git a/apis/c/node/src/lib.rs b/apis/c/node/src/lib.rs index be53ee5f..6fddfca4 100644 --- a/apis/c/node/src/lib.rs +++ b/apis/c/node/src/lib.rs @@ -1,21 +1,106 @@ -use std::ptr; +use dora_node_api::{DoraNode, Input}; +use futures::{executor::block_on, Stream, StreamExt}; +use std::{pin::Pin, ptr, slice}; -use dora_node_api::DoraNode; -use futures::executor::block_on; +struct DoraContext { + node: &'static DoraNode, + inputs: Pin>>, +} -pub extern "C" fn init_dora_node_from_env() -> *mut () { - let node = match block_on(DoraNode::init_from_env()) { +pub extern "C" fn init_dora_context_from_env() -> *mut () { + let context = match block_on(async { + let node = DoraNode::init_from_env().await?; + let node = Box::leak(Box::new(node)); + let inputs: Pin>> = Box::pin(node.inputs().await?); + Ok(DoraContext { node, inputs }) + }) { Ok(n) => n, Err(err) => { + let err: eyre::Error = err; eprintln!("{err:?}"); return ptr::null_mut(); } }; - Box::into_raw(Box::new(node)).cast() + Box::into_raw(Box::new(context)).cast() +} + +pub extern "C" fn free_dora_context(context: *mut ()) { + let context: Box = unsafe { Box::from_raw(context.cast()) }; + // drop all fields except for `node` + let DoraContext { node, .. } = *context; + // convert the `'static` reference back to a Box, then drop it + let _ = unsafe { Box::from_raw(node as *const DoraNode as *mut DoraNode) }; +} + +pub extern "C" fn dora_next_input(context: *mut ()) -> *mut () { + let context: &mut DoraContext = unsafe { &mut *context.cast() }; + match block_on(context.inputs.next()) { + Some(input) => Box::into_raw(Box::new(input)).cast(), + None => ptr::null_mut(), + } +} + +pub extern "C" fn read_dora_input_id( + input: *const (), + out_ptr: *mut *const u8, + out_len: *mut usize, +) { + let input: &Input = unsafe { &*input.cast() }; + let id = input.id.as_str().as_bytes(); + let ptr = id.as_ptr(); + let len = id.len(); + unsafe { + *out_ptr = ptr; + *out_len = len; + } +} + +pub extern "C" fn read_dora_input_data( + input: *const (), + out_ptr: *mut *const u8, + out_len: *mut usize, +) { + let input: &Input = unsafe { &*input.cast() }; + let data = input.data.as_slice(); + let ptr = data.as_ptr(); + let len = data.len(); + unsafe { + *out_ptr = ptr; + *out_len = len; + } +} + +pub extern "C" fn free_dora_input(input: *mut ()) { + let _: Box = unsafe { Box::from_raw(input.cast()) }; +} + +pub extern "C" fn dora_send_output( + context: *mut (), + id_ptr: *const u8, + id_len: usize, + data_ptr: *const u8, + data_len: usize, +) -> isize { + match try_send_output(context, id_ptr, id_len, data_ptr, data_len) { + Ok(()) => 0, + Err(err) => { + eprintln!("{err:?}"); + -1 + } + } } -pub extern "C" fn free_dora_node(node: *mut ()) { - let node: Box = unsafe { Box::from_raw(node.cast()) }; - let _ = node; +fn try_send_output( + context: *mut (), + id_ptr: *const u8, + id_len: usize, + data_ptr: *const u8, + data_len: usize, +) -> eyre::Result<()> { + let context: &mut DoraContext = unsafe { &mut *context.cast() }; + let id = std::str::from_utf8(unsafe { slice::from_raw_parts(id_ptr, id_len) })?; + let output_id = id.to_owned().into(); + let data = unsafe { slice::from_raw_parts(data_ptr, data_len) }; + block_on(context.node.send_output(&output_id, data)) }