1use 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 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 let dst = buf.as_ptr().add(1) as *mut u8;
76
77 std::ptr::copy_nonoverlapping(self.0.as_ptr(), dst, self.0.len());
80
81 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 pub fn encode(&self, buf: &mut [u32]) -> usize {
105 let bytes = self.0.as_bytes();
106 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 let dst = buf.as_ptr().add(1) as *mut u8;
118
119 std::ptr::copy_nonoverlapping(bytes.as_ptr(), dst, bytes.len());
122
123 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}