Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 18 additions & 19 deletions bindings/c/src/custom_node.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
use std::ffi::{c_char, CString};

use anyhow::anyhow;

use zen_engine::handler::custom_node_adapter::{
CustomNodeAdapter, CustomNodeRequest, NoopCustomNode,
};
use zen_engine::handler::node::{NodeResponse, NodeResult};

use crate::languages::native::NativeCustomNode;
use anyhow::anyhow;
use std::ffi::{c_char, CString};
use std::future::Future;
use std::pin::Pin;
use zen_engine::nodes::custom::{CustomNodeAdapter, CustomNodeRequest, NoopCustomNode};
use zen_engine::nodes::{NodeResponse, NodeResult};

#[derive(Debug)]
pub(crate) enum DynamicCustomNode {
Expand All @@ -24,13 +21,15 @@ impl Default for DynamicCustomNode {
}

impl CustomNodeAdapter for DynamicCustomNode {
async fn handle(&self, request: CustomNodeRequest) -> NodeResult {
match self {
DynamicCustomNode::Noop(cn) => cn.handle(request).await,
DynamicCustomNode::Native(cn) => cn.handle(request).await,
#[cfg(feature = "go")]
DynamicCustomNode::Go(cn) => cn.handle(request).await,
}
fn handle(&self, request: CustomNodeRequest) -> Pin<Box<dyn Future<Output = NodeResult> + '_>> {
Box::pin(async move {
match self {
DynamicCustomNode::Noop(cn) => cn.handle(request).await,
DynamicCustomNode::Native(cn) => cn.handle(request).await,
#[cfg(feature = "go")]
DynamicCustomNode::Go(cn) => cn.handle(request).await,
}
})
}
}

Expand All @@ -41,19 +40,19 @@ pub struct ZenCustomNodeResult {
}

impl ZenCustomNodeResult {
pub fn into_node_result(self) -> NodeResult {
pub fn into_node_result(self) -> anyhow::Result<NodeResponse> {
let maybe_error = match self.error.is_null() {
false => Some(unsafe { CString::from_raw(self.error) }),
true => None,
};

if let Some(c_error) = maybe_error {
let maybe_str = c_error.to_str().unwrap_or("unknown error");
return Err(anyhow!("{maybe_str}").into());
return Err(anyhow!("{maybe_str}"));
}

if self.content.is_null() {
return Err(anyhow!("response not provided").into());
return Err(anyhow!("response not provided"));
}

let content_cstr = unsafe { CString::from_raw(self.content) };
Expand Down
10 changes: 4 additions & 6 deletions bindings/c/src/decision.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,19 @@ use std::marker::{PhantomData, PhantomPinned};
use std::ops::{Deref, DerefMut};
use zen_engine::Decision;

use crate::custom_node::DynamicCustomNode;
use crate::engine::ZenEngineEvaluationOptions;
use crate::error::ZenError;
use crate::loader::DynamicDecisionLoader;
use crate::mt::tokio_runtime;
use crate::result::ZenResult;

#[repr(C)]
pub(crate) struct ZenDecision {
_data: Decision<DynamicDecisionLoader, DynamicCustomNode>,
_data: Decision,
_marker: PhantomData<(*mut c_void, PhantomPinned)>,
}

impl Deref for ZenDecision {
type Target = Decision<DynamicDecisionLoader, DynamicCustomNode>;
type Target = Decision;

fn deref(&self) -> &Self::Target {
&self._data
Expand All @@ -31,8 +29,8 @@ impl DerefMut for ZenDecision {
}
}

impl From<Decision<DynamicDecisionLoader, DynamicCustomNode>> for ZenDecision {
fn from(value: Decision<DynamicDecisionLoader, DynamicCustomNode>) -> Self {
impl From<Decision> for ZenDecision {
fn from(value: Decision) -> Self {
Self {
_data: value,
_marker: PhantomData,
Expand Down
8 changes: 4 additions & 4 deletions bindings/c/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ use crate::loader::DynamicDecisionLoader;
use crate::mt::tokio_runtime;
use crate::result::ZenResult;

pub(crate) struct ZenEngine(DecisionEngine<DynamicDecisionLoader, DynamicCustomNode>);
pub(crate) struct ZenEngine(DecisionEngine);

impl Deref for ZenEngine {
type Target = DecisionEngine<DynamicDecisionLoader, DynamicCustomNode>;
type Target = DecisionEngine;

fn deref(&self) -> &Self::Target {
&self.0
Expand Down Expand Up @@ -59,8 +59,8 @@ pub struct ZenEngineEvaluationOptions {
impl Into<EvaluationOptions> for ZenEngineEvaluationOptions {
fn into(self) -> EvaluationOptions {
EvaluationOptions {
trace: Some(self.trace),
max_depth: Some(self.max_depth),
trace: self.trace,
max_depth: self.max_depth,
}
}
}
Expand Down
59 changes: 37 additions & 22 deletions bindings/c/src/languages/go.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
use anyhow::anyhow;
use std::ffi::{c_char, CString};
use std::future::Future;

use zen_engine::handler::custom_node_adapter::{CustomNodeAdapter, CustomNodeRequest};
use zen_engine::handler::node::NodeResult;
use zen_engine::loader::{DecisionLoader, LoaderError, LoaderResponse};

use crate::custom_node::{DynamicCustomNode, ZenCustomNodeResult};
use crate::engine::{ZenEngine, ZenEngineStruct};
use crate::loader::{DynamicDecisionLoader, ZenDecisionLoaderResult};
use std::ffi::{c_char, CString};
use std::future::Future;
use std::pin::Pin;
use zen_engine::loader::{DecisionLoader, LoaderError, LoaderResponse};
use zen_engine::nodes::custom::{CustomNodeAdapter, CustomNodeRequest};
use zen_engine::nodes::{NodeError, NodeResult};

#[derive(Debug, Default)]
pub(crate) struct GoDecisionLoader {
Expand All @@ -22,8 +20,11 @@ impl GoDecisionLoader {
}

impl DecisionLoader for GoDecisionLoader {
fn load<'a>(&'a self, key: &'a str) -> impl Future<Output = LoaderResponse> + 'a {
async move {
fn load<'a>(
&'a self,
key: &'a str,
) -> Pin<Box<dyn Future<Output = LoaderResponse> + Send + 'a>> {
Box::pin(async move {
let Some(handler) = &self.handler else {
return Err(LoaderError::NotFound(key.to_string()).into());
};
Expand All @@ -33,7 +34,7 @@ impl DecisionLoader for GoDecisionLoader {
unsafe { zen_engine_go_loader_callback(handler.clone(), c_key.as_ptr()) };

c_content_ptr.into_loader_response(key)
}
})
}
}

Expand All @@ -50,19 +51,33 @@ impl GoCustomNode {
}

impl CustomNodeAdapter for GoCustomNode {
async fn handle(&self, request: CustomNodeRequest) -> NodeResult {
let Some(handler) = self.handler else {
return Err(anyhow!("go handler not found").into());
};
fn handle(&self, request: CustomNodeRequest) -> Pin<Box<dyn Future<Output = NodeResult> + '_>> {
Box::pin(async move {
let Some(handler) = self.handler else {
return Err(NodeError {
node_id: request.node.id.clone(),
source: "go handler not found".into(),
trace: None,
});
};

let Ok(request_value) = serde_json::to_string(&request) else {
return Err(anyhow!("failed to serialize request json").into());
};
let Ok(request_value) = serde_json::to_string(&request) else {
return Err(NodeError {
node_id: request.node.id.clone(),
source: "failed to serialize request json".into(),
trace: None,
});
};

let c_request = unsafe { CString::from_vec_unchecked(request_value.into_bytes()) };
let c_node_result =
unsafe { zen_engine_go_custom_node_callback(handler, c_request.as_ptr()) };
c_node_result.into_node_result()
let c_request = unsafe { CString::from_vec_unchecked(request_value.into_bytes()) };
let c_node_result =
unsafe { zen_engine_go_custom_node_callback(handler, c_request.as_ptr()) };
c_node_result.into_node_result().map_err(|c_err| NodeError {
node_id: request.node.id.clone(),
source: c_err.into(),
trace: None,
})
})
}
}

Expand Down
47 changes: 29 additions & 18 deletions bindings/c/src/languages/native.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
use anyhow::anyhow;
use std::ffi::{c_char, CString};
use std::future::Future;

use zen_engine::handler::custom_node_adapter::{CustomNodeAdapter, CustomNodeRequest};
use zen_engine::handler::node::NodeResult;
use zen_engine::loader::{DecisionLoader, LoaderResponse};

use crate::custom_node::{DynamicCustomNode, ZenCustomNodeResult};
use crate::engine::{ZenEngine, ZenEngineStruct};
use crate::loader::{DynamicDecisionLoader, ZenDecisionLoaderResult};
use std::ffi::{c_char, CString};
use std::future::Future;
use std::pin::Pin;
use zen_engine::loader::{DecisionLoader, LoaderResponse};
use zen_engine::nodes::custom::{CustomNodeAdapter, CustomNodeRequest};
use zen_engine::nodes::{NodeError, NodeResult};

pub type ZenDecisionLoaderNativeCallback =
extern "C" fn(key: *const c_char) -> ZenDecisionLoaderResult;
Expand All @@ -27,13 +25,16 @@ impl NativeDecisionLoader {
}

impl DecisionLoader for NativeDecisionLoader {
fn load<'a>(&'a self, key: &'a str) -> impl Future<Output = LoaderResponse> + 'a {
async move {
fn load<'a>(
&'a self,
key: &'a str,
) -> Pin<Box<dyn Future<Output = LoaderResponse> + Send + 'a>> {
Box::pin(async move {
let c_key = CString::new(key).unwrap();
let c_content_ptr = (&self.callback)(c_key.as_ptr());

c_content_ptr.into_loader_response(key)
}
})
}
}

Expand All @@ -49,14 +50,24 @@ impl NativeCustomNode {
}

impl CustomNodeAdapter for NativeCustomNode {
async fn handle(&self, request: CustomNodeRequest) -> NodeResult {
let Ok(request_value) = serde_json::to_string(&request) else {
return Err(anyhow!("failed to serialize request json").into());
};
fn handle(&self, request: CustomNodeRequest) -> Pin<Box<dyn Future<Output = NodeResult> + '_>> {
Box::pin(async move {
let Ok(request_value) = serde_json::to_string(&request) else {
return Err(NodeError {
node_id: request.node.id.clone(),
trace: None,
source: "failed to serialize request json".into(),
});
};

let c_request = unsafe { CString::from_vec_unchecked(request_value.into_bytes()) };
let c_response_str = (&self.callback)(c_request.as_ptr());
c_response_str.into_node_result()
let c_request = unsafe { CString::from_vec_unchecked(request_value.into_bytes()) };
let c_response_str = (&self.callback)(c_request.as_ptr());
c_response_str.into_node_result().map_err(|err| NodeError {
node_id: request.node.id.clone(),
trace: None,
source: err.into(),
})
})
}
}

Expand Down
10 changes: 7 additions & 3 deletions bindings/c/src/loader.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::ffi::{c_char, CString};
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;

use anyhow::anyhow;
Expand All @@ -24,15 +25,18 @@ impl Default for DynamicDecisionLoader {
}

impl DecisionLoader for DynamicDecisionLoader {
fn load<'a>(&'a self, key: &'a str) -> impl Future<Output = LoaderResponse> + 'a {
async move {
fn load<'a>(
&'a self,
key: &'a str,
) -> Pin<Box<dyn Future<Output = LoaderResponse> + Send + 'a>> {
Box::pin(async move {
match self {
DynamicDecisionLoader::Noop(loader) => loader.load(key).await,
DynamicDecisionLoader::Native(loader) => loader.load(key).await,
#[cfg(feature = "go")]
DynamicDecisionLoader::Go(loader) => loader.load(key).await,
}
}
})
}
}

Expand Down
Loading
Loading