pub mod bridge;
use cxx::UniquePtr;
use std::fmt;
pub use bridge::{ContextWrapper, ValueWrapper, RpcWrapper, MonitorWrapper, MonitorBuilderWrapper, ServerWrapper, SharedPVWrapper, StaticSourceWrapper};
pub use std::sync::atomic::{AtomicUsize, Ordering};
pub type Result<T> = std::result::Result<T, PvxsError>;
#[derive(Debug, Clone)]
pub struct PvxsError {
message: String,
}
impl PvxsError {
pub fn new(message: impl Into<String>) -> Self {
Self {
message: message.into(),
}
}
}
impl fmt::Display for PvxsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "PVXS error: {}", self.message)
}
}
impl std::error::Error for PvxsError {}
impl From<cxx::Exception> for PvxsError {
fn from(e: cxx::Exception) -> Self {
Self::new(e.what())
}
}
#[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<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 Value {
inner: UniquePtr<ValueWrapper>,
}
impl Value {
pub fn is_valid(&self) -> bool {
bridge::value_is_valid(&self.inner)
}
pub fn get_field_double(&self, field_name: &str) -> Result<f64> {
Ok(bridge::value_get_field_double(&self.inner, field_name.to_string())?)
}
pub fn get_field_int32(&self, field_name: &str) -> Result<i32> {
Ok(bridge::value_get_field_int32(&self.inner, field_name.to_string())?)
}
pub fn get_field_string(&self, field_name: &str) -> Result<String> {
Ok(bridge::value_get_field_string(&self.inner, field_name.to_string())?)
}
pub fn get_field_enum(&self, field_name: &str) -> Result<i16> {
Ok(bridge::value_get_field_enum(&self.inner, field_name.to_string())?)
}
pub fn get_field_double_array(&self, field_name: &str) -> Result<Vec<f64>> {
Ok(bridge::value_get_field_double_array(&self.inner, field_name.to_string())?)
}
pub fn get_field_int32_array(&self, field_name: &str) -> Result<Vec<i32>> {
Ok(bridge::value_get_field_int32_array(&self.inner, field_name.to_string())?)
}
pub fn get_field_string_array(&self, field_name: &str) -> Result<Vec<String>> {
Ok(bridge::value_get_field_string_array(&self.inner, field_name.to_string())?)
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", bridge::value_to_string(&self.inner))
}
}
impl fmt::Debug for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Value")
.field("data", &bridge::value_to_string(&self.inner))
.finish()
}
}
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;
}
}
}
pub struct Server {
inner: UniquePtr<ServerWrapper>,
}
impl Server {
pub fn from_env() -> Result<Self> {
let inner = bridge::server_create_from_env()?;
Ok(Self { inner })
}
pub fn create_isolated() -> Result<Self> {
let inner = bridge::server_create_isolated()?;
Ok(Self { inner })
}
pub fn start(&mut self) -> Result<()> {
bridge::server_start(self.inner.pin_mut())?;
Ok(())
}
pub fn stop(&mut self) -> Result<()> {
bridge::server_stop(self.inner.pin_mut())?;
Ok(())
}
pub(crate) fn add_pv(&mut self, name: &str, pv: &mut SharedPV) -> Result<()> {
bridge::server_add_pv(self.inner.pin_mut(), name.to_string(), pv.inner.pin_mut())?;
Ok(())
}
pub fn remove_pv(&mut self, name: &str) -> Result<()> {
bridge::server_remove_pv(self.inner.pin_mut(), name.to_string())?;
Ok(())
}
pub fn add_source(&mut self, name: &str, source: &mut StaticSource, order: i32) -> Result<()> {
bridge::server_add_source(self.inner.pin_mut(), name.to_string(), source.inner.pin_mut(), order)?;
Ok(())
}
pub fn tcp_port(&self) -> u16 {
bridge::server_get_tcp_port(&self.inner)
}
pub fn udp_port(&self) -> u16 {
bridge::server_get_udp_port(&self.inner)
}
pub fn create_pv_double(&mut self, name: &str, initial_value: f64, metadata: NTScalarMetadataBuilder) -> Result<SharedPV> {
let mut pv = SharedPV::create_mailbox()?;
pv.open_double(initial_value, metadata)?;
self.add_pv(name, &mut pv)?;
Ok(pv)
}
pub fn create_pv_double_array(&mut self, name: &str, initial_value: Vec<f64>, metadata: NTScalarMetadataBuilder) -> Result<SharedPV> {
if initial_value.is_empty() {
return Err(PvxsError::new("Initial double array cannot be empty"));
}
let mut pv = SharedPV::create_mailbox()?;
pv.open_double_array(initial_value, metadata)?;
self.add_pv(name, &mut pv)?;
Ok(pv)
}
pub fn create_pv_int32(&mut self, name: &str, initial_value: i32, metadata: NTScalarMetadataBuilder) -> Result<SharedPV> {
let mut pv = SharedPV::create_mailbox()?;
pv.open_int32(initial_value, metadata)?;
self.add_pv(name, &mut pv)?;
Ok(pv)
}
pub fn create_pv_int32_array(&mut self, name: &str, initial_value: Vec<i32>, metadata: NTScalarMetadataBuilder) -> Result<SharedPV> {
if initial_value.is_empty() {
return Err(PvxsError::new("Initial int32 array cannot be empty"));
}
let mut pv = SharedPV::create_mailbox()?;
pv.open_int32_array(initial_value, metadata)?;
self.add_pv(name, &mut pv)?;
Ok(pv)
}
pub fn create_pv_string(&mut self, name: &str, initial_value: &str, metadata: NTScalarMetadataBuilder) -> Result<SharedPV> {
let mut pv = SharedPV::create_mailbox()?;
pv.open_string(initial_value, metadata)?;
self.add_pv(name, &mut pv)?;
Ok(pv)
}
pub fn create_pv_string_array(&mut self, name: &str, initial_value: Vec<String>, metadata: NTScalarMetadataBuilder) -> Result<SharedPV> {
if initial_value.is_empty() {
return Err(PvxsError::new("Initial string array cannot be empty"));
}
let mut pv = SharedPV::create_mailbox()?;
pv.open_string_array(initial_value, metadata)?;
self.add_pv(name, &mut pv)?;
Ok(pv)
}
pub fn create_pv_enum(&mut self, name: &str, choices: Vec<&str>, selected_index: i16, metadata: NTEnumMetadataBuilder) -> Result<SharedPV> {
let mut pv = SharedPV::create_mailbox()?;
pv.open_enum(choices, selected_index, metadata)?;
self.add_pv(name, &mut pv)?;
Ok(pv)
}
pub fn create_readonly_pv_double(&mut self, name: &str, initial_value: f64, metadata: NTScalarMetadataBuilder) -> Result<SharedPV> {
let mut pv = SharedPV::create_readonly()?;
pv.open_double(initial_value, metadata)?;
self.add_pv(name, &mut pv)?;
Ok(pv)
}
}
pub struct SharedPV {
inner: UniquePtr<SharedPVWrapper>,
}
impl SharedPV {
pub fn create_mailbox() -> Result<Self> {
let inner = bridge::shared_pv_create_mailbox()?;
Ok(Self { inner })
}
pub fn create_readonly() -> Result<Self> {
let inner = bridge::shared_pv_create_readonly()?;
Ok(Self { inner })
}
pub(crate) fn open_double(&mut self, initial_value: f64, metadata: NTScalarMetadataBuilder) -> Result<()> {
let meta = metadata.build()?;
bridge::shared_pv_open_double(self.inner.pin_mut(), initial_value, &meta)?;
Ok(())
}
pub(crate) fn open_double_array(&mut self, initial_value: Vec<f64>, metadata: NTScalarMetadataBuilder) -> Result<()> {
let meta = metadata.build()?;
bridge::shared_pv_open_double_array(self.inner.pin_mut(), initial_value, &meta)?;
Ok(())
}
pub(crate) fn open_enum(&mut self, choices: Vec<&str>, selected_index: i16, metadata: NTEnumMetadataBuilder) -> Result<()> {
let meta = metadata.build()?;
let choices_vec: Vec<String> = choices.iter().map(|s| s.to_string()).collect();
bridge::shared_pv_open_enum(self.inner.pin_mut(), choices_vec, selected_index, &meta)?;
Ok(())
}
pub(crate) fn open_int32(&mut self, initial_value: i32, metadata: NTScalarMetadataBuilder) -> Result<()> {
let meta = metadata.build()?;
bridge::shared_pv_open_int32(self.inner.pin_mut(), initial_value, &meta)?;
Ok(())
}
pub(crate) fn open_int32_array(&mut self, initial_value: Vec<i32>, metadata: NTScalarMetadataBuilder) -> Result<()> {
let meta = metadata.build()?;
bridge::shared_pv_open_int32_array(self.inner.pin_mut(), initial_value, &meta)?;
Ok(())
}
pub(crate) fn open_string(&mut self, initial_value: &str, metadata: NTScalarMetadataBuilder) -> Result<()> {
let meta = metadata.build()?;
bridge::shared_pv_open_string(self.inner.pin_mut(), initial_value.to_string(), &meta)?;
Ok(())
}
pub(crate) fn open_string_array(&mut self, initial_value: Vec<String>, metadata: NTScalarMetadataBuilder) -> Result<()> {
let meta = metadata.build()?;
bridge::shared_pv_open_string_array(self.inner.pin_mut(), initial_value, &meta)?;
Ok(())
}
pub fn is_open(&self) -> bool {
bridge::shared_pv_is_open(&self.inner)
}
pub fn close(&mut self) -> Result<()> {
bridge::shared_pv_close(self.inner.pin_mut())?;
Ok(())
}
pub fn post_double(&mut self, value: f64) -> Result<()> {
bridge::shared_pv_post_double(self.inner.pin_mut(), value)?;
Ok(())
}
pub fn post_int32(&mut self, value: i32) -> Result<()> {
bridge::shared_pv_post_int32(self.inner.pin_mut(), value)?;
Ok(())
}
pub fn post_string(&mut self, value: &str) -> Result<()> {
bridge::shared_pv_post_string(self.inner.pin_mut(), value.to_string())?;
Ok(())
}
pub fn post_enum(&mut self, value: i16) -> Result<()> {
bridge::shared_pv_post_enum(self.inner.pin_mut(), value)?;
Ok(())
}
pub fn post_double_array(&mut self, value: &[f64]) -> Result<()> {
if value.is_empty() {
return Err(PvxsError::new("Cannot post empty double array"));
}
bridge::shared_pv_post_double_array(self.inner.pin_mut(), value.to_vec())?;
Ok(())
}
pub fn post_int32_array(&mut self, value: &[i32]) -> Result<()> {
if value.is_empty() {
return Err(PvxsError::new("Cannot post empty int32 array"));
}
bridge::shared_pv_post_int32_array(self.inner.pin_mut(), value.to_vec())?;
Ok(())
}
pub fn post_string_array(&mut self, value: &[String]) -> Result<()> {
if value.is_empty() {
return Err(PvxsError::new("Cannot post empty string array"));
}
bridge::shared_pv_post_string_array(self.inner.pin_mut(), value.to_vec())?;
Ok(())
}
pub fn fetch(&self) -> Result<Value> {
let inner = bridge::shared_pv_fetch(&self.inner)?;
Ok(Value { inner })
}
}
pub struct StaticSource {
inner: UniquePtr<StaticSourceWrapper>,
}
impl StaticSource {
pub fn create() -> Result<Self> {
let inner = bridge::static_source_create()?;
Ok(Self { inner })
}
pub fn add_pv(&mut self, name: &str, pv: &mut SharedPV) -> Result<()> {
bridge::static_source_add_pv(self.inner.pin_mut(), name.to_string(), pv.inner.pin_mut())?;
Ok(())
}
pub fn remove_pv(&mut self, name: &str) -> Result<()> {
bridge::static_source_remove_pv(self.inner.pin_mut(), name.to_string())?;
Ok(())
}
pub fn close_all(&mut self) -> Result<()> {
bridge::static_source_close_all(self.inner.pin_mut())?;
Ok(())
}
}
pub struct NTScalarMetadataBuilder {
alarm_severity: i32,
alarm_status: i32,
alarm_message: String,
timestamp_seconds: i64,
timestamp_nanos: i32,
timestamp_user_tag: i32,
display: Option<DisplayMetadata>,
control: Option<ControlMetadata>,
value_alarm: Option<ValueAlarmMetadata>,
with_form: bool,
}
#[derive(Clone, Debug, Default)]
pub struct DisplayMetadata {
pub limit_low: i64,
pub limit_high: i64,
pub description: String,
pub units: String,
pub precision: i32,
}
#[derive(Clone, Debug, Default)]
pub struct ControlMetadata {
pub limit_low: f64,
pub limit_high: f64,
pub min_step: f64,
}
#[derive(Clone, Debug, Default)]
pub struct ValueAlarmMetadata {
pub active: bool,
pub low_alarm_limit: f64,
pub low_warning_limit: f64,
pub high_warning_limit: f64,
pub high_alarm_limit: f64,
pub low_alarm_severity: i32,
pub low_warning_severity: i32,
pub high_warning_severity: i32,
pub high_alarm_severity: i32,
pub hysteresis: u8,
}
impl NTScalarMetadataBuilder {
pub fn new() -> Self {
use std::time::{SystemTime, UNIX_EPOCH};
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
Self {
alarm_severity: 0,
alarm_status: 0,
alarm_message: String::new(),
timestamp_seconds: now.as_secs() as i64,
timestamp_nanos: now.subsec_nanos() as i32,
timestamp_user_tag: 0,
display: None,
control: None,
value_alarm: None,
with_form: false,
}
}
pub fn alarm(mut self, severity: i32, status: i32, message: impl Into<String>) -> Self {
self.alarm_severity = severity;
self.alarm_status = status;
self.alarm_message = message.into();
self
}
pub fn timestamp(mut self, seconds: i64, nanos: i32, user_tag: i32) -> Self {
self.timestamp_seconds = seconds;
self.timestamp_nanos = nanos;
self.timestamp_user_tag = user_tag;
self
}
pub fn display(mut self, meta: DisplayMetadata) -> Self {
self.display = Some(meta);
self
}
pub fn control(mut self, meta: ControlMetadata) -> Self {
self.control = Some(meta);
self
}
pub fn value_alarm(mut self, meta: ValueAlarmMetadata) -> Self {
self.value_alarm = Some(meta);
self
}
pub fn with_form(mut self, enable: bool) -> Self {
self.with_form = enable;
self
}
fn build(self) -> Result<cxx::UniquePtr<bridge::NTScalarMetadata>> {
let alarm = bridge::create_alarm(self.alarm_severity, self.alarm_status, self.alarm_message);
let time_stamp = bridge::create_time(self.timestamp_seconds, self.timestamp_nanos, self.timestamp_user_tag);
let metadata = match (&self.display, &self.control, &self.value_alarm) {
(None, None, None) => {
bridge::create_metadata_no_optional(&alarm, &time_stamp, self.with_form)
}
(Some(d), None, None) => {
let display = bridge::create_display(d.limit_low, d.limit_high, d.description.clone(), d.units.clone(), d.precision);
bridge::create_metadata_with_display(&alarm, &time_stamp, &display, self.with_form)
}
(None, Some(c), None) => {
let control = bridge::create_control(c.limit_low, c.limit_high, c.min_step);
bridge::create_metadata_with_control(&alarm, &time_stamp, &control, self.with_form)
}
(None, None, Some(v)) => {
let value_alarm = bridge::create_value_alarm(
v.active, v.low_alarm_limit, v.low_warning_limit,
v.high_warning_limit, v.high_alarm_limit,
v.low_alarm_severity, v.low_warning_severity,
v.high_warning_severity, v.high_alarm_severity, v.hysteresis
);
bridge::create_metadata_with_value_alarm(&alarm, &time_stamp, &value_alarm, self.with_form)
}
(Some(d), Some(c), None) => {
let display = bridge::create_display(d.limit_low, d.limit_high, d.description.clone(), d.units.clone(), d.precision);
let control = bridge::create_control(c.limit_low, c.limit_high, c.min_step);
bridge::create_metadata_with_display_control(&alarm, &time_stamp, &display, &control, self.with_form)
}
(Some(d), None, Some(v)) => {
let display = bridge::create_display(d.limit_low, d.limit_high, d.description.clone(), d.units.clone(), d.precision);
let value_alarm = bridge::create_value_alarm(
v.active, v.low_alarm_limit, v.low_warning_limit,
v.high_warning_limit, v.high_alarm_limit,
v.low_alarm_severity, v.low_warning_severity,
v.high_warning_severity, v.high_alarm_severity, v.hysteresis
);
bridge::create_metadata_with_display_value_alarm(&alarm, &time_stamp, &display, &value_alarm, self.with_form)
}
(None, Some(c), Some(v)) => {
let control = bridge::create_control(c.limit_low, c.limit_high, c.min_step);
let value_alarm = bridge::create_value_alarm(
v.active, v.low_alarm_limit, v.low_warning_limit,
v.high_warning_limit, v.high_alarm_limit,
v.low_alarm_severity, v.low_warning_severity,
v.high_warning_severity, v.high_alarm_severity, v.hysteresis
);
bridge::create_metadata_with_control_value_alarm(&alarm, &time_stamp, &control, &value_alarm, self.with_form)
}
(Some(d), Some(c), Some(v)) => {
let display = bridge::create_display(d.limit_low, d.limit_high, d.description.clone(), d.units.clone(), d.precision);
let control = bridge::create_control(c.limit_low, c.limit_high, c.min_step);
let value_alarm = bridge::create_value_alarm(
v.active, v.low_alarm_limit, v.low_warning_limit,
v.high_warning_limit, v.high_alarm_limit,
v.low_alarm_severity, v.low_warning_severity,
v.high_warning_severity, v.high_alarm_severity, v.hysteresis
);
bridge::create_metadata_full(&alarm, &time_stamp, &display, &control, &value_alarm, self.with_form)
}
};
Ok(metadata)
}
}
impl Default for NTScalarMetadataBuilder {
fn default() -> Self {
Self::new()
}
}
pub struct NTEnumMetadataBuilder {
alarm_severity: i32,
alarm_status: i32,
alarm_message: String,
timestamp_seconds: i64,
timestamp_nanos: i32,
timestamp_user_tag: i32,
}
impl NTEnumMetadataBuilder {
pub fn new() -> Self {
use std::time::{SystemTime, UNIX_EPOCH};
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
Self {
alarm_severity: 0,
alarm_status: 0,
alarm_message: String::new(),
timestamp_seconds: now.as_secs() as i64,
timestamp_nanos: now.subsec_nanos() as i32,
timestamp_user_tag: 0,
}
}
pub fn alarm(mut self, severity: i32, status: i32, message: impl Into<String>) -> Self {
self.alarm_severity = severity;
self.alarm_status = status;
self.alarm_message = message.into();
self
}
pub fn timestamp(mut self, seconds: i64, nanos: i32, user_tag: i32) -> Self {
self.timestamp_seconds = seconds;
self.timestamp_nanos = nanos;
self.timestamp_user_tag = user_tag;
self
}
fn build(self) -> Result<cxx::UniquePtr<bridge::NTEnumMetadata>> {
let alarm = bridge::create_alarm(self.alarm_severity, self.alarm_status, self.alarm_message);
let time_stamp = bridge::create_time(self.timestamp_seconds, self.timestamp_nanos, self.timestamp_user_tag);
let metadata = bridge::create_enum_metadata(&alarm, &time_stamp);
Ok(metadata)
}
}
impl Default for NTEnumMetadataBuilder {
fn default() -> Self {
Self::new()
}
}