waybackend/
types.rs

1//! This module contains the definitions of all wayland types that can go through the wire.
2
3use std::{mem::MaybeUninit, num::NonZeroU32};
4
5use crate::wire::Error;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub struct ObjectId(NonZeroU32);
9
10#[derive(Debug, Clone)]
11pub struct WlSlice<'a>(pub(crate) &'a [u8]);
12
13#[derive(Debug, Clone)]
14pub struct WlStr<'a>(pub(crate) &'a str);
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
17pub struct WlFixed(pub(crate) i32);
18
19#[derive(Debug, Clone)]
20pub struct NewId<'a> {
21    pub(crate) id: ObjectId,
22    pub(crate) interface: &'a str,
23    pub(crate) version: u32,
24}
25
26impl ObjectId {
27    #[inline]
28    #[must_use]
29    pub const fn get(&self) -> NonZeroU32 {
30        self.0
31    }
32
33    #[inline]
34    #[must_use]
35    pub const fn new(value: NonZeroU32) -> Self {
36        Self(value)
37    }
38
39    #[inline]
40    pub const fn try_new(value: u32) -> Result<Self, Error> {
41        match NonZeroU32::new(value) {
42            Some(x) => Ok(Self(x)),
43            None => Err(Error::NullObjectId),
44        }
45    }
46
47    #[inline]
48    #[must_use]
49    pub const fn null() -> Option<Self> {
50        None
51    }
52}
53
54impl std::fmt::Display for ObjectId {
55    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56        write!(f, "{}", self.get())
57    }
58}
59
60impl WlSlice<'_> {
61    #[inline]
62    #[must_use]
63    /// returns how many bytes we have written (including the prepended length)
64    pub fn encode(&self, buf: &mut [u32]) -> usize {
65        let len = self.0.len().next_multiple_of(4);
66        assert!(
67            len + 1 < buf.len() * 4,
68            "slice is too big ({}) to be encoded in the wayland wire format (max: {})",
69            len + 1,
70            buf.len() * 4
71        );
72        buf[0] = self.0.len() as u32;
73        unsafe {
74            // dst is the next free position in the buffer
75            let dst = buf.as_ptr().add(1) as *mut u8;
76
77            // copy all the bytes
78            // SAFETY: we've ensured the buf's pointer has the necessary size above
79            std::ptr::copy_nonoverlapping(self.0.as_ptr(), dst, self.0.len());
80
81            // 0 initialize the padding
82            for i in self.0.len()..len {
83                dst.add(i).write(0);
84            }
85        }
86        4 + len
87    }
88}
89
90impl<'a, 'b> From<&'b [u8]> for WlSlice<'a>
91where
92    'b: 'a,
93{
94    #[inline]
95    fn from(bytes: &'b [u8]) -> Self {
96        Self(bytes)
97    }
98}
99
100impl WlStr<'_> {
101    #[inline]
102    #[must_use]
103    /// returns how many bytes we have written (including the prepended length)
104    pub fn encode(&self, buf: &mut [u32]) -> usize {
105        let bytes = self.0.as_bytes();
106        // add one for the null terminator
107        let len = (bytes.len() + 1).next_multiple_of(4);
108        assert!(
109            len + 1 < buf.len() * 4,
110            "string is too big ({}) to be encoded in the wayland wire format (max: {})",
111            len + 1,
112            buf.len() * 4
113        );
114        buf[0] = self.0.len() as u32 + 1;
115        unsafe {
116            // dst is the next free position in the buffer
117            let dst = buf.as_ptr().add(1) as *mut u8;
118
119            // copy all the bytes
120            // SAFETY: we've ensured the buf's pointer has the necessary size above
121            std::ptr::copy_nonoverlapping(bytes.as_ptr(), dst, bytes.len());
122
123            // 0 initialize the padding and the null terminator
124            for i in bytes.len()..len {
125                dst.add(i).write(0);
126            }
127        }
128        4 + len
129    }
130}
131
132impl<'a, 'b> From<&'b str> for WlStr<'a>
133where
134    'b: 'a,
135{
136    #[inline]
137    fn from(s: &'b str) -> Self {
138        Self(s)
139    }
140}
141
142impl From<i32> for WlFixed {
143    #[inline]
144    fn from(value: i32) -> Self {
145        Self(value * 256)
146    }
147}
148
149impl From<u32> for WlFixed {
150    #[inline]
151    fn from(value: u32) -> Self {
152        Self(value as i32 * 256)
153    }
154}
155
156impl From<&WlFixed> for i32 {
157    #[inline]
158    fn from(val: &WlFixed) -> Self {
159        val.0 / 256
160    }
161}
162
163impl From<f64> for WlFixed {
164    #[inline]
165    fn from(value: f64) -> Self {
166        let d = value + (3i64 << (51 - 8)) as f64;
167        Self(d.to_bits() as i32)
168    }
169}
170
171impl From<&WlFixed> for f64 {
172    #[inline]
173    fn from(val: &WlFixed) -> Self {
174        let i = ((1023i64 + 44i64) << 52) + (1i64 << 51) + val.0 as i64;
175        let d = f64::from_bits(i as u64);
176        d - (3i64 << 43) as f64
177    }
178}
179
180impl NewId<'_> {
181    #[inline]
182    #[must_use]
183    pub fn id(&self) -> ObjectId {
184        self.id
185    }
186
187    #[inline]
188    #[must_use]
189    pub fn interface(&self) -> &str {
190        self.interface
191    }
192
193    #[inline]
194    #[must_use]
195    pub fn version(&self) -> u32 {
196        self.version
197    }
198}
199
200pub(crate) const fn u32_slice_to_u8(src: &[u32]) -> &[u8] {
201    let len = src.len() << 2;
202    unsafe { std::slice::from_raw_parts(src.as_ptr().cast(), len) }
203}
204
205pub(crate) const fn u32_slice_to_u8_mut(src: &mut [u32]) -> &mut [u8] {
206    let len = src.len() << 2;
207    unsafe { std::slice::from_raw_parts_mut(src.as_mut_ptr().cast(), len) }
208}
209
210pub(crate) const fn i32_slice_to_u8_mut(src: &mut [MaybeUninit<i32>]) -> &mut [MaybeUninit<u8>] {
211    let len = src.len() << 2;
212    unsafe { std::slice::from_raw_parts_mut(src.as_mut_ptr().cast(), len) }
213}
214
215#[cfg(test)]
216mod tests {
217    use super::*;
218
219    #[test]
220    fn fixed_creation() {
221        assert_eq!(WlFixed::from(-1), WlFixed::from(0xFFFFFFFFu32));
222    }
223
224    #[test]
225    fn slice_encoding() {
226        let mut buf = vec![0; 3];
227
228        let arr = [1u8, 2, 3, 4, 5, 6, 7];
229        let len = WlSlice::from(arr.as_ref()).encode(&mut buf) / 4;
230
231        #[cfg(target_endian = "little")]
232        let expected = [7, 0x04030201u32, 0x00070605];
233
234        #[cfg(target_endian = "big")]
235        let expected = [8, 0x01020304u32, 0x05060700];
236
237        assert_eq!(buf[..len], expected);
238
239        let arr = [1u8, 2, 3, 4];
240        let len = WlSlice::from(arr.as_ref()).encode(&mut buf) / 4;
241
242        #[cfg(target_endian = "little")]
243        let expected = [4, 0x04030201u32];
244
245        #[cfg(target_endian = "big")]
246        let expected = [4, 0x01020304u32];
247
248        assert_eq!(buf[..len], expected);
249    }
250
251    #[test]
252    fn str_encoding() {
253        let mut buf = vec![0; 4];
254
255        let len = WlStr::from("hello world").encode(&mut buf) / 4;
256
257        #[cfg(target_endian = "little")]
258        let expected = [12, 0x6C6C6568u32, 0x6F77206F, 0x00646C72];
259
260        #[cfg(target_endian = "big")]
261        let expected = [12, 0x06865C6Cu32, 0x6F20776F, 0x726C6400];
262
263        assert_eq!(buf[..len], expected);
264
265        let len = WlStr::from("hell").encode(&mut buf) / 4;
266        #[cfg(target_endian = "little")]
267        let expected = [5, 0x6C6C6568u32, 0];
268
269        #[cfg(target_endian = "big")]
270        let expected = [8, 0x06865C6Cu32, 0];
271
272        assert_eq!(buf[..len], expected);
273    }
274
275    #[test]
276    #[should_panic]
277    fn slice_encoding_should_panic() {
278        let mut buf = vec![0; 2];
279
280        let arr = [1u8, 2, 3, 4, 5, 6, 7];
281        let _ = WlSlice::from(arr.as_ref()).encode(&mut buf);
282    }
283
284    #[test]
285    #[should_panic]
286    fn str_encoding_should_panic() {
287        let mut buf = vec![0; 3];
288
289        let _ = WlStr::from("hello world").encode(&mut buf);
290    }
291}