1use std::{
4 ffi::{CStr, CString},
5 os::unix::io::{AsRawFd, BorrowedFd, OwnedFd},
6};
7
8#[cfg(any(test, feature = "client_system", feature = "server_system"))]
9use wayland_sys::common::{wl_interface, wl_message};
10
11#[cfg(not(any(test, feature = "client_system", feature = "server_system")))]
13#[allow(non_camel_case_types)]
14type wl_interface = std::marker::PhantomData<*const ()>;
15#[allow(non_camel_case_types)]
16#[cfg(not(any(test, feature = "client_system", feature = "server_system")))]
17type wl_message = std::marker::PhantomData<*const ()>;
18
19#[derive(Clone, Copy, PartialEq, Eq, Debug)]
21pub enum AllowNull {
22 Yes,
24 No,
26}
27
28#[derive(Copy, Clone, PartialEq, Eq, Debug)]
30pub enum ArgumentType {
31 Int,
33 Uint,
35 Fixed,
37 Str(AllowNull),
39 Object(AllowNull),
41 NewId,
43 Array,
45 Fd,
49}
50
51impl ArgumentType {
52 pub fn same_type(self, other: Self) -> bool {
54 std::mem::discriminant(&self) == std::mem::discriminant(&other)
55 }
56}
57
58#[derive(Debug)]
60#[allow(clippy::box_collection)]
61pub enum OwnedArgument<Id> {
62 Int(i32),
64 Uint(u32),
66 Fixed(i32),
68 Str(Option<Box<CString>>),
73 Object(Id),
75 NewId(Id),
77 Array(Box<Vec<u8>>),
82 Fd(OwnedFd),
84}
85
86impl<Id: PartialEq> PartialEq for OwnedArgument<Id> {
87 fn eq(&self, other: &Self) -> bool {
88 match (self, other) {
89 (Self::Int(a), Self::Int(b)) => a == b,
90 (Self::Uint(a), Self::Uint(b)) => a == b,
91 (Self::Fixed(a), Self::Fixed(b)) => a == b,
92 (Self::Str(a), Self::Str(b)) => a == b,
93 (Self::Object(a), Self::Object(b)) => a == b,
94 (Self::NewId(a), Self::NewId(b)) => a == b,
95 (Self::Array(a), Self::Array(b)) => a == b,
96 (Self::Fd(_), Self::Fd(_)) => false,
98 _ => false,
99 }
100 }
101}
102
103impl<Id: Clone> OwnedArgument<Id> {
104 #[cfg(test)]
105 pub(crate) fn as_argument(&self) -> Argument<'_, Id> {
106 use std::os::fd::AsFd;
107 match self {
108 Self::Int(val) => Argument::Int(*val),
109 Self::Uint(val) => Argument::Uint(*val),
110 Self::Fixed(val) => Argument::Fixed(*val),
111 Self::Str(val) => Argument::Str(val.clone()),
112 Self::Object(val) => Argument::Object(val),
113 Self::NewId(val) => Argument::NewId(val),
114 Self::Array(val) => Argument::Array(Box::new(val)),
115 Self::Fd(val) => Argument::Fd(val.as_fd()),
116 }
117 }
118}
119
120impl<Id: Eq> Eq for OwnedArgument<Id> {}
121
122#[derive(Debug, Clone)]
124#[allow(clippy::box_collection)]
125pub enum Argument<'a, Id> {
126 Int(i32),
128 Uint(u32),
130 Fixed(i32),
132 Str(Option<Box<CString>>),
137 Object(&'a Id),
139 NewId(&'a Id),
141 Array(Box<&'a [u8]>),
146 Fd(BorrowedFd<'a>),
148}
149
150impl<'a, Id> Argument<'a, Id> {
151 pub fn get_type(&self) -> ArgumentType {
153 match *self {
154 Self::Int(_) => ArgumentType::Int,
155 Self::Uint(_) => ArgumentType::Uint,
156 Self::Fixed(_) => ArgumentType::Fixed,
157 Self::Str(_) => ArgumentType::Str(AllowNull::Yes),
158 Self::Object(_) => ArgumentType::Object(AllowNull::Yes),
159 Self::NewId(_) => ArgumentType::NewId,
160 Self::Array(_) => ArgumentType::Array,
161 Self::Fd(_) => ArgumentType::Fd,
162 }
163 }
164}
165
166impl<'a, Id: PartialEq> PartialEq for Argument<'a, Id> {
167 fn eq(&self, other: &Self) -> bool {
168 match (self, other) {
169 (Self::Int(a), Self::Int(b)) => a == b,
170 (Self::Uint(a), Self::Uint(b)) => a == b,
171 (Self::Fixed(a), Self::Fixed(b)) => a == b,
172 (Self::Str(a), Self::Str(b)) => a == b,
173 (Self::Object(a), Self::Object(b)) => a == b,
174 (Self::NewId(a), Self::NewId(b)) => a == b,
175 (Self::Array(a), Self::Array(b)) => a == b,
176 (Self::Fd(a), Self::Fd(b)) => a.as_raw_fd() == b.as_raw_fd(),
177 _ => false,
178 }
179 }
180}
181
182impl<'a, Id: Eq> Eq for Argument<'a, Id> {}
183
184impl<'a, Id: std::fmt::Display> std::fmt::Display for Argument<'a, Id> {
185 #[cfg_attr(unstable_coverage, coverage(off))]
186 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
187 match self {
188 Self::Int(value) => write!(f, "{value}"),
189 Self::Uint(value) => write!(f, "{value}"),
190 Self::Fixed(value) => write!(f, "{:.4}", *value as f64 / 256.0),
191 Self::Str(value) => write!(f, "{value:?}"),
192 Self::Object(value) => write!(f, "{value}"),
193 Self::NewId(value) => write!(f, "{value}"),
194 Self::Array(value) => write!(f, "{value:?}"),
195 Self::Fd(value) => write!(f, "{}", value.as_raw_fd()),
196 }
197 }
198}
199
200impl<Id: std::fmt::Display> std::fmt::Display for OwnedArgument<Id> {
201 #[cfg_attr(unstable_coverage, coverage(off))]
202 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
203 match self {
204 Self::Int(value) => write!(f, "{value}"),
205 Self::Uint(value) => write!(f, "{value}"),
206 Self::Fixed(value) => write!(f, "{:.4}", *value as f64 / 256.0),
207 Self::Str(value) => write!(f, "{value:?}"),
208 Self::Object(value) => write!(f, "{value}"),
209 Self::NewId(value) => write!(f, "{value}"),
210 Self::Array(value) => write!(f, "{value:?}"),
211 Self::Fd(value) => write!(f, "{}", value.as_raw_fd()),
212 }
213 }
214}
215
216#[derive(Debug)]
221pub struct Interface {
222 pub name: &'static str,
224 pub version: u32,
226 pub requests: &'static [MessageDesc],
228 pub events: &'static [MessageDesc],
230 pub c_interface: Option<&'static CWlInterface>,
232}
233
234#[derive(Debug)]
236#[repr(transparent)]
237pub struct CWlInterface(pub(crate) wl_interface);
238
239unsafe impl Sync for CWlInterface {}
240
241impl CWlInterface {
242 #[cfg(any(test, feature = "client_system", feature = "server_system"))]
244 pub const fn new(
245 name: &'static CStr,
246 version: u32,
247 requests: &'static [CWlMessage],
248 events: &'static [CWlMessage],
249 ) -> Self {
250 Self(wl_interface {
251 name: name.as_ptr(),
252 version: version as _,
253 request_count: requests.len() as _,
254 requests: requests.as_ptr() as _,
255 event_count: events.len() as _,
256 events: events.as_ptr() as _,
257 })
258 }
259
260 #[cfg(not(any(test, feature = "client_system", feature = "server_system")))]
262 pub const fn new(
263 name: &'static CStr,
264 version: u32,
265 requests: &'static [CWlMessage],
266 events: &'static [CWlMessage],
267 ) -> Self {
268 let _ = (name, version, requests, events);
269 Self(std::marker::PhantomData)
270 }
271}
272
273#[allow(missing_debug_implementations)]
275#[repr(transparent)]
276pub struct CWlMessage(wl_message);
277
278unsafe impl Sync for CWlMessage {}
279
280impl CWlMessage {
281 #[cfg(any(test, feature = "client_system", feature = "server_system"))]
283 pub const fn new(
284 name: &'static CStr,
285 signature: &'static CStr,
286 types: &'static [Option<&'static CWlInterface>],
288 ) -> Self {
289 Self(wl_message {
290 name: name.as_ptr(),
291 signature: signature.as_ptr(),
292 types: types.as_ptr() as *const *const wl_interface,
293 })
294 }
295
296 #[cfg(not(any(test, feature = "client_system", feature = "server_system")))]
298 pub const fn new(
299 name: &'static CStr,
300 signature: &'static CStr,
301 types: &'static [Option<&'static CWlInterface>],
302 ) -> Self {
303 let _ = (name, signature, types);
304 Self(std::marker::PhantomData)
305 }
306}
307
308impl std::fmt::Display for Interface {
309 #[cfg_attr(unstable_coverage, coverage(off))]
310 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
311 f.write_str(self.name)
312 }
313}
314
315#[derive(Copy, Clone, Debug)]
317pub struct MessageDesc {
318 pub name: &'static str,
320 pub signature: &'static [ArgumentType],
322 pub since: u32,
324 pub is_destructor: bool,
326 pub child_interface: Option<&'static Interface>,
330 pub arg_interfaces: &'static [&'static Interface],
332}
333
334pub static ANONYMOUS_INTERFACE: Interface =
336 Interface { name: "<anonymous>", version: 0, requests: &[], events: &[], c_interface: None };
337
338#[derive(Copy, Clone, Debug)]
340pub struct ObjectInfo {
341 pub id: u32,
343 pub interface: &'static Interface,
345 pub version: u32,
347}
348
349#[derive(Clone, Debug)]
354pub struct ProtocolError {
355 pub code: u32,
360 pub object_id: u32,
362 pub object_interface: String,
364 pub message: String,
366}
367
368pub const INLINE_ARGS: usize = 4;
374
375#[derive(Debug, PartialEq, Eq)]
377pub struct OwnedMessage<Id> {
378 pub sender_id: Id,
380 pub opcode: u16,
382 pub args: smallvec::SmallVec<[OwnedArgument<Id>; INLINE_ARGS]>,
384}
385
386#[derive(Clone, Debug, PartialEq, Eq)]
401pub struct Message<'a, Id> {
402 pub sender_id: &'a Id,
404 pub opcode: u16,
406 pub args: smallvec::SmallVec<[Argument<'a, Id>; INLINE_ARGS]>,
408}
409
410impl std::error::Error for ProtocolError {}
411
412impl std::fmt::Display for ProtocolError {
413 #[cfg_attr(unstable_coverage, coverage(off))]
414 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
415 if self.message.is_empty() {
416 write!(
418 f,
419 "Protocol error {} on object {}@{}",
420 self.code, self.object_interface, self.object_id
421 )
422 } else {
423 write!(
424 f,
425 "Protocol error {} on object {}@{}: {}",
426 self.code, self.object_interface, self.object_id, self.message
427 )
428 }
429 }
430}
431
432#[inline]
434pub fn same_interface(a: &'static Interface, b: &'static Interface) -> bool {
435 std::ptr::eq(a, b) || a.name == b.name
436}
437
438pub(crate) fn check_for_signature<Id>(signature: &[ArgumentType], args: &[Argument<Id>]) -> bool {
439 if signature.len() != args.len() {
440 return false;
441 }
442 for (typ, arg) in signature.iter().copied().zip(args.iter()) {
443 if !arg.get_type().same_type(typ) {
444 return false;
445 }
446 }
447 true
448}
449
450#[inline]
451#[allow(dead_code)]
452pub(crate) fn same_interface_or_anonymous(a: &'static Interface, b: &'static Interface) -> bool {
453 same_interface(a, b) || same_interface(a, &ANONYMOUS_INTERFACE)
454}
455
456#[cfg(test)]
457mod test {
458 use std::mem;
459
460 use super::*;
461
462 #[test]
463 fn test_argument_size() {
464 assert!(mem::size_of::<Argument<'_, usize>>() <= 2 * mem::size_of::<usize>());
466 assert!(mem::size_of::<OwnedArgument<usize>>() <= 2 * mem::size_of::<usize>());
467 }
468}