Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make resolve_error public API #266

Merged
merged 3 commits into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 14 additions & 11 deletions build/cg/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,17 @@ impl CodeGen {
}
writeln!(out, "}}")?;

writeln!(out)?;
writeln!(out, "impl Error {{")?;
writeln!(out, " pub fn as_raw(&self) -> *mut xcb_generic_error_t {{")?;
writeln!(out, " match self {{")?;
for error in &self.errors {
writeln!(out, " Self::{}(e) => e.as_raw(),", error.variant)?;
}
writeln!(out, " }}")?;
writeln!(out, " }}")?;
writeln!(out, "}}")?;

self.emit_resolve_wire_error(out)?;

Ok(())
Expand All @@ -218,7 +229,7 @@ impl CodeGen {
fn emit_resolve_wire_error<O: Write>(&self, out: &mut O) -> io::Result<()> {
writeln!(out)?;
writeln!(out, "impl base::ResolveWireError for Error {{")?;
writeln!(out, "{}unsafe fn resolve_wire_error(first_error: u8, raw: *mut xcb_generic_error_t) -> Self {{", cg::ind(1))?;
writeln!(out, "{}unsafe fn resolve_wire_error(first_error: u8, raw: *mut xcb_generic_error_t) -> std::option::Option<Self> {{", cg::ind(1))?;
writeln!(out, "{}debug_assert!(!raw.is_null());", cg::ind(2))?;
writeln!(out, "{}let error_code = (*raw).error_code;", cg::ind(2))?;
writeln!(out, "{}match error_code - first_error {{", cg::ind(2))?;
Expand All @@ -228,22 +239,14 @@ impl CodeGen {
}
writeln!(
out,
"{}{} => Error::{}({}::from_raw(raw)),",
"{}{} => std::option::Option::Some(Error::{}({}::from_raw(raw))),",
cg::ind(3),
error.number,
error.variant,
error.rs_typ
)?;
}
writeln!(out, "{}_ => unreachable!(", cg::ind(3))?;
writeln!(
out,
"{}\"Could not resolve {} Error with error_code {{}} and first_error {{}}\",",
cg::ind(4),
self.xcb_mod
)?;
writeln!(out, "{}error_code, first_error", cg::ind(4))?;
writeln!(out, "{}),", cg::ind(3))?;
writeln!(out, "{}_ => std::option::Option::None,", cg::ind(3))?;
writeln!(out, "{}}}", cg::ind(2))?;
writeln!(out, "{}}}", cg::ind(1))?;
writeln!(out, "}}")?;
Expand Down
4 changes: 2 additions & 2 deletions build/cg/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -654,14 +654,14 @@ impl CodeGen {

writeln!(
out,
"{}{} => Some(Event::{}({}::from_raw(raw))),",
"{}{} => std::option::Option::Some(Event::{}({}::from_raw(raw))),",
cg::ind(3),
event.number,
event.variant,
event.rs_typ
)?;
}
writeln!(out, "{}_ => None,", cg::ind(3))?;
writeln!(out, "{}_ => std::option::Option::None,", cg::ind(3))?;
writeln!(out, "{}}}", cg::ind(2))?;
writeln!(out, "{}}}", cg::ind(1))?;
writeln!(out, "}}")?;
Expand Down
32 changes: 20 additions & 12 deletions src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,6 @@
/// Resolve a pointer to `xcb_generic_event_t` to `Self`, inferring the correct subtype
/// using `response_type` field and `first_event`
///
/// # Panics
/// Panics if the event subtype cannot be resolved to `Self`. That is,
/// `response_type` field must be checked beforehand to be in range with
/// `first_event`.
///
/// # Safety
/// `event` must be a valid, non-null event returned by `xcb_wait_for_event`
/// or similar function
Expand Down Expand Up @@ -163,19 +158,14 @@
///
/// `Self` is normally an enum of several event subtypes.
/// See [crate::x::Error] and [crate::ProtocolError]
pub(crate) trait ResolveWireError {
pub(crate) trait ResolveWireError: Sized {
/// Convert a pointer to `xcb_generic_error_t` to `Self`, inferring the correct subtype
/// using `response_type` field and `first_error`.
///
/// # Panics
/// Panics if the error subtype cannot be resolved for `self`. That is,
/// `response_type` field must be checked beforehand to be in range with
/// `first_error`.
///
/// # Safety
/// `err` must be a valid, non-null error obtained by `xcb_wait_for_reply`
/// or similar function
unsafe fn resolve_wire_error(first_error: u8, error: *mut xcb_generic_error_t) -> Self;
unsafe fn resolve_wire_error(first_error: u8, error: *mut xcb_generic_error_t) -> Option<Self>;
}

/// Trait for types that can serialize themselves to the X wire.
Expand Down Expand Up @@ -1095,6 +1085,14 @@
self.ext_data.iter().map(|eed| eed.ext)
}

/// Get the data of the extensions activated for this connection.
///
/// You may use this to manually resolve an event or an error with
/// `xcb::event::resolve_event` or `xcb::error::resolve_error`.
pub fn active_extensions_data(&self) -> &[ExtensionData] {
&self.ext_data
}

/// Returns the inner ffi `xcb_connection_t` pointer
pub fn get_raw_conn(&self) -> *mut xcb_connection_t {
self.c
Expand Down Expand Up @@ -1218,6 +1216,16 @@
event::resolve_event(ev, &self.ext_data)
}

/// Resolve an xcb_generic_error_t pointer into an Error.
/// # Safety
/// The caller is repsonsible to ensure that the `err` pointer is not NULL.
/// The ownership of the pointer is effectively transferred to the
/// returned Error and it will be destroyed when the Error is
/// dropped.
pub unsafe fn resolve_error(&self, err: &mut xcb_generic_error_t) -> error::ProtocolError {
error::resolve_error(err, &self.ext_data)
}

/// Blocks and returns the next event or error from the server.
///
/// # Example
Expand Down Expand Up @@ -1309,9 +1317,9 @@
unsafe {
let ext: *mut xcb_extension_t = match XGE::EXTENSION {
#[cfg(feature = "xinput")]
Extension::Input => &mut xinput::FFI_EXT as *mut _,

Check warning on line 1320 in src/base.rs

View workflow job for this annotation

GitHub Actions / Build and Test

creating a mutable reference to mutable static is discouraged
#[cfg(feature = "present")]
Extension::Present => &mut present::FFI_EXT as *mut _,

Check warning on line 1322 in src/base.rs

View workflow job for this annotation

GitHub Actions / Build and Test

creating a mutable reference to mutable static is discouraged

Check warning on line 1322 in src/base.rs

View workflow job for this annotation

GitHub Actions / Build and Test

creating a mutable reference to mutable static is discouraged
_ => unreachable!("only Input and Present have XGE events"),
};

Expand Down Expand Up @@ -1370,9 +1378,9 @@
unsafe {
let ext: *mut xcb_extension_t = match extension {
#[cfg(feature = "xinput")]
Extension::Input => &mut xinput::FFI_EXT as *mut _,

Check warning on line 1381 in src/base.rs

View workflow job for this annotation

GitHub Actions / Build and Test

creating a mutable reference to mutable static is discouraged

Check warning on line 1381 in src/base.rs

View workflow job for this annotation

GitHub Actions / Build and Test

creating a mutable reference to mutable static is discouraged
#[cfg(feature = "present")]
Extension::Present => &mut present::FFI_EXT as *mut _,

Check warning on line 1383 in src/base.rs

View workflow job for this annotation

GitHub Actions / Build and Test

creating a mutable reference to mutable static is discouraged

Check warning on line 1383 in src/base.rs

View workflow job for this annotation

GitHub Actions / Build and Test

creating a mutable reference to mutable static is discouraged
_ => panic!("only Input and Present have XGE events"),
};

Expand Down
185 changes: 135 additions & 50 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::base::ResolveWireError;
use crate::ext::{Extension, ExtensionData};
use crate::ffi::*;
use crate::x;
use crate::{ffi::*, BaseError, Raw};
use std::mem;

#[cfg(feature = "damage")]
Expand Down Expand Up @@ -95,6 +95,42 @@ pub enum ProtocolError {
#[cfg(feature = "xv")]
/// The error is issued from the `XVideo` extension.
Xv(xv::Error, Option<&'static str>),

/// The error is unknown.
Unknown(UnknownError, Option<&'static str>),
}

impl ProtocolError {
pub fn as_raw(&self) -> *mut xcb_generic_error_t {
match self {
ProtocolError::X(e, _) => e.as_raw(),
#[cfg(feature = "damage")]
ProtocolError::Damage(e, _) => e.as_raw(),
#[cfg(feature = "glx")]
ProtocolError::Glx(e, _) => e.as_raw(),
#[cfg(feature = "randr")]
ProtocolError::RandR(e, _) => e.as_raw(),
#[cfg(feature = "render")]
ProtocolError::Render(e, _) => e.as_raw(),
#[cfg(feature = "shm")]
ProtocolError::Shm(e, _) => e.as_raw(),
#[cfg(feature = "sync")]
ProtocolError::Sync(e, _) => e.as_raw(),
#[cfg(feature = "xf86vidmode")]
ProtocolError::Xf86VidMode(e, _) => e.as_raw(),
#[cfg(feature = "xfixes")]
ProtocolError::XFixes(e, _) => e.as_raw(),
#[cfg(feature = "xinput")]
ProtocolError::Input(e, _) => e.as_raw(),
#[cfg(feature = "xkb")]
ProtocolError::Xkb(e, _) => e.as_raw(),
#[cfg(feature = "xprint")]
ProtocolError::XPrint(e, _) => e.as_raw(),
#[cfg(feature = "xv")]
ProtocolError::Xv(e, _) => e.as_raw(),
ProtocolError::Unknown(e, _) => e.as_raw(),
}
}
}

impl std::fmt::Display for ProtocolError {
Expand All @@ -105,7 +141,71 @@ impl std::fmt::Display for ProtocolError {

impl std::error::Error for ProtocolError {}

pub(crate) unsafe fn resolve_error(
/// an error that was not recognized as part of the core protocol or any enabled extension
pub struct UnknownError {
raw: *mut xcb_generic_error_t,
}

impl Raw<xcb_generic_error_t> for UnknownError {
unsafe fn from_raw(raw: *mut xcb_generic_error_t) -> Self {
UnknownError { raw }
}

fn as_raw(&self) -> *mut xcb_generic_error_t {
self.raw
}
}

impl BaseError for UnknownError {
const EXTENSION: Option<Extension> = None;
const NUMBER: u32 = u32::MAX;
}

impl UnknownError {
pub fn response_type(&self) -> u8 {
unsafe { (*self.raw).response_type }
}
pub fn sequence(&self) -> u16 {
unsafe { (*self.raw).sequence }
}
pub fn resource_id(&self) -> u32 {
unsafe { (*self.raw).resource_id }
}
pub fn minor_code(&self) -> u16 {
unsafe { (*self.raw).minor_code }
}
pub fn major_code(&self) -> u8 {
unsafe { (*self.raw).major_code }
}
pub fn full_sequence(&self) -> u32 {
unsafe { (*self.raw).full_sequence }
}
}

unsafe impl Send for UnknownError {}
unsafe impl Sync for UnknownError {}

impl std::fmt::Debug for UnknownError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("UnknownError").finish()
}
}

impl Drop for UnknownError {
fn drop(&mut self) {
unsafe { libc::free(self.raw as *mut _) }
}
}

/// Resolve an error from the X server
///
/// If the error originates from an extension, the `extension_data` parameter must contain the
/// data for the extension of origin.
/// If the resolution fails, an `ProtocolError::Unknown` is returned.
///
/// # Safety
/// The caller must ensure that `error` is a valid pointer to an `xcb_generic_error_t`.
pub unsafe fn resolve_error(
error: *mut xcb_generic_error_t,
extension_data: &[ExtensionData],
) -> ProtocolError {
Expand Down Expand Up @@ -228,79 +328,64 @@ pub(crate) unsafe fn resolve_error(
crate::x::request_name(major_code as u16)
};

if let Some(ext_data) = best {
let resolved: Option<ProtocolError> = if let Some(ext_data) = best {
match ext_data.ext {
#[cfg(feature = "damage")]
Extension::Damage => ProtocolError::Damage(
damage::Error::resolve_wire_error(ext_data.first_error, error),
emitted_by,
),
Extension::Damage => damage::Error::resolve_wire_error(ext_data.first_error, error)
.map(|e| ProtocolError::Damage(e, emitted_by)),

#[cfg(feature = "glx")]
Extension::Glx => ProtocolError::Glx(
glx::Error::resolve_wire_error(ext_data.first_error, error),
emitted_by,
),
Extension::Glx => glx::Error::resolve_wire_error(ext_data.first_error, error)
.map(|e| ProtocolError::Glx(e, emitted_by)),

#[cfg(feature = "randr")]
Extension::RandR => ProtocolError::RandR(
randr::Error::resolve_wire_error(ext_data.first_error, error),
emitted_by,
),
Extension::RandR => randr::Error::resolve_wire_error(ext_data.first_error, error)
.map(|e| ProtocolError::RandR(e, emitted_by)),

#[cfg(feature = "render")]
Extension::Render => render::Error::resolve_wire_error(ext_data.first_error, error)
.map(|e| ProtocolError::Render(e, emitted_by)),

#[cfg(feature = "shm")]
Extension::Shm => ProtocolError::Shm(
shm::Error::resolve_wire_error(ext_data.first_error, error),
emitted_by,
),
Extension::Shm => shm::Error::resolve_wire_error(ext_data.first_error, error)
.map(|e| ProtocolError::Shm(e, emitted_by)),

#[cfg(feature = "sync")]
Extension::Sync => ProtocolError::Sync(
sync::Error::resolve_wire_error(ext_data.first_error, error),
emitted_by,
),
Extension::Sync => sync::Error::resolve_wire_error(ext_data.first_error, error)
.map(|e| ProtocolError::Sync(e, emitted_by)),

#[cfg(feature = "xf86vidmode")]
Extension::Xf86VidMode => ProtocolError::Xf86VidMode(
xf86vidmode::Error::resolve_wire_error(ext_data.first_error, error),
emitted_by,
),
Extension::Xf86VidMode => {
xf86vidmode::Error::resolve_wire_error(ext_data.first_error, error)
.map(|e| ProtocolError::Xf86VidMode(e, emitted_by))
}

#[cfg(feature = "xfixes")]
Extension::XFixes => ProtocolError::XFixes(
xfixes::Error::resolve_wire_error(ext_data.first_error, error),
emitted_by,
),
Extension::XFixes => xfixes::Error::resolve_wire_error(ext_data.first_error, error)
.map(|e| ProtocolError::XFixes(e, emitted_by)),

#[cfg(feature = "xinput")]
Extension::Input => ProtocolError::Input(
xinput::Error::resolve_wire_error(ext_data.first_error, error),
emitted_by,
),
Extension::Input => xinput::Error::resolve_wire_error(ext_data.first_error, error)
.map(|e| ProtocolError::Input(e, emitted_by)),

#[cfg(feature = "xkb")]
Extension::Xkb => ProtocolError::Xkb(
xkb::Error::resolve_wire_error(ext_data.first_error, error),
emitted_by,
),
Extension::Xkb => xkb::Error::resolve_wire_error(ext_data.first_error, error)
.map(|e| ProtocolError::Xkb(e, emitted_by)),

#[cfg(feature = "xprint")]
Extension::XPrint => ProtocolError::XPrint(
xprint::Error::resolve_wire_error(ext_data.first_error, error),
emitted_by,
),
Extension::XPrint => xprint::Error::resolve_wire_error(ext_data.first_error, error)
.map(|e| ProtocolError::XPrint(e, emitted_by)),

#[cfg(feature = "xv")]
Extension::Xv => ProtocolError::Xv(
xv::Error::resolve_wire_error(ext_data.first_error, error),
emitted_by,
),
Extension::Xv => xv::Error::resolve_wire_error(ext_data.first_error, error)
.map(|e| ProtocolError::Xv(e, emitted_by)),

_ => unreachable!("Could not match extension event"),
_ => None,
}
} else {
ProtocolError::X(x::Error::resolve_wire_error(0, error), emitted_by)
}
x::Error::resolve_wire_error(0, error).map(|e| ProtocolError::X(e, emitted_by))
};
resolved.unwrap_or_else(|| ProtocolError::Unknown(UnknownError::from_raw(error), emitted_by))
}

#[cfg(all(feature = "xinput", feature = "xkb", feature = "screensaver"))]
Expand Down
14 changes: 13 additions & 1 deletion src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,19 @@ impl Drop for UnknownEvent {
}
}

pub(crate) unsafe fn resolve_event(
/// Resolve an event from the X server
///
/// If the event originates from an extension, the `extension_data` parameter must contain the
/// data for the extension of origin.
/// If the resolution fails, an `Event::Unknown` is returned.
///
/// # Panics
/// The function will panic if the matches with an `XCB_GE_GENERIC` event, but can't
/// be resolved as such.
///
/// # Safety
/// The caller must ensure that `event` is a valid pointer to an `xcb_generic_event_t`.
pub unsafe fn resolve_event(
event: *mut xcb_generic_event_t,
extension_data: &[ExtensionData],
) -> Event {
Expand Down
Loading
Loading