const CLIENT_MAX_ID: u32 = 0xfeffffff;
pub mod event_dispatcher;
pub mod store;
pub mod traits;
use std::{future::Future, os::fd::RawFd, pin::Pin};
#[doc(inline)]
pub use event_dispatcher::EventDispatcher;
#[doc(inline)]
pub use store::Store;
pub type Dispatch<'a, Ctx, R>
where
Ctx: traits::Client + 'a,
Ctx::Object: for<'b> crate::objects::Object<Ctx, Request<'b> = (&'b [u8], &'b [RawFd])>,
R: runa_io::traits::buf::AsyncBufReadWithFd + 'a,
= impl Future<Output = bool> + 'a;
pub fn dispatch_to<'a, Ctx, R>(ctx: &'a mut Ctx, mut reader: Pin<&'a mut R>) -> Dispatch<'a, Ctx, R>
where
R: runa_io::traits::buf::AsyncBufReadWithFd,
Ctx: traits::Client,
Ctx::Object: for<'b> crate::objects::Object<Ctx, Request<'b> = (&'b [u8], &'b [RawFd])>,
{
async move {
use runa_io::traits::{buf::Message, WriteMessage};
use runa_wayland_protocols::wayland::wl_display::v1 as wl_display;
use runa_wayland_types as types;
use traits::Store;
use crate::{error::ProtocolError, objects::AnyObject};
let Message {
object_id,
len,
data,
fds,
} = match R::next_message(reader.as_mut()).await {
Ok(v) => v,
Err(_) => return true,
};
let (ret, bytes_read, fds_read) =
<<Ctx as traits::Client>::Object as crate::objects::Object<Ctx>>::dispatch(
ctx,
object_id,
(data, fds),
)
.await;
let (mut fatal, error) = match ret {
Ok(_) => (false, None),
Err(e) => (
e.fatal(),
e.wayland_error()
.map(|(object_id, error_code)| (object_id, error_code, e.to_string())),
),
};
if let Some((object_id, error_code, msg)) = error {
fatal |= ctx
.connection_mut()
.send(crate::objects::DISPLAY_ID, wl_display::events::Error {
object_id: types::Object(object_id),
code: error_code,
message: types::Str(msg.as_bytes()),
})
.await
.is_err();
}
if !fatal {
if bytes_read != len {
let len_opcode = u32::from_ne_bytes(data[0..4].try_into().unwrap());
let opcode = len_opcode & 0xffff;
tracing::error!(
"unparsed bytes in buffer, read ({bytes_read}) != received ({len}). \
object_id: {}@{object_id}, opcode: {opcode}",
ctx.objects()
.get::<Ctx::Object>(object_id)
.map(|o| o.interface())
.unwrap_or("unknown")
);
fatal = true;
}
reader.consume(bytes_read, fds_read);
}
fatal
}
}
#[doc(hidden)] pub mod serial {
use hashbrown::HashMap;
#[derive(Debug)]
pub struct EventSerial<D> {
serials: HashMap<u32, (D, std::time::Instant)>,
last_serial: u32,
expire: std::time::Duration,
}
impl<D> EventSerial<D> {
pub fn new(expire: std::time::Duration) -> Self {
Self {
serials: HashMap::new(),
last_serial: 0,
expire,
}
}
fn clean_up(&mut self) {
let now = std::time::Instant::now();
self.serials.retain(|_, (_, t)| *t + self.expire > now);
}
}
impl<D: 'static> crate::Serial for EventSerial<D> {
type Data = D;
type Iter<'a> = <&'a Self as IntoIterator>::IntoIter;
fn next_serial(&mut self, data: Self::Data) -> u32 {
self.last_serial += 1;
self.clean_up();
if self
.serials
.insert(self.last_serial, (data, std::time::Instant::now()))
.is_some()
{
panic!(
"serial {} already in use, expiration duration too long?",
self.last_serial
);
}
self.last_serial
}
fn get(&self, serial: u32) -> Option<&Self::Data> {
let now = std::time::Instant::now();
self.serials.get(&serial).and_then(|(d, timestamp)| {
if *timestamp + self.expire > now {
Some(d)
} else {
None
}
})
}
fn expire(&mut self, serial: u32) -> bool {
self.clean_up();
self.serials.remove(&serial).is_some()
}
fn iter(&self) -> Self::Iter<'_> {
self.into_iter()
}
}
impl<'a, D: 'a> IntoIterator for &'a EventSerial<D> {
type Item = (u32, &'a D);
type IntoIter = impl Iterator<Item = Self::Item> + 'a where Self: 'a;
fn into_iter(self) -> Self::IntoIter {
self.serials.iter().map(|(k, (d, _))| (*k, d))
}
}
}