pub mod german_string;
use core::{mem::MaybeUninit, num::NonZeroU32};
use crate::wire::Error;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ObjectId(NonZeroU32);
#[derive(Debug, Clone)]
pub struct WlSlice<'a>(pub(crate) &'a [u8]);
#[derive(Debug, Clone)]
pub struct WlStr<'a>(pub(crate) &'a str);
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct WlFixed(pub(crate) i32);
#[derive(Debug, Clone)]
pub struct NewId<'a> {
pub(crate) id: ObjectId,
pub(crate) interface: &'a str,
pub(crate) version: u32,
}
impl ObjectId {
#[inline]
#[must_use]
pub const fn get(self) -> NonZeroU32 {
self.0
}
#[inline]
#[must_use]
pub(crate) const fn new(value: NonZeroU32) -> Self {
Self(value)
}
#[inline]
pub(crate) const fn try_new(value: u32) -> Result<Self, Error> {
match NonZeroU32::new(value) {
Some(x) => Ok(Self(x)),
None => Err(Error::NullObjectId),
}
}
#[inline]
#[must_use]
pub const fn null() -> Option<Self> {
None
}
#[inline]
#[must_use]
pub const fn created_by_server(self) -> bool {
self.0.get() >= 0xFF000000
}
}
impl core::fmt::Display for ObjectId {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(rustix::path::DecInt::new(self.get().get()).as_str())
}
}
impl WlSlice<'_> {
#[inline]
#[must_use]
pub fn encode(&self, buf: &mut [u32]) -> usize {
let len = self.0.len().next_multiple_of(4);
assert!(
len + 1 < buf.len() * 4,
"slice is too big ({}) to be encoded in the wayland wire format (max: {})",
len + 1,
buf.len() * 4
);
buf[0] = self.0.len() as u32;
unsafe {
let dst = buf.as_mut_ptr().add(1) as *mut u8;
core::ptr::copy_nonoverlapping(self.0.as_ptr(), dst, self.0.len());
for i in self.0.len()..len {
dst.add(i).write(0);
}
}
4 + len
}
}
impl<'a, 'b> From<&'b [u8]> for WlSlice<'a>
where
'b: 'a,
{
#[inline]
fn from(bytes: &'b [u8]) -> Self {
Self(bytes)
}
}
impl WlStr<'_> {
#[inline]
#[must_use]
pub fn encode(&self, buf: &mut [u32]) -> usize {
let bytes = self.0.as_bytes();
let len = (bytes.len() + 1).next_multiple_of(4);
assert!(
len + 1 < buf.len() * 4,
"string is too big ({}) to be encoded in the wayland wire format (max: {})",
len + 1,
buf.len() * 4
);
buf[0] = self.0.len() as u32 + 1;
unsafe {
let dst = buf.as_mut_ptr().add(1) as *mut u8;
core::ptr::copy_nonoverlapping(bytes.as_ptr(), dst, bytes.len());
for i in bytes.len()..len {
dst.add(i).write(0);
}
}
4 + len
}
}
impl<'a, 'b> From<&'b str> for WlStr<'a>
where
'b: 'a,
{
#[inline]
fn from(s: &'b str) -> Self {
Self(s)
}
}
impl From<i32> for WlFixed {
#[inline]
fn from(value: i32) -> Self {
Self(value * 256)
}
}
impl From<u32> for WlFixed {
#[inline]
fn from(value: u32) -> Self {
Self(value as i32 * 256)
}
}
impl From<WlFixed> for i32 {
#[inline]
fn from(val: WlFixed) -> Self {
val.0 / 256
}
}
impl From<f64> for WlFixed {
#[inline]
fn from(value: f64) -> Self {
let d = value + (3i64 << (51 - 8)) as f64;
Self(d.to_bits() as i32)
}
}
impl From<WlFixed> for f64 {
#[inline]
fn from(val: WlFixed) -> Self {
let i = ((1023i64 + 44i64) << 52) + (1i64 << 51) + val.0 as i64;
let d = f64::from_bits(i as u64);
d - (3i64 << 43) as f64
}
}
impl NewId<'_> {
#[inline]
#[must_use]
pub fn id(&self) -> ObjectId {
self.id
}
#[inline]
#[must_use]
pub fn interface(&self) -> &str {
self.interface
}
#[inline]
#[must_use]
pub fn version(&self) -> u32 {
self.version
}
}
pub(crate) const fn u32_slice_to_u8(src: &[u32]) -> &[u8] {
let len = src.len() << 2;
unsafe { core::slice::from_raw_parts(src.as_ptr().cast(), len) }
}
pub(crate) const fn u32_slice_to_u8_mut(src: &mut [u32]) -> &mut [u8] {
let len = src.len() << 2;
unsafe { core::slice::from_raw_parts_mut(src.as_mut_ptr().cast(), len) }
}
pub(crate) const fn i32_slice_to_u8_mut(src: &mut [MaybeUninit<i32>]) -> &mut [MaybeUninit<u8>] {
let len = src.len() << 2;
unsafe { core::slice::from_raw_parts_mut(src.as_mut_ptr().cast(), len) }
}
#[cfg(test)]
mod tests {
extern crate std;
use super::*;
#[test]
fn fixed_creation() {
assert_eq!(WlFixed::from(-1), WlFixed::from(0xFFFFFFFFu32));
}
#[test]
fn slice_encoding() {
let mut buf = std::vec![0; 3];
let arr = [1u8, 2, 3, 4, 5, 6, 7];
let len = WlSlice::from(arr.as_ref()).encode(&mut buf) / 4;
#[cfg(target_endian = "little")]
let expected = [7, 0x04030201u32, 0x00070605];
#[cfg(target_endian = "big")]
let expected = [8, 0x01020304u32, 0x05060700];
assert_eq!(buf[..len], expected);
let arr = [1u8, 2, 3, 4];
let len = WlSlice::from(arr.as_ref()).encode(&mut buf) / 4;
#[cfg(target_endian = "little")]
let expected = [4, 0x04030201u32];
#[cfg(target_endian = "big")]
let expected = [4, 0x01020304u32];
assert_eq!(buf[..len], expected);
}
#[test]
fn str_encoding() {
let mut buf = std::vec![0; 4];
let len = WlStr::from("hello world").encode(&mut buf) / 4;
#[cfg(target_endian = "little")]
let expected = [12, 0x6C6C6568u32, 0x6F77206F, 0x00646C72];
#[cfg(target_endian = "big")]
let expected = [12, 0x06865C6Cu32, 0x6F20776F, 0x726C6400];
assert_eq!(buf[..len], expected);
let len = WlStr::from("hell").encode(&mut buf) / 4;
#[cfg(target_endian = "little")]
let expected = [5, 0x6C6C6568u32, 0];
#[cfg(target_endian = "big")]
let expected = [8, 0x06865C6Cu32, 0];
assert_eq!(buf[..len], expected);
}
#[test]
#[should_panic]
fn slice_encoding_should_panic() {
let mut buf = std::vec![0; 2];
let arr = [1u8, 2, 3, 4, 5, 6, 7];
let _ = WlSlice::from(arr.as_ref()).encode(&mut buf);
}
#[test]
#[should_panic]
fn str_encoding_should_panic() {
let mut buf = std::vec![0; 3];
let _ = WlStr::from("hello world").encode(&mut buf);
}
}