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    #[must_use]
45    pub fn as_u32(self) -> u32 {
46        self.0.get()
47    }
48
49    /// Whether the object with this ID was created by the server
50    #[must_use]
51    pub fn created_by_server(self) -> bool {
52        self >= Self::MIN_SERVER
53    }
54
55    /// Whether the object with this ID was created by the client
56    #[must_use]
57    pub fn created_by_client(self) -> bool {
58        self <= Self::MAX_CLIENT
59    }
60}
61
62/// A header of a Wayland message
63#[derive(Debug, Clone, Copy)]
64pub struct MessageHeader {
65    /// The ID of the associated object
66    pub object_id: ObjectId,
67    /// Size of the message in bytes, including the header
68    pub size: u16,
69    /// The opcode of the message
70    pub opcode: u16,
71}
72
73impl MessageHeader {
74    /// The size of the header in bytes
75    pub const SIZE: usize = 8;
76}
77
78/// A Wayland message
79#[derive(Debug)]
80pub struct Message {
81    pub header: MessageHeader,
82    pub args: Vec<ArgValue>,
83}
84
85#[derive(Debug, PartialEq, Eq)]
86pub enum ArgType {
87    Int,
88    Uint,
89    Fixed,
90    Object,
91    OptObject,
92    NewId(&'static Interface),
93    AnyNewId,
94    String,
95    OptString,
96    Array,
97    Fd,
98}
99
100#[derive(Debug)]
101pub enum ArgValue {
102    Int(i32),
103    Uint(u32),
104    Fixed(Fixed),
105    Object(ObjectId),
106    OptObject(Option<ObjectId>),
107    NewId(ObjectId),
108    AnyNewId(Cow<'static, CStr>, u32, ObjectId),
109    String(CString),
110    OptString(Option<CString>),
111    Array(Vec<u8>),
112    Fd(OwnedFd),
113}
114
115impl ArgValue {
116    /// The size of the argument in bytes.
117    #[must_use]
118    pub fn size(&self) -> usize {
119        match self {
120            Self::Int(_)
121            | Self::Uint(_)
122            | Self::Fixed(_)
123            | Self::Object(_)
124            | Self::OptObject(_)
125            | Self::NewId(_)
126            | Self::OptString(None) => 4,
127            Self::AnyNewId(iface, _version, _id) => {
128                iface.to_bytes_with_nul().len().next_multiple_of(4) + 12
129            }
130            Self::String(string) | Self::OptString(Some(string)) => {
131                string.to_bytes_with_nul().len().next_multiple_of(4) + 4
132            }
133            Self::Array(array) => array.len().next_multiple_of(4) + 4,
134            Self::Fd(_) => 0,
135        }
136    }
137}
138
139/// Signed 24.8 decimal number
140#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
141pub struct Fixed(pub i32);
142
143impl From<i32> for Fixed {
144    fn from(value: i32) -> Self {
145        Self(value * 256)
146    }
147}
148
149impl From<u32> for Fixed {
150    fn from(value: u32) -> Self {
151        Self(value as i32 * 256)
152    }
153}
154
155impl From<f32> for Fixed {
156    fn from(value: f32) -> Self {
157        Self((value * 256.0) as i32)
158    }
159}
160
161impl From<f64> for Fixed {
162    fn from(value: f64) -> Self {
163        Self((value * 256.0) as i32)
164    }
165}
166
167impl Fixed {
168    pub const ZERO: Self = Self(0);
169    pub const ONE: Self = Self(256);
170    pub const MINUS_ONE: Self = Self(-256);
171
172    #[must_use]
173    pub fn as_f64(self) -> f64 {
174        self.0 as f64 / 256.0
175    }
176
177    #[must_use]
178    pub fn as_f32(self) -> f32 {
179        self.0 as f32 / 256.0
180    }
181
182    #[must_use]
183    pub fn as_int(self) -> i32 {
184        self.0 / 256
185    }
186
187    #[must_use]
188    pub fn is_int(self) -> bool {
189        self.0 & 255 == 0
190    }
191}
192
193impl fmt::Debug for Fixed {
194    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195        self.as_f64().fmt(f)
196    }
197}
198
199/// A Wayland interface, usually generated from the XML files
200///
201/// `PartialEq` and `Hash` implementations are delegated to the `name` field for performance reasons.
202pub struct Interface {
203    pub name: &'static CStr,
204    pub version: u32,
205    pub events: &'static [MessageDesc],
206    pub requests: &'static [MessageDesc],
207}
208
209/// A "description" of a single Wayland event or request
210#[derive(Debug, Clone, Copy)]
211pub struct MessageDesc {
212    pub name: &'static str,
213    pub is_destructor: bool,
214    pub signature: &'static [ArgType],
215}
216
217impl PartialEq for &'static Interface {
218    fn eq(&self, other: &Self) -> bool {
219        self.name == other.name
220    }
221}
222
223impl Eq for &'static Interface {}
224
225impl Hash for &'static Interface {
226    fn hash<H: Hasher>(&self, state: &mut H) {
227        self.name.hash(state);
228    }
229}
230
231impl fmt::Debug for Interface {
232    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233        f.debug_tuple("Interface").field(&self.name).finish()
234    }
235}
236
237/// A pool of resources reusable between messages
238#[derive(Default)]
239pub struct MessageBuffersPool {
240    pool: Vec<Vec<ArgValue>>,
241}
242
243impl MessageBuffersPool {
244    pub fn reuse_args(&mut self, mut buf: Vec<ArgValue>) {
245        buf.clear();
246        self.pool.push(buf);
247    }
248
249    pub fn get_args(&mut self) -> Vec<ArgValue> {
250        self.pool.pop().unwrap_or_default()
251    }
252}