use std::borrow::Cow;
use std::convert::TryInto;
use crate::errors::ParseError;
use crate::utils::RawFdContainer;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct ExtensionInformation {
pub major_opcode: u8,
pub first_event: u8,
pub first_error: u8,
}
pub trait ExtInfoProvider {
fn get_from_major_opcode(&self, major_opcode: u8) -> Option<(&str, ExtensionInformation)>;
fn get_from_event_code(&self, event_code: u8) -> Option<(&str, ExtensionInformation)>;
fn get_from_error_code(&self, error_code: u8) -> Option<(&str, ExtensionInformation)>;
}
pub trait TryParse: Sized {
fn try_parse(value: &[u8]) -> Result<(Self, &[u8]), ParseError>;
}
pub trait TryParseFd: Sized {
fn try_parse_fd<'a>(
value: &'a [u8],
fds: &mut Vec<RawFdContainer>,
) -> Result<(Self, &'a [u8]), ParseError>;
}
impl<T: TryParse> TryParseFd for T {
fn try_parse_fd<'a>(
value: &'a [u8],
_: &mut Vec<RawFdContainer>,
) -> Result<(Self, &'a [u8]), ParseError> {
T::try_parse(value)
}
}
#[derive(Debug, Clone, Copy)]
pub struct RequestHeader {
pub major_opcode: u8,
pub minor_opcode: u8,
pub remaining_length: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BigRequests {
Enabled,
NotEnabled,
}
pub fn parse_request_header(
input: &[u8],
big_requests_enabled: BigRequests,
) -> Result<(RequestHeader, &[u8]), ParseError> {
let (major_opcode, remaining) = u8::try_parse(input)?;
let (minor_opcode, remaining) = u8::try_parse(remaining)?;
let (length, remaining) = u16::try_parse(remaining)?;
let (remaining_length, finally_remaining) = if length == 0 {
if big_requests_enabled == BigRequests::NotEnabled {
return Err(ParseError::ParseError);
}
let (length, remaining) = u32::try_parse(remaining)?;
if length < 2 {
return Err(ParseError::ParseError);
}
(length - 2, remaining)
} else {
(u32::from(length) - 1, remaining)
};
Ok((
RequestHeader {
major_opcode,
minor_opcode,
remaining_length,
},
finally_remaining,
))
}
pub trait Request {
type Reply: Into<crate::protocol::Reply> + TryParseFd;
fn parse_reply<'a>(
bytes: &'a [u8],
fds: &mut Vec<RawFdContainer>,
) -> Result<(crate::protocol::Reply, &'a [u8]), ParseError> {
let (reply, remaining) = Self::Reply::try_parse_fd(bytes, fds)?;
Ok((reply.into(), remaining))
}
}
pub type ReplyParsingFunction =
for<'a> fn(
&'a [u8],
&mut Vec<RawFdContainer>,
) -> Result<(crate::protocol::Reply, &'a [u8]), ParseError>;
pub trait Serialize {
type Bytes;
fn serialize(&self) -> Self::Bytes;
fn serialize_into(&self, bytes: &mut Vec<u8>);
}
macro_rules! implement_try_parse {
($t:ty) => {
impl TryParse for $t {
fn try_parse(value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let len = std::mem::size_of::<$t>();
let bytes = value
.get(..len)
.ok_or(ParseError::ParseError)?
.try_into()
.unwrap();
Ok((<$t>::from_ne_bytes(bytes), &value[len..]))
}
}
};
}
macro_rules! implement_serialize {
($t:ty: $size:expr) => {
impl Serialize for $t {
type Bytes = [u8; $size];
fn serialize(&self) -> Self::Bytes {
self.to_ne_bytes()
}
fn serialize_into(&self, bytes: &mut Vec<u8>) {
bytes.extend_from_slice(&self.to_ne_bytes());
}
}
};
}
macro_rules! forward_float {
($from:ty: $to:ty) => {
impl TryParse for $from {
fn try_parse(value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let (data, remaining) = <$to>::try_parse(value)?;
Ok((<$from>::from_bits(data), remaining))
}
}
impl Serialize for $from {
type Bytes = <$to as Serialize>::Bytes;
fn serialize(&self) -> Self::Bytes {
self.to_bits().serialize()
}
fn serialize_into(&self, bytes: &mut Vec<u8>) {
self.to_bits().serialize_into(bytes);
}
}
};
}
implement_try_parse!(u8);
implement_try_parse!(i8);
implement_try_parse!(u16);
implement_try_parse!(i16);
implement_try_parse!(u32);
implement_try_parse!(i32);
implement_try_parse!(u64);
implement_try_parse!(i64);
implement_serialize!(u8: 1);
implement_serialize!(i8: 1);
implement_serialize!(u16: 2);
implement_serialize!(i16: 2);
implement_serialize!(u32: 4);
implement_serialize!(i32: 4);
implement_serialize!(u64: 8);
implement_serialize!(i64: 8);
forward_float!(f32: u32);
forward_float!(f64: u64);
impl TryParse for bool {
fn try_parse(value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let (data, remaining) = u8::try_parse(value)?;
Ok((data != 0, remaining))
}
}
impl Serialize for bool {
type Bytes = [u8; 1];
fn serialize(&self) -> Self::Bytes {
[u8::from(*self)]
}
fn serialize_into(&self, bytes: &mut Vec<u8>) {
bytes.push(u8::from(*self));
}
}
macro_rules! tuple_try_parse {
($($name:ident)*) => {
impl<$($name,)*> TryParse for ($($name,)*)
where $($name: TryParse,)*
{
#[allow(non_snake_case)]
fn try_parse(remaining: &[u8]) -> Result<(($($name,)*), &[u8]), ParseError> {
$(let ($name, remaining) = $name::try_parse(remaining)?;)*
Ok((($($name,)*), remaining))
}
}
}
}
macro_rules! tuple_serialize {
($($name:ident:$idx:tt)*) => {
impl<$($name,)*> Serialize for ($($name,)*)
where $($name: Serialize,)*
{
type Bytes = Vec<u8>;
fn serialize(&self) -> Self::Bytes {
let mut result = Vec::new();
self.serialize_into(&mut result);
result
}
fn serialize_into(&self, bytes: &mut Vec<u8>) {
$(self.$idx.serialize_into(bytes);)*
}
}
}
}
macro_rules! tuple_impls {
($($name:ident:$idx:tt)*) => {
tuple_try_parse!($($name)*);
tuple_serialize!($($name:$idx)*);
}
}
impl Serialize for () {
type Bytes = [u8; 0];
fn serialize(&self) -> Self::Bytes {
[]
}
fn serialize_into(&self, _bytes: &mut Vec<u8>) {}
}
impl<T: Serialize> Serialize for (T,) {
type Bytes = T::Bytes;
fn serialize(&self) -> Self::Bytes {
self.0.serialize()
}
fn serialize_into(&self, bytes: &mut Vec<u8>) {
self.0.serialize_into(bytes)
}
}
tuple_try_parse!();
tuple_try_parse!(A);
tuple_impls!(A:0 B:1);
tuple_impls!(A:0 B:1 C:2);
tuple_impls!(A:0 B:1 C:2 D:3);
tuple_impls!(A:0 B:1 C:2 D:3 E:4);
tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5);
tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6);
tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7);
tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 I:8);
tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 I:8 J:9);
tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 I:8 J:9 K:10);
tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 I:8 J:9 K:10 L:11);
tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 I:8 J:9 K:10 L:11 M:12);
tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 I:8 J:9 K:10 L:11 M:12 N:13);
tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 I:8 J:9 K:10 L:11 M:12 N:13 O:14);
pub fn parse_list<T>(data: &[u8], list_length: usize) -> Result<(Vec<T>, &[u8]), ParseError>
where
T: TryParse,
{
let mut remaining = data;
let mut result = Vec::with_capacity(list_length);
for _ in 0..list_length {
let (entry, new_remaining) = T::try_parse(remaining)?;
result.push(entry);
remaining = new_remaining;
}
Ok((result, remaining))
}
pub fn parse_u8_list(data: &[u8], list_length: usize) -> Result<(&[u8], &[u8]), ParseError> {
if data.len() < list_length {
Err(ParseError::ParseError)
} else {
Ok(data.split_at(list_length))
}
}
impl<T: Serialize> Serialize for [T] {
type Bytes = Vec<u8>;
fn serialize(&self) -> Self::Bytes {
let mut result = Vec::new();
self.serialize_into(&mut result);
result
}
fn serialize_into(&self, bytes: &mut Vec<u8>) {
for item in self {
item.serialize_into(bytes);
}
}
}
macro_rules! bitmask_binop {
($t:ty, $u:ty) => {
impl std::ops::BitOr for $t {
type Output = $u;
fn bitor(self, other: Self) -> Self::Output {
Self::Output::from(self) | Self::Output::from(other)
}
}
impl std::ops::BitOr<$u> for $t {
type Output = $u;
fn bitor(self, other: $u) -> Self::Output {
Self::Output::from(self) | other
}
}
impl std::ops::BitOr<$t> for $u {
type Output = $u;
fn bitor(self, other: $t) -> Self::Output {
self | Self::Output::from(other)
}
}
impl std::ops::BitOrAssign<$t> for $u {
fn bitor_assign(&mut self, other: $t) {
*self |= Self::from(other)
}
}
};
}
#[macro_export]
macro_rules! atom_manager {
{
$vis:vis $struct_name:ident: $cookie_name:ident {
$($field_name:ident$(: $atom_value:expr)?,)*
}
} => {
#[allow(non_snake_case)]
#[derive(Debug)]
$vis struct $cookie_name<'a, C: $crate::protocol::xproto::ConnectionExt> {
phantom: std::marker::PhantomData<&'a C>,
$(
$field_name: $crate::cookie::Cookie<'a, C, $crate::protocol::xproto::InternAtomReply>,
)*
}
#[allow(non_snake_case)]
#[derive(Debug, Clone, Copy)]
$vis struct $struct_name {
$(
$vis $field_name: $crate::protocol::xproto::Atom,
)*
}
impl $struct_name {
$vis fn new<C: $crate::protocol::xproto::ConnectionExt>(
_conn: &C,
) -> ::std::result::Result<$cookie_name<'_, C>, $crate::errors::ConnectionError> {
Ok($cookie_name {
phantom: std::marker::PhantomData,
$(
$field_name: _conn.intern_atom(
false,
$crate::__atom_manager_atom_value!($field_name$(: $atom_value)?),
)?,
)*
})
}
}
impl<'a, C: $crate::protocol::xproto::ConnectionExt> $cookie_name<'a, C> {
$vis fn reply(self) -> ::std::result::Result<$struct_name, $crate::errors::ReplyError> {
Ok($struct_name {
$(
$field_name: self.$field_name.reply()?.atom,
)*
})
}
}
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! __atom_manager_atom_value {
($field_name:ident) => {
stringify!($field_name).as_bytes()
};
($field_name:ident: $atom_value:expr) => {
$atom_value
};
}
#[allow(clippy::ptr_arg)]
pub(crate) fn cow_strip_length(cow: &Cow<'_, [u8; 32]>) -> Cow<'static, [u8]> {
Cow::Owned(cow.to_vec())
}