#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(dead_code)]
pub mod error;
pub mod ffi;
pub mod types;
pub mod query;
pub mod ipc;
pub use error::{RayforceError, Result};
pub use ffi::RayObj;
pub use types::*;
pub use ipc::{Connection, hopen};
use std::ffi::CString;
use std::os::raw::c_char;
use std::ptr;
use std::sync::Once;
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
static INIT: Once = Once::new();
static mut RUNTIME: *mut runtime_t = ptr::null_mut();
pub struct RayforceBuilder {
args: Vec<CString>,
}
impl RayforceBuilder {
pub fn new() -> Self {
Self {
args: vec![CString::new("rayforce").unwrap()],
}
}
pub fn with_arg(mut self, arg: &str) -> Self {
self.args.push(CString::new(arg).unwrap());
self
}
pub fn build(self) -> Result<Rayforce> {
unsafe {
let mut c_args: Vec<*mut c_char> = self
.args
.iter()
.map(|arg| arg.as_ptr() as *mut c_char)
.collect();
c_args.push(ptr::null_mut());
let runtime = runtime_create(c_args.len() as i32 - 1, c_args.as_mut_ptr());
if !runtime.is_null() {
RUNTIME = runtime;
Ok(Rayforce { runtime })
} else {
Err(RayforceError::RuntimeCreationFailed)
}
}
}
}
impl Default for RayforceBuilder {
fn default() -> Self {
Self::new()
}
}
pub struct Rayforce {
runtime: *mut runtime_t,
}
unsafe impl Send for Rayforce {}
unsafe impl Sync for Rayforce {}
impl Rayforce {
pub fn new() -> Result<Self> {
RayforceBuilder::new().with_arg("-r").with_arg("0").build()
}
pub fn builder() -> RayforceBuilder {
RayforceBuilder::new()
}
pub fn version(&self) -> u8 {
unsafe { version() }
}
pub fn run(&self) -> i32 {
unsafe { runtime_run() }
}
pub fn as_ptr(&self) -> *mut runtime_t {
self.runtime
}
pub fn eval(&self, code: &str) -> Result<RayObj> {
let c_str = CString::new(code).map_err(|_| RayforceError::InvalidString)?;
unsafe {
let obj = eval_str(c_str.as_ptr());
if obj.is_null() {
Err(RayforceError::EvalFailed("Evaluation returned null".into()))
} else if (*obj).type_ == TYPE_ERR as i8 {
let error_msg = ffi::get_error_message(obj);
Err(RayforceError::EvalFailed(error_msg))
} else {
Ok(RayObj::from_raw(obj))
}
}
}
pub fn eval_obj(&self, obj: &RayObj) -> Result<RayObj> {
unsafe {
let cloned = clone_obj(obj.as_ptr());
let result = eval_obj(cloned);
if result.is_null() {
Err(RayforceError::EvalFailed("Evaluation returned null".into()))
} else if (*result).type_ == TYPE_ERR as i8 {
let error_msg = ffi::get_error_message(result);
Err(RayforceError::EvalFailed(error_msg))
} else {
Ok(RayObj::from_raw(result))
}
}
}
}
impl Drop for Rayforce {
fn drop(&mut self) {
unsafe {
runtime_destroy();
RUNTIME = ptr::null_mut();
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_runtime() {
let rf = Rayforce::new().unwrap();
assert!(!rf.as_ptr().is_null());
let v = rf.version();
assert!(v > 0);
let result = rf.eval("42").unwrap();
let val: i64 = result.try_into().unwrap();
assert_eq!(val, 42);
}
}