From 443cb1f885ab2e4c13a4e1bceed84cf935fb7f0f Mon Sep 17 00:00:00 2001 From: PolyMeilex Date: Sun, 11 Feb 2024 19:51:02 +0100 Subject: [PATCH] Begone delegate macros init --- wayland-scanner/src/server_gen.rs | 7 +- .../tests/scanner_assets/test-server-code.rs | 60 ++++- wayland-server/src/dispatch.rs | 222 +++++++++++++----- wayland-server/src/display.rs | 29 ++- wayland-server/src/global.rs | 20 +- wayland-server/src/lib.rs | 5 +- 6 files changed, 266 insertions(+), 77 deletions(-) diff --git a/wayland-scanner/src/server_gen.rs b/wayland-scanner/src/server_gen.rs index 8f4a27f4d12..36a8d0368b0 100644 --- a/wayland-scanner/src/server_gen.rs +++ b/wayland-scanner/src/server_gen.rs @@ -65,7 +65,7 @@ fn generate_objects_for(interface: &Interface) -> TokenStream { smallvec, ObjectData, ObjectId, InvalidId, WeakHandle, protocol::{WEnum, Argument, Message, Interface, same_interface} }, - Resource, Dispatch, DisplayHandle, DispatchError, ResourceData, New, Weak, + Resource, Dispatch, DisplayHandle, DispatchError, ResourceData, DelegatedResourceData, New, Weak, }; #enums @@ -132,6 +132,11 @@ fn generate_objects_for(interface: &Interface) -> TokenStream { self.data.as_ref().and_then(|arc| (&**arc).downcast_ref::>()).map(|data| &data.udata) } + #[inline] + fn delegated_data(&self) -> Option<&U> { + self.data.as_ref().and_then(|arc| (&**arc).downcast_ref::>()).map(|data| &data.udata) + } + #[inline] fn object_data(&self) -> Option<&Arc> { self.data.as_ref() diff --git a/wayland-scanner/tests/scanner_assets/test-server-code.rs b/wayland-scanner/tests/scanner_assets/test-server-code.rs index e6773cbc24a..9ed7b7bf330 100644 --- a/wayland-scanner/tests/scanner_assets/test-server-code.rs +++ b/wayland-scanner/tests/scanner_assets/test-server-code.rs @@ -5,10 +5,11 @@ pub mod wl_callback { protocol::{same_interface, Argument, Interface, Message, WEnum}, smallvec, InvalidId, ObjectData, ObjectId, WeakHandle, }, - Dispatch, DispatchError, DisplayHandle, New, Resource, ResourceData, Weak, + DelegatedResourceData, Dispatch, DispatchError, DisplayHandle, New, Resource, ResourceData, + Weak, }; - use std::sync::Arc; use std::os::unix::io::OwnedFd; + use std::sync::Arc; #[doc = r" The minimal object version supporting this event"] pub const EVT_DONE_SINCE: u32 = 1u32; #[doc = r" The wire opcode for this event"] @@ -97,6 +98,13 @@ pub mod wl_callback { .map(|data| &data.udata) } #[inline] + fn delegated_data(&self) -> Option<&U> { + self.data + .as_ref() + .and_then(|arc| (&**arc).downcast_ref::>()) + .map(|data| &data.udata) + } + #[inline] fn object_data(&self) -> Option<&Arc> { self.data.as_ref() } @@ -169,10 +177,11 @@ pub mod test_global { protocol::{same_interface, Argument, Interface, Message, WEnum}, smallvec, InvalidId, ObjectData, ObjectId, WeakHandle, }, - Dispatch, DispatchError, DisplayHandle, New, Resource, ResourceData, Weak, + DelegatedResourceData, Dispatch, DispatchError, DisplayHandle, New, Resource, ResourceData, + Weak, }; - use std::sync::Arc; use std::os::unix::io::OwnedFd; + use std::sync::Arc; #[doc = r" The minimal object version supporting this request"] pub const REQ_MANY_ARGS_SINCE: u32 = 1u32; #[doc = r" The wire opcode for this request"] @@ -359,6 +368,13 @@ pub mod test_global { .map(|data| &data.udata) } #[inline] + fn delegated_data(&self) -> Option<&U> { + self.data + .as_ref() + .and_then(|arc| (&**arc).downcast_ref::>()) + .map(|data| &data.udata) + } + #[inline] fn object_data(&self) -> Option<&Arc> { self.data.as_ref() } @@ -774,10 +790,11 @@ pub mod secondary { protocol::{same_interface, Argument, Interface, Message, WEnum}, smallvec, InvalidId, ObjectData, ObjectId, WeakHandle, }, - Dispatch, DispatchError, DisplayHandle, New, Resource, ResourceData, Weak, + DelegatedResourceData, Dispatch, DispatchError, DisplayHandle, New, Resource, ResourceData, + Weak, }; - use std::sync::Arc; use std::os::unix::io::OwnedFd; + use std::sync::Arc; #[doc = r" The minimal object version supporting this request"] pub const REQ_DESTROY_SINCE: u32 = 2u32; #[doc = r" The wire opcode for this request"] @@ -865,6 +882,13 @@ pub mod secondary { .map(|data| &data.udata) } #[inline] + fn delegated_data(&self) -> Option<&U> { + self.data + .as_ref() + .and_then(|arc| (&**arc).downcast_ref::>()) + .map(|data| &data.udata) + } + #[inline] fn object_data(&self) -> Option<&Arc> { self.data.as_ref() } @@ -933,10 +957,11 @@ pub mod tertiary { protocol::{same_interface, Argument, Interface, Message, WEnum}, smallvec, InvalidId, ObjectData, ObjectId, WeakHandle, }, - Dispatch, DispatchError, DisplayHandle, New, Resource, ResourceData, Weak, + DelegatedResourceData, Dispatch, DispatchError, DisplayHandle, New, Resource, ResourceData, + Weak, }; - use std::sync::Arc; use std::os::unix::io::OwnedFd; + use std::sync::Arc; #[doc = r" The minimal object version supporting this request"] pub const REQ_DESTROY_SINCE: u32 = 3u32; #[doc = r" The wire opcode for this request"] @@ -1024,6 +1049,13 @@ pub mod tertiary { .map(|data| &data.udata) } #[inline] + fn delegated_data(&self) -> Option<&U> { + self.data + .as_ref() + .and_then(|arc| (&**arc).downcast_ref::>()) + .map(|data| &data.udata) + } + #[inline] fn object_data(&self) -> Option<&Arc> { self.data.as_ref() } @@ -1092,10 +1124,11 @@ pub mod quad { protocol::{same_interface, Argument, Interface, Message, WEnum}, smallvec, InvalidId, ObjectData, ObjectId, WeakHandle, }, - Dispatch, DispatchError, DisplayHandle, New, Resource, ResourceData, Weak, + DelegatedResourceData, Dispatch, DispatchError, DisplayHandle, New, Resource, ResourceData, + Weak, }; - use std::sync::Arc; use std::os::unix::io::OwnedFd; + use std::sync::Arc; #[doc = r" The minimal object version supporting this request"] pub const REQ_DESTROY_SINCE: u32 = 3u32; #[doc = r" The wire opcode for this request"] @@ -1183,6 +1216,13 @@ pub mod quad { .map(|data| &data.udata) } #[inline] + fn delegated_data(&self) -> Option<&U> { + self.data + .as_ref() + .and_then(|arc| (&**arc).downcast_ref::>()) + .map(|data| &data.udata) + } + #[inline] fn object_data(&self) -> Option<&Arc> { self.data.as_ref() } diff --git a/wayland-server/src/dispatch.rs b/wayland-server/src/dispatch.rs index f68fc5b84dd..bb128408d73 100644 --- a/wayland-server/src/dispatch.rs +++ b/wayland-server/src/dispatch.rs @@ -166,11 +166,20 @@ impl<'a, D> DataInit<'a, D> { where D: Dispatch + 'static, { - let arc = Arc::new(ResourceData::::new(data)); - *self.store = Some(arc.clone() as Arc<_>); - let mut obj = resource.id; - obj.__set_object_data(arc); - obj + self.custom_init(resource, Arc::new(ResourceData::::new(data))) + } + + /// Initialize an object by assigning it its user-data + pub fn init_delegated( + &mut self, + resource: New, + data: U, + ) -> I + where + D: 'static, + M: Dispatch + 'static, + { + self.custom_init(resource, Arc::new(DelegatedResourceData::::new(data))) } /// Set a custom [`ObjectData`] for this object @@ -227,52 +236,69 @@ impl + 'stati client_id: wayland_backend::server::ClientId, msg: wayland_backend::protocol::Message, ) -> Option>> { - let dhandle = DisplayHandle::from(handle.clone()); - let client = match Client::from_id(&dhandle, client_id) { - Ok(v) => v, - Err(_) => { - crate::log_error!("Receiving a request from a dead client ?!"); - return None; - } - }; - - let (sender_id, opcode) = (msg.sender_id.protocol_id(), msg.opcode); - - let (resource, request) = match I::parse_request(&dhandle, msg) { - Ok(v) => v, - Err(e) => { - crate::log_warn!("Dispatching error encountered: {:?}, killing client.", e); - handle.kill_client( - client.id(), - DisconnectReason::ProtocolError(ProtocolError { - code: 1, - object_id: 0, - object_interface: "wl_display".into(), - message: format!( - "Malformed request received for id {} and opcode {}.", - sender_id, opcode - ), - }), - ); - return None; - } - }; - let udata = resource.data::().expect("Wrong user_data value for object"); - - let mut new_data = None; + on_request::(handle, data, client_id, msg, |resource| { + resource.data().expect("Wrong user_data value for object") + }) + } - >::request( + fn destroyed( + self: Arc, + handle: &wayland_backend::server::Handle, + data: &mut D, + client_id: ClientId, + object_id: ObjectId, + ) { + on_destroyed::( + self.clone(), + &self.udata, + handle, data, - &client, - &resource, - request, - udata, - &dhandle, - // The error is None since the creating object posts an error. - &mut DataInit { store: &mut new_data, error: &mut None }, - ); - - new_data + client_id, + object_id, + ) + } +} + +/// The [`ObjectData`] implementation that is internally used by this crate +#[derive(Debug)] +pub struct DelegatedResourceData { + /// The user-data associated with this object + pub udata: U, + marker: std::marker::PhantomData<(I, DelegatedTo)>, +} + +impl DelegatedResourceData { + pub(crate) fn new(udata: U) -> Self + where + D: 'static, + I: Resource + 'static, + M: Dispatch + 'static, + U: Send + Sync + 'static, + { + DelegatedResourceData { udata, marker: std::marker::PhantomData::<(I, M)> } + } +} + +unsafe impl Send for DelegatedResourceData {} +unsafe impl Sync for DelegatedResourceData {} + +impl ObjectData for DelegatedResourceData +where + I: Resource + 'static, + U: Send + Sync + 'static, + D: 'static, + DelegatedTo: Dispatch + 'static, +{ + fn request( + self: Arc, + handle: &wayland_backend::server::Handle, + data: &mut D, + client_id: wayland_backend::server::ClientId, + msg: wayland_backend::protocol::Message, + ) -> Option>> { + on_request::(handle, data, client_id, msg, |resource| { + resource.delegated_data::().expect("Wrong user_data value for object") + }) } fn destroyed( @@ -282,15 +308,99 @@ impl + 'stati client_id: ClientId, object_id: ObjectId, ) { - let dhandle = DisplayHandle::from(handle.clone()); - let mut resource = I::from_id(&dhandle, object_id).unwrap(); + on_destroyed::( + self.clone(), + &self.udata, + handle, + data, + client_id, + object_id, + ) + } +} - // Proxy::from_id will return an inert protocol object wrapper inside of ObjectData::destroyed, - // therefore manually initialize the data associated with protocol object wrapper. - resource.__set_object_data(self.clone()); +pub(crate) fn on_request( + handle: &wayland_backend::server::Handle, + data: &mut D, + client_id: wayland_backend::server::ClientId, + msg: wayland_backend::protocol::Message, + get_data: impl FnOnce(&I) -> &U, +) -> Option>> +where + I: Resource, + U: Send + Sync + 'static, + D: 'static, + DelegatedTo: Dispatch, +{ + let dhandle = DisplayHandle::from(handle.clone()); + let client = match Client::from_id(&dhandle, client_id) { + Ok(v) => v, + Err(_) => { + crate::log_error!("Receiving a request from a dead client ?!"); + return None; + } + }; - >::destroyed(data, client_id, &resource, &self.udata) - } + let (sender_id, opcode) = (msg.sender_id.protocol_id(), msg.opcode); + + let (resource, request) = match I::parse_request(&dhandle, msg) { + Ok(v) => v, + Err(e) => { + crate::log_warn!("Dispatching error encountered: {:?}, killing client.", e); + handle.kill_client( + client.id(), + DisconnectReason::ProtocolError(ProtocolError { + code: 1, + object_id: 0, + object_interface: "wl_display".into(), + message: format!( + "Malformed request received for id {} and opcode {}.", + sender_id, opcode + ), + }), + ); + return None; + } + }; + let udata = get_data(&resource); + + let mut new_data = None; + + >::request( + data, + &client, + &resource, + request, + udata, + &dhandle, + // The error is None since the creating object posts an error. + &mut DataInit { store: &mut new_data, error: &mut None }, + ); + + new_data +} + +pub(crate) fn on_destroyed( + this: Arc, + udata: &U, + handle: &wayland_backend::server::Handle, + data: &mut D, + client_id: ClientId, + object_id: ObjectId, +) where + I: Resource, + U: Send + Sync + 'static, + DATA: Send + Sync + 'static, + DelegatedTo: Dispatch, +{ + let dhandle = DisplayHandle::from(handle.clone()); + let mut resource = I::from_id(&dhandle, object_id).unwrap(); + + // Proxy::from_id will return an inert protocol object wrapper inside of ObjectData::destroyed, + // therefore manually initialize the data associated with protocol object wrapper. + resource.__set_object_data(this); + + >::destroyed(data, client_id, &resource, udata) } /// A helper macro which delegates a set of [`Dispatch`] implementations for a resource to some other type which diff --git a/wayland-server/src/display.rs b/wayland-server/src/display.rs index fb1fcaa2329..f65c24f5ddc 100644 --- a/wayland-server/src/display.rs +++ b/wayland-server/src/display.rs @@ -134,7 +134,34 @@ impl DisplayHandle { self.handle.create_global::( I::interface(), version, - Arc::new(GlobalData { data, _types: std::marker::PhantomData }), + Arc::new(GlobalData { data, _types: std::marker::PhantomData::<(_, _, State)> }), + ) + } + + /// Create a new protocol global + /// + /// This global will be advertized to clients through the `wl_registry` according to the rules + /// defined by your [`GlobalDispatch`] implementation for the given interface. Whenever a client + /// binds this global, the associated [`GlobalDispatch::bind()`] method will be invoked on your + /// `State`. + pub fn create_delegated_global( + &self, + version: u32, + data: U, + ) -> GlobalId + where + State: 'static, + I: Resource + 'static, + U: Send + Sync + 'static, + DelegateTo: GlobalDispatch + 'static, + { + self.handle.create_global::( + I::interface(), + version, + Arc::new(GlobalData { + data, + _types: std::marker::PhantomData::<(I, State, DelegateTo)>, + }), ) } diff --git a/wayland-server/src/global.rs b/wayland-server/src/global.rs index 42835c0b4b7..107bf4c8782 100644 --- a/wayland-server/src/global.rs +++ b/wayland-server/src/global.rs @@ -7,20 +7,24 @@ use wayland_backend::server::{ use crate::{Client, DataInit, DisplayHandle, New, Resource}; -pub(crate) struct GlobalData { +pub(crate) struct GlobalData { pub(crate) data: U, - pub(crate) _types: std::marker::PhantomData<(I, D)>, + pub(crate) _types: std::marker::PhantomData<(I, D, DelegatedTo)>, } -unsafe impl Send for GlobalData {} -unsafe impl Sync for GlobalData {} +unsafe impl Send for GlobalData {} +unsafe impl Sync for GlobalData {} -impl + 'static> - GlobalHandler for GlobalData +impl GlobalHandler for GlobalData +where + I: Resource + 'static, + U: Send + Sync + 'static, + D: 'static, + DelegatedTo: GlobalDispatch + 'static, { fn can_view(&self, id: ClientId, data: &Arc, _: GlobalId) -> bool { let client = Client { id, data: data.clone() }; - >::can_view(client, &self.data) + >::can_view(client, &self.data) } fn bind( @@ -39,7 +43,7 @@ impl + let mut new_data = None; let mut protocol_error = None; - >::bind( + >::bind( data, &handle, &client, diff --git a/wayland-server/src/lib.rs b/wayland-server/src/lib.rs index 7526f430a46..e9f74f3881e 100644 --- a/wayland-server/src/lib.rs +++ b/wayland-server/src/lib.rs @@ -92,7 +92,7 @@ mod global; mod socket; pub use client::Client; -pub use dispatch::{DataInit, Dispatch, New, ResourceData}; +pub use dispatch::{DataInit, DelegatedResourceData, Dispatch, New, ResourceData}; pub use display::{Display, DisplayHandle}; pub use global::GlobalDispatch; pub use socket::{BindError, ListeningSocket}; @@ -171,6 +171,9 @@ pub trait Resource: Clone + std::fmt::Debug + Sized { /// Access the user-data associated with this object fn data(&self) -> Option<&U>; + /// Access the user-data associated with this object + fn delegated_data(&self) -> Option<&U>; + /// Access the raw data associated with this object. /// /// It is given to you as a `dyn Any`, and you are responsible for downcasting it.