#![warn(missing_docs)]
pub(crate) const PROTOCOL_VERSION: u32 = 1;
pub mod client;
pub(crate) mod helpers;
pub use helpers::reset_trace_cache;
pub mod implementation;
pub(crate) mod message;
pub mod server;
pub(crate) mod socket;
#[cfg(feature = "log")]
#[allow(unused_imports)]
use log::{debug as log_debug, error as log_error, info as log_info, warn as log_warn};
#[cfg(not(feature = "log"))]
#[allow(unused_imports)]
use std::{
eprintln as log_debug, eprintln as log_error, eprintln as log_info, eprintln as log_warn,
};
use implementation::object as impl_object;
use nix::{errno, poll, sys};
use std::os::fd::{AsFd, AsRawFd};
use std::os::unix::net;
use std::{cell, io, rc, sync, time};
pub(crate) struct SharedState {
pub(crate) error: cell::Cell<bool>,
pub(crate) stream: net::UnixStream,
pub(crate) impls:
rc::Rc<cell::RefCell<Vec<Box<dyn implementation::server::ProtocolImplementations>>>>,
}
impl SharedState {
pub(crate) fn new(
stream: net::UnixStream,
impls: rc::Rc<cell::RefCell<Vec<Box<dyn implementation::server::ProtocolImplementations>>>>,
) -> Self {
Self {
error: cell::Cell::new(false),
stream,
impls,
}
}
pub(crate) fn send_message(&self, message: &dyn message::Message) {
trace! { crate::log_debug!("[hw] trace: [{} @ {:.3}] -> {}", self.stream.as_raw_fd(), steady_millis(), message.parse_data()) };
let buf = message.data();
let iov = [io::IoSlice::new(buf)];
let cmsg = [sys::socket::ControlMessage::ScmRights(message.fds())];
loop {
match sys::socket::sendmsg::<()>(
self.stream.as_raw_fd(),
&iov,
&cmsg,
sys::socket::MsgFlags::empty(),
None,
) {
Ok(_) => break,
Err(errno::Errno::EAGAIN) => {
let mut pfd = [poll::PollFd::new(
self.stream.as_fd(),
poll::PollFlags::POLLOUT | poll::PollFlags::POLLWRBAND,
)];
if let Err(e) = poll::poll(&mut pfd, poll::PollTimeout::NONE) {
crate::log_error!(
"[{} @ {:.3}] poll error during send_message: {e}",
self.stream.as_raw_fd(),
steady_millis(),
);
break;
}
}
Err(_) => {
break;
}
}
}
}
}
#[macro_export]
macro_rules! include_protocol {
($name:expr) => {
include!(concat!(env!("OUT_DIR"), "/", $name, ".rs"));
};
}
#[doc(hidden)]
pub trait Object: Sized {
type Event<'a>;
const NAME: &str;
fn from_object<D: Dispatch<Self>>(object: rc::Rc<dyn impl_object::RawObject>) -> Self;
}
#[doc(hidden)]
#[allow(missing_docs)]
pub trait Dispatch<I: crate::Object> {
fn event(&mut self, object: &I, event: <I as crate::Object>::Event<'_>);
}
#[macro_export]
macro_rules! delegate_noop {
($(@< $( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+ >)? $dispatch_from:ty : $interface:ty) => {
impl$(< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $crate::Dispatch<$interface> for $dispatch_from {
fn event(&mut self, _: &$interface, _: <$interface as $crate::Object>::Event<'_>) {
unreachable!();
}
}
};
($(@< $( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+ >)? $dispatch_from:ty : ignore $interface:ty) => {
impl$(< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $crate::Dispatch<$interface> for $dispatch_from {
fn event(&mut self, _: &$interface, _: <$interface as $crate::Object>::Event<'_>) {
}
}
};
}
#[doc(hidden)]
#[allow(missing_docs)]
pub struct DispatchData {
pub object: *const dyn impl_object::RawObject,
}
#[doc(hidden)]
#[allow(missing_docs)]
pub struct DispatchContext<D: ?Sized> {
pub object: *const dyn impl_object::RawObject,
pub dispatch: *mut D,
}
static START: sync::OnceLock<time::Instant> = sync::OnceLock::new();
pub(crate) fn steady_millis() -> f64 {
let start = START.get_or_init(time::Instant::now);
start.elapsed().as_nanos() as f64 / 1_000_000.0
}