1use std::{
4 ffi::{CStr, CString},
5 os::unix::io::AsRawFd,
6};
7
8#[cfg(any(feature = "client_system", feature = "server_system"))]
9use wayland_sys::common::{wl_interface, wl_message};
10
11#[cfg(not(any(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(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, Clone)]
60#[allow(clippy::box_collection)]
61pub enum Argument<Id, Fd> {
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(Fd),
86}
87
88impl<Id, Fd> Argument<Id, Fd> {
89 pub fn get_type(&self) -> ArgumentType {
91 match *self {
92 Self::Int(_) => ArgumentType::Int,
93 Self::Uint(_) => ArgumentType::Uint,
94 Self::Fixed(_) => ArgumentType::Fixed,
95 Self::Str(_) => ArgumentType::Str(AllowNull::Yes),
96 Self::Object(_) => ArgumentType::Object(AllowNull::Yes),
97 Self::NewId(_) => ArgumentType::NewId,
98 Self::Array(_) => ArgumentType::Array,
99 Self::Fd(_) => ArgumentType::Fd,
100 }
101 }
102
103 fn map_fd<T>(self, f: &mut impl FnMut(Fd) -> T) -> Argument<Id, T> {
104 match self {
105 Self::Int(val) => Argument::Int(val),
106 Self::Uint(val) => Argument::Uint(val),
107 Self::Fixed(val) => Argument::Fixed(val),
108 Self::Str(val) => Argument::Str(val),
109 Self::Object(val) => Argument::Object(val),
110 Self::NewId(val) => Argument::NewId(val),
111 Self::Array(val) => Argument::Array(val),
112 Self::Fd(val) => Argument::Fd(f(val)),
113 }
114 }
115}
116
117impl<Id: PartialEq, Fd: AsRawFd> PartialEq for Argument<Id, Fd> {
118 fn eq(&self, other: &Self) -> bool {
119 match (self, other) {
120 (Self::Int(a), Self::Int(b)) => a == b,
121 (Self::Uint(a), Self::Uint(b)) => a == b,
122 (Self::Fixed(a), Self::Fixed(b)) => a == b,
123 (Self::Str(a), Self::Str(b)) => a == b,
124 (Self::Object(a), Self::Object(b)) => a == b,
125 (Self::NewId(a), Self::NewId(b)) => a == b,
126 (Self::Array(a), Self::Array(b)) => a == b,
127 (Self::Fd(a), Self::Fd(b)) => a.as_raw_fd() == b.as_raw_fd(),
128 _ => false,
129 }
130 }
131}
132
133impl<Id: Eq, Fd: AsRawFd> Eq for Argument<Id, Fd> {}
134
135impl<Id: std::fmt::Display, Fd: AsRawFd> std::fmt::Display for Argument<Id, Fd> {
136 #[cfg_attr(unstable_coverage, coverage(off))]
137 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138 match self {
139 Self::Int(value) => write!(f, "{value}"),
140 Self::Uint(value) => write!(f, "{value}"),
141 Self::Fixed(value) => write!(f, "{:.4}", *value as f64 / 256.0),
142 Self::Str(value) => write!(f, "{value:?}"),
143 Self::Object(value) => write!(f, "{value}"),
144 Self::NewId(value) => write!(f, "{value}"),
145 Self::Array(value) => write!(f, "{value:?}"),
146 Self::Fd(value) => write!(f, "{}", value.as_raw_fd()),
147 }
148 }
149}
150
151#[derive(Debug)]
156pub struct Interface {
157 pub name: &'static str,
159 pub version: u32,
161 pub requests: &'static [MessageDesc],
163 pub events: &'static [MessageDesc],
165 pub c_interface: Option<&'static CWlInterface>,
167}
168
169#[derive(Debug)]
171#[repr(transparent)]
172pub struct CWlInterface(pub(crate) wl_interface);
173
174unsafe impl Sync for CWlInterface {}
175
176impl CWlInterface {
177 #[cfg(any(feature = "client_system", feature = "server_system"))]
179 pub const fn new(
180 name: &'static CStr,
181 version: u32,
182 requests: &'static [CWlMessage],
183 events: &'static [CWlMessage],
184 ) -> Self {
185 Self(wl_interface {
186 name: name.as_ptr(),
187 version: version as _,
188 request_count: requests.len() as _,
189 requests: requests.as_ptr() as _,
190 event_count: events.len() as _,
191 events: events.as_ptr() as _,
192 })
193 }
194
195 #[cfg(not(any(feature = "client_system", feature = "server_system")))]
197 pub const fn new(
198 name: &'static CStr,
199 version: u32,
200 requests: &'static [CWlMessage],
201 events: &'static [CWlMessage],
202 ) -> Self {
203 let _ = (name, version, requests, events);
204 Self(std::marker::PhantomData)
205 }
206}
207
208#[allow(missing_debug_implementations)]
210#[repr(transparent)]
211pub struct CWlMessage(wl_message);
212
213unsafe impl Sync for CWlMessage {}
214
215impl CWlMessage {
216 #[cfg(any(feature = "client_system", feature = "server_system"))]
218 pub const fn new(
219 name: &'static CStr,
220 signature: &'static CStr,
221 types: &'static [Option<&'static CWlInterface>],
223 ) -> Self {
224 Self(wl_message {
225 name: name.as_ptr(),
226 signature: signature.as_ptr(),
227 types: types.as_ptr() as *const *const wl_interface,
228 })
229 }
230
231 #[cfg(not(any(feature = "client_system", feature = "server_system")))]
233 pub const fn new(
234 name: &'static CStr,
235 signature: &'static CStr,
236 types: &'static [Option<&'static CWlInterface>],
237 ) -> Self {
238 let _ = (name, signature, types);
239 Self(std::marker::PhantomData)
240 }
241}
242
243impl std::fmt::Display for Interface {
244 #[cfg_attr(unstable_coverage, coverage(off))]
245 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
246 f.write_str(self.name)
247 }
248}
249
250#[derive(Copy, Clone, Debug)]
252pub struct MessageDesc {
253 pub name: &'static str,
255 pub signature: &'static [ArgumentType],
257 pub since: u32,
259 pub is_destructor: bool,
261 pub child_interface: Option<&'static Interface>,
265 pub arg_interfaces: &'static [&'static Interface],
267}
268
269pub static ANONYMOUS_INTERFACE: Interface =
271 Interface { name: "<anonymous>", version: 0, requests: &[], events: &[], c_interface: None };
272
273#[derive(Copy, Clone, Debug)]
275pub struct ObjectInfo {
276 pub id: u32,
278 pub interface: &'static Interface,
280 pub version: u32,
282}
283
284#[derive(Clone, Debug)]
289pub struct ProtocolError {
290 pub code: u32,
295 pub object_id: u32,
297 pub object_interface: String,
299 pub message: String,
301}
302
303pub const INLINE_ARGS: usize = 4;
309
310#[derive(Clone, Debug)]
312pub struct Message<Id, Fd> {
313 pub sender_id: Id,
315 pub opcode: u16,
317 pub args: smallvec::SmallVec<[Argument<Id, Fd>; INLINE_ARGS]>,
319}
320
321impl<Id, Fd> Message<Id, Fd> {
322 pub fn map_fd<T>(self, mut f: impl FnMut(Fd) -> T) -> Message<Id, T> {
324 Message {
325 sender_id: self.sender_id,
326 opcode: self.opcode,
327 args: self.args.into_iter().map(move |arg| arg.map_fd(&mut f)).collect(),
328 }
329 }
330}
331
332impl<Id: PartialEq, Fd: AsRawFd> PartialEq for Message<Id, Fd> {
333 fn eq(&self, other: &Self) -> bool {
334 self.sender_id == other.sender_id && self.opcode == other.opcode && self.args == other.args
335 }
336}
337
338impl<Id: Eq, Fd: AsRawFd> Eq for Message<Id, Fd> {}
339
340impl std::error::Error for ProtocolError {}
341
342impl std::fmt::Display for ProtocolError {
343 #[cfg_attr(unstable_coverage, coverage(off))]
344 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
345 if self.message.is_empty() {
346 write!(
348 f,
349 "Protocol error {} on object {}@{}",
350 self.code, self.object_interface, self.object_id
351 )
352 } else {
353 write!(
354 f,
355 "Protocol error {} on object {}@{}: {}",
356 self.code, self.object_interface, self.object_id, self.message
357 )
358 }
359 }
360}
361
362#[inline]
364pub fn same_interface(a: &'static Interface, b: &'static Interface) -> bool {
365 std::ptr::eq(a, b) || a.name == b.name
366}
367
368pub(crate) fn check_for_signature<Id, Fd>(
369 signature: &[ArgumentType],
370 args: &[Argument<Id, Fd>],
371) -> bool {
372 if signature.len() != args.len() {
373 return false;
374 }
375 for (typ, arg) in signature.iter().copied().zip(args.iter()) {
376 if !arg.get_type().same_type(typ) {
377 return false;
378 }
379 }
380 true
381}
382
383#[inline]
384#[allow(dead_code)]
385pub(crate) fn same_interface_or_anonymous(a: &'static Interface, b: &'static Interface) -> bool {
386 same_interface(a, b) || same_interface(a, &ANONYMOUS_INTERFACE)
387}