use crate::any::Any;
use crate::error::*;
use crate::k::K;
use crate::k_error::KError;
use crate::k_type::ERROR;
use crate::kapi;
use crate::kbox::KBox;
use std::ffi::CString;
use std::ptr;
fn null() -> *const K {
ptr::null()
}
macro_rules! evaluate {
($conn: expr, $func: expr $(, $param:expr)*,) => {
evaluate!($conn, $func $(, $expr)*);
};
($conn: expr, $func: expr $(, $param:expr)*) => {
{
let result = unsafe { kapi::k($conn, CString::new($func).unwrap().as_ptr() $(, $param.into_raw() as *const K)*, null()) };
if result.is_null() {
Err(Error::NetworkError)
} else if $conn > 0 && unsafe { (*result).t == ERROR } {
let err = unsafe{ KBox::<KError>::from_raw(result) }.into();
Err(err)
} else {
Ok(result)
}
}
};
}
fn from_raw(k: *mut K) -> KBox<Any> {
unsafe { KBox::from_raw(k) }
}
pub struct Connection(i32);
impl Connection {
#[cfg(not(feature = "embedded"))]
pub fn connect(
hostname: &str,
port: u16,
credentials: &str,
timeout: Option<std::time::Duration>,
) -> Result<Self, ConnectionError> {
let c_hostname = CString::new(hostname).unwrap();
let c_credentials = CString::new(credentials).unwrap();
let result = if let Some(duration) = timeout {
let secs = duration.as_secs() as i32;
unsafe { kapi::khpun(c_hostname.as_ptr(), port as i32, c_credentials.as_ptr(), secs) }
} else {
unsafe { kapi::khpu(c_hostname.as_ptr(), port as i32, c_credentials.as_ptr()) }
};
match result {
0 => Err(ConnectionError::BadCredentials),
-1 => Err(ConnectionError::CouldNotConnect),
-2 => Err(ConnectionError::Timeout),
x => Ok(Self(x)),
}
}
#[cfg(any(feature = "embedded", doc))]
pub fn new() -> Self {
Connection(0)
}
#[cfg(any(not(feature = "embedded"), doc))]
pub fn publish(
&self,
callback: &str,
topic: impl Into<KBox<Any>>,
object: impl Into<KBox<Any>>,
) -> Result<(), Error> {
evaluate!(-self.0, callback, topic.into(), object.into()).map(|_| ())
}
pub fn eval(&self, query: &str) -> Result<KBox<Any>, Error> {
evaluate!(self.0, query).map(from_raw)
}
pub fn eval_1(&self, function: &str, param: impl Into<KBox<Any>>) -> Result<KBox<Any>, Error> {
evaluate!(self.0, function, param.into()).map(from_raw)
}
pub fn eval_2(
&self,
function: &str,
param: impl Into<KBox<Any>>,
param_2: impl Into<KBox<Any>>,
) -> Result<KBox<Any>, Error> {
evaluate!(self.0, function, param.into(), param_2.into()).map(from_raw)
}
pub fn eval_3(
&self,
function: &str,
param: impl Into<KBox<Any>>,
param_2: impl Into<KBox<Any>>,
param_3: impl Into<KBox<Any>>,
) -> Result<KBox<Any>, Error> {
evaluate!(self.0, function, param.into(), param_2.into(), param_3.into()).map(from_raw)
}
pub fn eval_4(
&self,
function: &str,
param: impl Into<KBox<Any>>,
param_2: impl Into<KBox<Any>>,
param_3: impl Into<KBox<Any>>,
param_4: impl Into<KBox<Any>>,
) -> Result<KBox<Any>, Error> {
evaluate!(
self.0,
function,
param.into(),
param_2.into(),
param_3.into(),
param_4.into()
)
.map(from_raw)
}
pub fn eval_5(
&self,
function: &str,
param: impl Into<KBox<Any>>,
param_2: impl Into<KBox<Any>>,
param_3: impl Into<KBox<Any>>,
param_4: impl Into<KBox<Any>>,
param_5: impl Into<KBox<Any>>,
) -> Result<KBox<Any>, Error> {
evaluate!(
self.0,
function,
param.into(),
param_2.into(),
param_3.into(),
param_4.into(),
param_5.into()
)
.map(from_raw)
}
#[allow(clippy::clippy::too_many_arguments)]
pub fn eval_6(
&self,
function: &str,
param: impl Into<KBox<Any>>,
param_2: impl Into<KBox<Any>>,
param_3: impl Into<KBox<Any>>,
param_4: impl Into<KBox<Any>>,
param_5: impl Into<KBox<Any>>,
param_6: impl Into<KBox<Any>>,
) -> Result<KBox<Any>, Error> {
evaluate!(
self.0,
function,
param.into(),
param_2.into(),
param_3.into(),
param_4.into(),
param_5.into(),
param_6.into()
)
.map(from_raw)
}
#[allow(clippy::clippy::too_many_arguments)]
pub fn eval_7(
&self,
function: &str,
param: impl Into<KBox<Any>>,
param_2: impl Into<KBox<Any>>,
param_3: impl Into<KBox<Any>>,
param_4: impl Into<KBox<Any>>,
param_5: impl Into<KBox<Any>>,
param_6: impl Into<KBox<Any>>,
param_7: impl Into<KBox<Any>>,
) -> Result<KBox<Any>, Error> {
evaluate!(
self.0,
function,
param.into(),
param_2.into(),
param_3.into(),
param_4.into(),
param_5.into(),
param_6.into(),
param_7.into()
)
.map(from_raw)
}
#[allow(clippy::clippy::too_many_arguments)]
pub fn eval_8(
&self,
function: &str,
param: impl Into<KBox<Any>>,
param_2: impl Into<KBox<Any>>,
param_3: impl Into<KBox<Any>>,
param_4: impl Into<KBox<Any>>,
param_5: impl Into<KBox<Any>>,
param_6: impl Into<KBox<Any>>,
param_7: impl Into<KBox<Any>>,
param_8: impl Into<KBox<Any>>,
) -> Result<KBox<Any>, Error> {
evaluate!(
self.0,
function,
param.into(),
param_2.into(),
param_3.into(),
param_4.into(),
param_5.into(),
param_6.into(),
param_7.into(),
param_8.into()
)
.map(from_raw)
}
}
impl Drop for Connection {
#[cfg(not(feature = "embedded"))]
fn drop(&mut self) {
unsafe {
kapi::kclose(self.0);
}
}
#[cfg(feature = "embedded")]
fn drop(&mut self) {}
}
#[cfg(feature = "embedded")]
impl Default for Connection {
fn default() -> Self {
Connection(0)
}
}