use std::any::Any;
use std::time::{Duration, SystemTime};
use crate::port::QueuePriority;
pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(1);
pub fn timeout_from_secs(secs: f64) -> Duration {
Duration::try_from_secs_f64(secs).unwrap_or(DEFAULT_TIMEOUT)
}
pub const ASYN_REASON_QUEUE_EVEN_IF_NOT_CONNECTED: usize = 0x7000_0000;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConnectCheck {
Required,
Waived,
}
pub struct AsynUser {
pub reason: usize,
pub addr: i32,
pub timeout: Duration,
pub queue_timeout: Option<Duration>,
pub priority: QueuePriority,
pub timestamp: Option<SystemTime>,
pub alarm_status: u16,
pub alarm_severity: u16,
pub user_data: Option<Box<dyn Any + Send>>,
pub block_token: Option<u64>,
pub trace: Option<UserTrace>,
pub error_message: String,
}
#[derive(Clone)]
pub struct UserTrace {
pub manager: std::sync::Arc<crate::trace::TraceManager>,
pub port: std::sync::Arc<str>,
}
impl Default for AsynUser {
fn default() -> Self {
Self {
reason: 0,
addr: 0,
timeout: Duration::from_secs(1),
queue_timeout: None,
priority: QueuePriority::default(),
timestamp: None,
alarm_status: 0,
alarm_severity: 0,
user_data: None,
block_token: None,
trace: None,
error_message: String::new(),
}
}
}
impl AsynUser {
pub fn new(reason: usize) -> Self {
Self {
reason,
..Default::default()
}
}
pub fn with_addr(mut self, addr: i32) -> Self {
self.addr = addr;
self
}
pub fn with_priority(mut self, priority: QueuePriority) -> Self {
self.priority = priority;
self
}
pub fn queue_even_if_not_connected(mut self) -> Self {
self.reason = ASYN_REASON_QUEUE_EVEN_IF_NOT_CONNECTED;
self.priority = QueuePriority::Connect;
self
}
pub fn connect_check(&self) -> ConnectCheck {
if self.priority == QueuePriority::Connect {
self.connect_check_at_connect_priority()
} else {
ConnectCheck::Required
}
}
pub fn connect_check_at_connect_priority(&self) -> ConnectCheck {
if self.addr < 0 || self.reason == ASYN_REASON_QUEUE_EVEN_IF_NOT_CONNECTED {
ConnectCheck::Waived
} else {
ConnectCheck::Required
}
}
pub fn with_timeout(mut self, timeout: Duration) -> Self {
self.timeout = timeout;
self
}
pub fn with_queue_timeout(mut self, queue_timeout: Duration) -> Self {
self.queue_timeout = Some(queue_timeout);
self
}
pub fn print_io(&self, mask: crate::trace::TraceMask, data: &[u8], label: &str) {
let Some(t) = &self.trace else { return };
if t.manager.is_enabled(&t.port, mask) {
t.manager
.output_device_io(&t.port, Some(self.addr), mask, data, label);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_user_default() {
let u = AsynUser::default();
assert_eq!(u.reason, 0);
assert_eq!(u.addr, 0);
assert_eq!(u.timeout, Duration::from_secs(1));
}
#[test]
fn test_user_builder() {
let u = AsynUser::new(42)
.with_addr(3)
.with_timeout(Duration::from_millis(500));
assert_eq!(u.reason, 42);
assert_eq!(u.addr, 3);
assert_eq!(u.timeout, Duration::from_millis(500));
}
}