wayrs_core/
lib.rs

1//! Core Wayland functionality
2//!
3//! It can be used on both client and server side.
4
5use std::borrow::Cow;
6use std::ffi::{CStr, CString};
7use std::fmt;
8use std::hash::{Hash, Hasher};
9use std::num::NonZeroU32;
10use std::os::fd::OwnedFd;
11
12mod ring_buffer;
13pub mod transport;
14
15/// The "mode" of an IO operation
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum IoMode {
18    /// Blocking.
19    ///
20    /// The function call may block, but it will never return [WouldBlock](std::io::ErrorKind::WouldBlock)
21    /// error.
22    Blocking,
23    /// Non-blocking.
24    ///
25    /// The function call will not block on IO operations. [WouldBlock](std::io::ErrorKind::WouldBlock)
26    /// error is returned if the operation cannot be completed immediately.
27    NonBlocking,
28}
29
30/// A Wayland object ID.
31///
32/// Uniquely identifies an object at each point of time. Note that an ID may have a limited
33/// lifetime. Also an ID which once pointed to a certain object, may point to a different object in
34/// the future, due to ID reuse.
35#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
36pub struct ObjectId(pub NonZeroU32);
37
38impl ObjectId {
39    pub const DISPLAY: Self = Self(unsafe { NonZeroU32::new_unchecked(1) });
40    pub const MAX_CLIENT: Self = Self(unsafe { NonZeroU32::new_unchecked(0xFEFFFFFF) });
41    pub const MIN_SERVER: Self = Self(unsafe { NonZeroU32::new_unchecked(0xFF000000) });
42
43    /// Returns the numeric representation of the ID
44    pub fn as_u32(self) -> u32 {
45        self.0.get()
46    }
47
48    /// Whether the object with this ID was created by the server
49    pub fn created_by_server(self) -> bool {
50        self >= Self::MIN_SERVER
51    }
52
53    /// Whether the object with this ID was created by the client
54    pub fn created_by_client(self) -> bool {
55        self <= Self::MAX_CLIENT
56    }
57}
58
59/// A header of a Wayland message
60#[derive(Debug, Clone, Copy)]
61pub struct MessageHeader {
62    /// The ID of the associated object
63    pub object_id: ObjectId,
64    /// Size of the message in bytes, including the header
65    pub size: u16,
66    /// The opcode of the message
67    pub opcode: u16,
68}
69
70impl MessageHeader {
71    /// The size of the header in bytes
72    pub const SIZE: usize = 8;
73}
74
75/// A Wayland message
76#[derive(Debug)]
77pub struct Message {
78    pub header: MessageHeader,
79    pub args: Vec<ArgValue>,
80}
81
82#[derive(Debug, PartialEq, Eq)]
83pub enum ArgType {
84    Int,
85    Uint,
86    Fixed,
87    Object,
88    OptObject,
89    NewId(&'static Interface),
90    AnyNewId,
91    String,
92    OptString,
93    Array,
94    Fd,
95}
96
97#[derive(Debug)]
98pub enum ArgValue {
99    Int(i32),
100    Uint(u32),
101    Fixed(Fixed),
102    Object(ObjectId),
103    OptObject(Option<ObjectId>),
104    NewId(ObjectId),
105    AnyNewId(Cow<'static, CStr>, u32, ObjectId),
106    String(CString),
107    OptString(Option<CString>),
108    Array(Vec<u8>),
109    Fd(OwnedFd),
110}
111
112impl ArgValue {
113    /// The size of the argument in bytes.
114    pub fn size(&self) -> usize {
115        fn len_with_padding(len: usize) -> usize {
116            let padding = (4 - (len % 4)) % 4;
117            4 + len + padding
118        }
119
120        match self {
121            Self::Int(_)
122            | Self::Uint(_)
123            | Self::Fixed(_)
124            | Self::Object(_)
125            | Self::OptObject(_)
126            | Self::NewId(_)
127            | Self::OptString(None) => 4,
128            Self::AnyNewId(iface, _version, _id) => {
129                len_with_padding(iface.to_bytes_with_nul().len()) + 8
130            }
131            Self::String(string) | Self::OptString(Some(string)) => {
132                len_with_padding(string.to_bytes_with_nul().len())
133            }
134            Self::Array(array) => len_with_padding(array.len()),
135            Self::Fd(_) => 0,
136        }
137    }
138}
139
140/// Signed 24.8 decimal number
141#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
142pub struct Fixed(pub i32);
143
144impl From<i32> for Fixed {
145    fn from(value: i32) -> Self {
146        Self(value * 256)
147    }
148}
149
150impl From<u32> for Fixed {
151    fn from(value: u32) -> Self {
152        Self(value as i32 * 256)
153    }
154}
155
156impl From<f32> for Fixed {
157    fn from(value: f32) -> Self {
158        Self((value * 256.0) as i32)
159    }
160}
161
162impl From<f64> for Fixed {
163    fn from(value: f64) -> Self {
164        Self((value * 256.0) as i32)
165    }
166}
167
168impl Fixed {
169    pub const ZERO: Self = Self(0);
170    pub const ONE: Self = Self(256);
171    pub const MINUS_ONE: Self = Self(-256);
172
173    pub fn as_f64(self) -> f64 {
174        self.0 as f64 / 256.0
175    }
176
177    pub fn as_f32(self) -> f32 {
178        self.0 as f32 / 256.0
179    }
180
181    pub fn as_int(self) -> i32 {
182        self.0 / 256
183    }
184
185    pub fn is_int(self) -> bool {
186        self.0 & 255 == 0
187    }
188}
189
190impl fmt::Debug for Fixed {
191    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
192        self.as_f64().fmt(f)
193    }
194}
195
196/// A Wayland interface, usually generated from the XML files
197///
198/// `PartialEq` and `Hash` implementations are delegated to the `name` field for performance reasons.
199pub struct Interface {
200    pub name: &'static CStr,
201    pub version: u32,
202    pub events: &'static [MessageDesc],
203    pub requests: &'static [MessageDesc],
204}
205
206/// A "description" of a single Wayland event or request
207#[derive(Debug, Clone, Copy)]
208pub struct MessageDesc {
209    pub name: &'static str,
210    pub is_destructor: bool,
211    pub signature: &'static [ArgType],
212}
213
214impl PartialEq for &'static Interface {
215    fn eq(&self, other: &Self) -> bool {
216        self.name == other.name
217    }
218}
219
220impl Eq for &'static Interface {}
221
222impl Hash for &'static Interface {
223    fn hash<H: Hasher>(&self, state: &mut H) {
224        self.name.hash(state);
225    }
226}
227
228impl fmt::Debug for Interface {
229    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
230        f.debug_tuple("Interface").field(&self.name).finish()
231    }
232}
233
234/// A pool of resources reusable between messages
235#[derive(Default)]
236pub struct MessageBuffersPool {
237    pool: Vec<Vec<ArgValue>>,
238}
239
240impl MessageBuffersPool {
241    pub fn reuse_args(&mut self, mut buf: Vec<ArgValue>) {
242        buf.clear();
243        self.pool.push(buf);
244    }
245
246    pub fn get_args(&mut self) -> Vec<ArgValue> {
247        self.pool.pop().unwrap_or_default()
248    }
249}