use cxx::UniquePtr;
use std::fmt;
use crate::{bridge, Result, Value};
#[derive(Debug, Clone, PartialEq)]
pub enum MonitorEvent {
Connected(String),
Disconnected(String),
Finished(String),
RemoteError(String),
ClientError(String),
}
impl fmt::Display for MonitorEvent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MonitorEvent::Connected(msg) => write!(f, "Monitor connected: {}", msg),
MonitorEvent::Disconnected(msg) => write!(f, "Monitor disconnected: {}", msg),
MonitorEvent::Finished(msg) => write!(f, "Monitor finished: {}", msg),
MonitorEvent::RemoteError(msg) => write!(f, "Monitor remote error: {}", msg),
MonitorEvent::ClientError(msg) => write!(f, "Monitor client error: {}", msg),
}
}
}
impl std::error::Error for MonitorEvent {}
pub struct Context {
inner: UniquePtr<bridge::ContextWrapper>,
}
impl Context {
pub fn from_env() -> Result<Self> {
let inner = bridge::create_context_from_env()?;
Ok(Self { inner })
}
pub fn get(&mut self, pv_name: &str, timeout: f64) -> Result<Value> {
let inner = bridge::context_get(self.inner.pin_mut(), pv_name, timeout)?;
Ok(Value { inner })
}
pub fn put_double(&mut self, pv_name: &str, value: f64, timeout: f64) -> Result<()> {
bridge::context_put_double(self.inner.pin_mut(), pv_name, value, timeout)?;
Ok(())
}
pub fn put_int32(&mut self, pv_name: &str, value: i32, timeout: f64) -> Result<()> {
bridge::context_put_int32(self.inner.pin_mut(), pv_name, value, timeout)?;
Ok(())
}
pub fn put_string(&mut self, pv_name: &str, value: &str, timeout: f64) -> Result<()> {
bridge::context_put_string(self.inner.pin_mut(), pv_name, value.to_string(), timeout)?;
Ok(())
}
pub fn put_enum(&mut self, pv_name: &str, value: i16, timeout: f64) -> Result<()> {
bridge::context_put_enum(self.inner.pin_mut(), pv_name, value, timeout)?;
Ok(())
}
pub fn put_double_array(&mut self, pv_name: &str, value: Vec<f64>, timeout: f64) -> Result<()> {
bridge::context_put_double_array(self.inner.pin_mut(), pv_name, value, timeout)?;
Ok(())
}
pub fn put_int32_array(&mut self, pv_name: &str, value: Vec<i32>, timeout: f64) -> Result<()> {
bridge::context_put_int32_array(self.inner.pin_mut(), pv_name, value, timeout)?;
Ok(())
}
pub fn put_string_array(
&mut self,
pv_name: &str,
value: Vec<String>,
timeout: f64,
) -> Result<()> {
bridge::context_put_string_array(self.inner.pin_mut(), pv_name, value, timeout)?;
Ok(())
}
pub fn info(&mut self, pv_name: &str, timeout: f64) -> Result<Value> {
let inner = bridge::context_info(self.inner.pin_mut(), pv_name, timeout)?;
Ok(Value { inner })
}
pub fn rpc(&mut self, pv_name: &str) -> Result<Rpc> {
let inner = bridge::context_rpc_create(self.inner.pin_mut(), pv_name.to_string())?;
Ok(Rpc { inner })
}
pub fn monitor(&mut self, pv_name: &str) -> Result<Monitor> {
let inner = bridge::context_monitor_create(self.inner.pin_mut(), pv_name.to_string())?;
Ok(Monitor { inner })
}
pub fn monitor_builder(&mut self, pv_name: &str) -> Result<MonitorBuilder> {
let inner =
bridge::context_monitor_builder_create(self.inner.pin_mut(), pv_name.to_string())?;
Ok(MonitorBuilder { inner })
}
}
unsafe impl Send for Context {}
unsafe impl Sync for Context {}
#[cfg(feature = "async")]
impl Context {
pub async fn get_async(&mut self, pv_name: &str, timeout: f64) -> Result<Value> {
let operation = bridge::context_get_async(self.inner.pin_mut(), pv_name, timeout)?;
self.wait_for_operation(operation).await
}
pub async fn put_double_async(
&mut self,
pv_name: &str,
value: f64,
timeout: f64,
) -> Result<()> {
let operation =
bridge::context_put_double_async(self.inner.pin_mut(), pv_name, value, timeout)?;
self.wait_for_operation(operation).await?;
Ok(())
}
pub async fn info_async(&mut self, pv_name: &str, timeout: f64) -> Result<Value> {
let operation = bridge::context_info_async(self.inner.pin_mut(), pv_name, timeout)?;
self.wait_for_operation(operation).await
}
async fn wait_for_operation(
&self,
mut operation: cxx::UniquePtr<bridge::OperationWrapper>,
) -> Result<Value> {
use tokio::time::{sleep, Duration};
loop {
if bridge::operation_is_done(&operation) {
let result = bridge::operation_get_result(operation.pin_mut())?;
return Ok(Value { inner: result });
}
sleep(Duration::from_millis(10)).await;
}
}
}
pub struct Monitor {
inner: UniquePtr<bridge::MonitorWrapper>,
}
impl Monitor {
pub fn start(&mut self) -> Result<()> {
bridge::monitor_start(self.inner.pin_mut())?;
Ok(())
}
pub fn stop(&mut self) -> Result<()> {
bridge::monitor_stop(self.inner.pin_mut())?;
Ok(())
}
pub fn is_running(&self) -> bool {
bridge::monitor_is_running(&self.inner)
}
pub fn has_update(&self) -> bool {
bridge::monitor_has_update(&self.inner)
}
pub fn get_update(&mut self, timeout: f64) -> Result<Value> {
let value_wrapper = bridge::monitor_get_update(self.inner.pin_mut(), timeout)?;
Ok(Value {
inner: value_wrapper,
})
}
pub fn try_get_update(&mut self) -> Result<Option<Value>> {
match bridge::monitor_try_get_update(self.inner.pin_mut()) {
Ok(value_wrapper) => {
if value_wrapper.is_null() {
Ok(None)
} else {
Ok(Some(Value {
inner: value_wrapper,
}))
}
}
Err(_) => Ok(None), }
}
pub fn pop(&mut self) -> std::result::Result<Option<Value>, MonitorEvent> {
match bridge::monitor_pop(self.inner.pin_mut()) {
Ok(value_wrapper) => {
if value_wrapper.is_null() {
Ok(None)
} else {
Ok(Some(Value {
inner: value_wrapper,
}))
}
}
Err(e) => {
let err_msg = e.what();
if err_msg.contains("Monitor connected:") {
Err(MonitorEvent::Connected(err_msg.to_string()))
} else if err_msg.contains("Monitor disconnected:") {
Err(MonitorEvent::Disconnected(err_msg.to_string()))
} else if err_msg.contains("Monitor finished:") {
Err(MonitorEvent::Finished(err_msg.to_string()))
} else if err_msg.contains("Monitor remote error:") {
Err(MonitorEvent::RemoteError(err_msg.to_string()))
} else if err_msg.contains("Monitor client error:") {
Err(MonitorEvent::ClientError(err_msg.to_string()))
} else {
Err(MonitorEvent::ClientError(err_msg.to_string()))
}
}
}
}
pub fn is_connected(&self) -> bool {
bridge::monitor_is_connected(&self.inner)
}
pub fn name(&self) -> String {
bridge::monitor_get_name(&self.inner)
}
}
pub struct MonitorBuilder {
inner: UniquePtr<bridge::MonitorBuilderWrapper>,
}
impl MonitorBuilder {
pub fn connect_exception(mut self, enable: bool) -> Self {
let _ = bridge::monitor_builder_mask_connected(self.inner.pin_mut(), !enable);
self
}
pub fn disconnect_exception(mut self, enable: bool) -> Self {
let _ = bridge::monitor_builder_mask_disconnected(self.inner.pin_mut(), !enable);
self
}
pub fn event(mut self, callback: extern "C" fn()) -> Self {
let callback_ptr = callback as usize;
let _ = bridge::monitor_builder_set_event_callback(self.inner.pin_mut(), callback_ptr);
self
}
pub fn exec(mut self) -> Result<Monitor> {
let inner = bridge::monitor_builder_exec(self.inner.pin_mut())?;
Ok(Monitor { inner })
}
pub fn exec_with_callback(mut self, callback_id: u64) -> Result<Monitor> {
let inner = bridge::monitor_builder_exec_with_callback(self.inner.pin_mut(), callback_id)?;
Ok(Monitor { inner })
}
}
pub struct Rpc {
inner: UniquePtr<bridge::RpcWrapper>,
}
impl Rpc {
pub fn arg_string(&mut self, name: &str, value: &str) -> Result<&mut Self> {
bridge::rpc_arg_string(self.inner.pin_mut(), name.to_string(), value.to_string())?;
Ok(self)
}
pub fn arg_double(&mut self, name: &str, value: f64) -> Result<&mut Self> {
bridge::rpc_arg_double(self.inner.pin_mut(), name.to_string(), value)?;
Ok(self)
}
pub fn arg_int32(&mut self, name: &str, value: i32) -> Result<&mut Self> {
bridge::rpc_arg_int32(self.inner.pin_mut(), name.to_string(), value)?;
Ok(self)
}
pub fn arg_bool(&mut self, name: &str, value: bool) -> Result<&mut Self> {
bridge::rpc_arg_bool(self.inner.pin_mut(), name.to_string(), value)?;
Ok(self)
}
pub fn execute(mut self, timeout: f64) -> Result<Value> {
let inner = bridge::rpc_execute_sync(self.inner.pin_mut(), timeout)?;
Ok(Value { inner })
}
}
#[cfg(feature = "async")]
impl Rpc {
pub async fn execute_async(mut self, timeout: f64) -> Result<Value> {
use tokio::time::{sleep, Duration};
let mut operation = bridge::rpc_execute_async(self.inner.pin_mut(), timeout)?;
loop {
if bridge::operation_is_done(&operation) {
let result = bridge::operation_get_result(operation.pin_mut())?;
return Ok(Value { inner: result });
}
sleep(Duration::from_millis(10)).await;
}
}
}