Files
zen/bindings/c/src/loader.rs
T
stefan-gorules daecf901e6 feat: custom node (#138)
* feat: custom node

* add zen template, expose $nodes and $root

* add custom handler to go and nodejs

* add support for python, improve bindings, add error to zen template

* fix: correct binding exports for nodejs and python

* fix benchmark

* improve rust api, trim template in zen templates

* update cargo action

* update expression version

* compile action

* fix action format
2024-04-03 16:09:51 +02:00

75 lines
2.2 KiB
Rust

use crate::languages::native::NativeDecisionLoader;
use anyhow::anyhow;
use async_trait::async_trait;
use std::ffi::{c_char, CStr, CString};
use std::sync::Arc;
use zen_engine::loader::{DecisionLoader, LoaderError, LoaderResponse, NoopLoader};
use zen_engine::model::DecisionContent;
#[derive(Debug)]
pub(crate) enum DynamicDecisionLoader {
Noop(NoopLoader),
Native(NativeDecisionLoader),
#[cfg(feature = "go")]
Go(crate::languages::go::GoDecisionLoader),
}
impl Default for DynamicDecisionLoader {
fn default() -> Self {
Self::Noop(Default::default())
}
}
#[async_trait]
impl DecisionLoader for DynamicDecisionLoader {
async fn load(&self, key: &str) -> LoaderResponse {
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,
}
}
}
#[repr(C)]
pub struct ZenDecisionLoaderResult {
content: *mut c_char,
error: *mut c_char,
}
impl ZenDecisionLoaderResult {
pub fn into_loader_response(self, key: &str) -> LoaderResponse {
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 {
return Err(LoaderError::Internal {
key: key.to_string(),
source: anyhow!(c_error.to_string_lossy().to_string()),
}
.into());
}
let maybe_content = match self.content.is_null() {
false => Some(unsafe { CStr::from_ptr(self.content) }),
true => None,
};
// If both pointers are null, we are treating it as not found
let Some(c_content) = maybe_content else {
return Err(LoaderError::NotFound(key.to_string()).into());
};
let decision_content: DecisionContent = serde_json::from_slice(c_content.to_bytes())
.map_err(|e| LoaderError::Internal {
key: key.to_string(),
source: anyhow!(e),
})?;
Ok(Arc::new(decision_content))
}
}