use std::{ffi::CString, os::unix::prelude::AsRawFd};
pub use wayland_sys::common::{wl_argument, wl_interface, wl_message};
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum AllowNull {
Yes,
No,
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum ArgumentType {
Int,
Uint,
Fixed,
Str(AllowNull),
Object(AllowNull),
NewId,
Array,
Fd,
}
impl ArgumentType {
pub fn same_type(self, other: Self) -> bool {
std::mem::discriminant(&self) == std::mem::discriminant(&other)
}
}
#[derive(Debug, Clone)]
#[allow(clippy::box_collection)]
pub enum Argument<Id, Fd> {
Int(i32),
Uint(u32),
Fixed(i32),
Str(Option<Box<CString>>),
Object(Id),
NewId(Id),
Array(Box<Vec<u8>>),
Fd(Fd),
}
impl<Id, Fd> Argument<Id, Fd> {
pub fn get_type(&self) -> ArgumentType {
match *self {
Self::Int(_) => ArgumentType::Int,
Self::Uint(_) => ArgumentType::Uint,
Self::Fixed(_) => ArgumentType::Fixed,
Self::Str(_) => ArgumentType::Str(AllowNull::Yes),
Self::Object(_) => ArgumentType::Object(AllowNull::Yes),
Self::NewId(_) => ArgumentType::NewId,
Self::Array(_) => ArgumentType::Array,
Self::Fd(_) => ArgumentType::Fd,
}
}
fn map_fd<T>(self, f: &mut impl FnMut(Fd) -> T) -> Argument<Id, T> {
match self {
Self::Int(val) => Argument::Int(val),
Self::Uint(val) => Argument::Uint(val),
Self::Fixed(val) => Argument::Fixed(val),
Self::Str(val) => Argument::Str(val),
Self::Object(val) => Argument::Object(val),
Self::NewId(val) => Argument::NewId(val),
Self::Array(val) => Argument::Array(val),
Self::Fd(val) => Argument::Fd(f(val)),
}
}
}
impl<Id: PartialEq, Fd: AsRawFd> PartialEq for Argument<Id, Fd> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Int(a), Self::Int(b)) => a == b,
(Self::Uint(a), Self::Uint(b)) => a == b,
(Self::Fixed(a), Self::Fixed(b)) => a == b,
(Self::Str(a), Self::Str(b)) => a == b,
(Self::Object(a), Self::Object(b)) => a == b,
(Self::NewId(a), Self::NewId(b)) => a == b,
(Self::Array(a), Self::Array(b)) => a == b,
(Self::Fd(a), Self::Fd(b)) => a.as_raw_fd() == b.as_raw_fd(),
_ => false,
}
}
}
impl<Id: Eq, Fd: AsRawFd> Eq for Argument<Id, Fd> {}
impl<Id: std::fmt::Display, Fd: AsRawFd> std::fmt::Display for Argument<Id, Fd> {
#[cfg_attr(coverage, no_coverage)]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Int(value) => write!(f, "{}", value),
Self::Uint(value) => write!(f, "{}", value),
Self::Fixed(value) => write!(f, "{}", value),
Self::Str(value) => write!(f, "{:?}", value),
Self::Object(value) => write!(f, "{}", value),
Self::NewId(value) => write!(f, "{}", value),
Self::Array(value) => write!(f, "{:?}", value),
Self::Fd(value) => write!(f, "{}", value.as_raw_fd()),
}
}
}
#[derive(Debug)]
pub struct Interface {
pub name: &'static str,
pub version: u32,
pub requests: &'static [MessageDesc],
pub events: &'static [MessageDesc],
pub c_ptr: Option<&'static wayland_sys::common::wl_interface>,
}
impl std::fmt::Display for Interface {
#[cfg_attr(coverage, no_coverage)]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.name)
}
}
#[derive(Copy, Clone, Debug)]
pub struct MessageDesc {
pub name: &'static str,
pub signature: &'static [ArgumentType],
pub since: u32,
pub is_destructor: bool,
pub child_interface: Option<&'static Interface>,
pub arg_interfaces: &'static [&'static Interface],
}
pub static ANONYMOUS_INTERFACE: Interface =
Interface { name: "<anonymous>", version: 0, requests: &[], events: &[], c_ptr: None };
#[derive(Copy, Clone, Debug)]
pub struct ObjectInfo {
pub id: u32,
pub interface: &'static Interface,
pub version: u32,
}
#[derive(Clone, Debug)]
pub struct ProtocolError {
pub code: u32,
pub object_id: u32,
pub object_interface: String,
pub message: String,
}
pub const INLINE_ARGS: usize = 4;
#[derive(Clone, Debug)]
pub struct Message<Id, Fd> {
pub sender_id: Id,
pub opcode: u16,
pub args: smallvec::SmallVec<[Argument<Id, Fd>; INLINE_ARGS]>,
}
impl<Id, Fd> Message<Id, Fd> {
pub fn map_fd<T>(self, mut f: impl FnMut(Fd) -> T) -> Message<Id, T> {
Message {
sender_id: self.sender_id,
opcode: self.opcode,
args: self.args.into_iter().map(move |arg| arg.map_fd(&mut f)).collect(),
}
}
}
impl<Id: PartialEq, Fd: AsRawFd> PartialEq for Message<Id, Fd> {
fn eq(&self, other: &Self) -> bool {
self.sender_id == other.sender_id && self.opcode == other.opcode && self.args == other.args
}
}
impl<Id: Eq, Fd: AsRawFd> Eq for Message<Id, Fd> {}
impl std::error::Error for ProtocolError {}
impl std::fmt::Display for ProtocolError {
#[cfg_attr(coverage, no_coverage)]
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
write!(
f,
"Protocol error {} on object {}@{}: {}",
self.code, self.object_interface, self.object_id, self.message
)
}
}
#[inline]
pub fn same_interface(a: &'static Interface, b: &'static Interface) -> bool {
std::ptr::eq(a, b) || a.name == b.name
}
pub(crate) fn check_for_signature<Id, Fd>(
signature: &[ArgumentType],
args: &[Argument<Id, Fd>],
) -> bool {
if signature.len() != args.len() {
return false;
}
for (typ, arg) in signature.iter().copied().zip(args.iter()) {
if !arg.get_type().same_type(typ) {
return false;
}
}
true
}
#[inline]
#[allow(dead_code)]
pub(crate) fn same_interface_or_anonymous(a: &'static Interface, b: &'static Interface) -> bool {
same_interface(a, b) || same_interface(a, &ANONYMOUS_INTERFACE)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WEnum<T> {
Value(T),
Unknown(u32),
}
#[derive(Debug, Copy, Clone)]
pub struct WEnumError {
typ: &'static str,
value: u32,
}
impl std::error::Error for WEnumError {}
impl std::fmt::Display for WEnumError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Unknown numeric value {} for enum {}", self.value, self.typ)
}
}
impl<T> WEnum<T> {
#[inline]
pub fn into_result(self) -> Result<T, WEnumError> {
match self {
Self::Value(v) => Ok(v),
Self::Unknown(value) => Err(WEnumError { typ: std::any::type_name::<T>(), value }),
}
}
}
impl<T> From<WEnum<T>> for Result<T, WEnumError> {
fn from(me: WEnum<T>) -> Self {
me.into_result()
}
}
impl<T: std::convert::TryFrom<u32>> From<u32> for WEnum<T> {
fn from(v: u32) -> Self {
match T::try_from(v) {
Ok(t) => Self::Value(t),
Err(_) => Self::Unknown(v),
}
}
}
impl<T: Into<u32>> From<WEnum<T>> for u32 {
fn from(enu: WEnum<T>) -> u32 {
match enu {
WEnum::Unknown(u) => u,
WEnum::Value(t) => t.into(),
}
}
}