Skip to content

Commit

Permalink
Begone delegate macros init
Browse files Browse the repository at this point in the history
  • Loading branch information
PolyMeilex committed Feb 11, 2024
1 parent eb7a57b commit 2d534c1
Show file tree
Hide file tree
Showing 5 changed files with 216 additions and 67 deletions.
7 changes: 6 additions & 1 deletion wayland-scanner/src/server_gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -132,6 +132,11 @@ fn generate_objects_for(interface: &Interface) -> TokenStream {
self.data.as_ref().and_then(|arc| (&**arc).downcast_ref::<ResourceData<Self, U>>()).map(|data| &data.udata)
}

#[inline]
fn delegated_data<U: 'static, M: 'static>(&self) -> Option<&U> {
self.data.as_ref().and_then(|arc| (&**arc).downcast_ref::<DelegatedResourceData<Self, U, M>>()).map(|data| &data.udata)
}

#[inline]
fn object_data(&self) -> Option<&Arc<dyn std::any::Any + Send + Sync>> {
self.data.as_ref()
Expand Down
222 changes: 166 additions & 56 deletions wayland-server/src/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,20 @@ impl<'a, D> DataInit<'a, D> {
where
D: Dispatch<I, U> + 'static,
{
let arc = Arc::new(ResourceData::<I, _>::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::<I, _>::new(data)))
}

/// Initialize an object by assigning it its user-data
pub fn init_delegated<I: Resource + 'static, U: Send + Sync + 'static, M>(
&mut self,
resource: New<I>,
data: U,
) -> I
where
D: 'static,
M: Dispatch<I, U, D> + 'static,
{
self.custom_init(resource, Arc::new(DelegatedResourceData::<I, _, M>::new(data)))
}

/// Set a custom [`ObjectData`] for this object
Expand Down Expand Up @@ -227,52 +236,69 @@ impl<I: Resource + 'static, U: Send + Sync + 'static, D: Dispatch<I, U> + 'stati
client_id: wayland_backend::server::ClientId,
msg: wayland_backend::protocol::Message<wayland_backend::server::ObjectId, OwnedFd>,
) -> Option<Arc<dyn ObjectData<D>>> {
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::<U>().expect("Wrong user_data value for object");

let mut new_data = None;
on_request::<I, U, D, D>(handle, data, client_id, msg, |resource| {
resource.data().expect("Wrong user_data value for object")
})
}

<D as Dispatch<I, U>>::request(
fn destroyed(
self: Arc<Self>,
handle: &wayland_backend::server::Handle,
data: &mut D,
client_id: ClientId,
object_id: ObjectId,
) {
on_destroyed::<Self, I, U, D, D>(
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<I, U, M> {
/// The user-data associated with this object
pub udata: U,
marker: std::marker::PhantomData<(I, M)>,
}

impl<I, U, M> DelegatedResourceData<I, U, M> {
pub(crate) fn new<D>(udata: U) -> Self
where
D: 'static,
I: Resource + 'static,
M: Dispatch<I, U, D> + 'static,
U: Send + Sync + 'static,
{
DelegatedResourceData { udata, marker: std::marker::PhantomData::<(I, M)> }
}
}

unsafe impl<I, U: Send, M> Send for DelegatedResourceData<I, U, M> {}
unsafe impl<I, U: Sync, M> Sync for DelegatedResourceData<I, U, M> {}

impl<M, I, U, D> ObjectData<D> for DelegatedResourceData<I, U, M>
where
I: Resource + 'static,
U: Send + Sync + 'static,
D: 'static,
M: Dispatch<I, U, D> + 'static,
{
fn request(
self: Arc<Self>,
handle: &wayland_backend::server::Handle,
data: &mut D,
client_id: wayland_backend::server::ClientId,
msg: wayland_backend::protocol::Message<wayland_backend::server::ObjectId, OwnedFd>,
) -> Option<Arc<dyn ObjectData<D>>> {
on_request::<I, U, D, M>(handle, data, client_id, msg, |resource| {
resource.delegated_data::<U, M>().expect("Wrong user_data value for object")
})
}

fn destroyed(
Expand All @@ -282,15 +308,99 @@ impl<I: Resource + 'static, U: Send + Sync + 'static, D: Dispatch<I, U> + '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, I, U, D, M>(
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<I, U, D, M>(
handle: &wayland_backend::server::Handle,
data: &mut D,
client_id: wayland_backend::server::ClientId,
msg: wayland_backend::protocol::Message<wayland_backend::server::ObjectId, OwnedFd>,
get_data: impl FnOnce(&I) -> &U,
) -> Option<Arc<dyn ObjectData<D>>>
where
I: Resource,
U: Send + Sync + 'static,
M: Dispatch<I, U, D>,
D: 'static,
{
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;
}
};

<D as Dispatch<I, U>>::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;

<M as Dispatch<I, U, D>>::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<DATA, I, U, D, M>(
this: Arc<DATA>,
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,
M: Dispatch<I, U, D>,
{
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);

<M as Dispatch<I, U, D>>::destroyed(data, client_id, &resource, udata)
}

/// A helper macro which delegates a set of [`Dispatch`] implementations for a resource to some other type which
Expand Down
29 changes: 28 additions & 1 deletion wayland-server/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,34 @@ impl DisplayHandle {
self.handle.create_global::<State>(
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<State, I, U, DelegateTo>(
&self,
version: u32,
data: U,
) -> GlobalId
where
State: 'static,
I: Resource + 'static,
U: Send + Sync + 'static,
DelegateTo: GlobalDispatch<I, U, State> + 'static,
{
self.handle.create_global::<State>(
I::interface(),
version,
Arc::new(GlobalData {
data,
_types: std::marker::PhantomData::<(I, State, DelegateTo)>,
}),
)
}

Expand Down
20 changes: 12 additions & 8 deletions wayland-server/src/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,24 @@ use wayland_backend::server::{

use crate::{Client, DataInit, DisplayHandle, New, Resource};

pub(crate) struct GlobalData<I, U, D> {
pub(crate) struct GlobalData<I, U, D, M = D> {
pub(crate) data: U,
pub(crate) _types: std::marker::PhantomData<(I, D)>,
pub(crate) _types: std::marker::PhantomData<(I, D, M)>,
}

unsafe impl<I, D, U: Send + Sync> Send for GlobalData<I, U, D> {}
unsafe impl<I, D, U: Send + Sync> Sync for GlobalData<I, U, D> {}
unsafe impl<I, D, U: Send + Sync, M> Send for GlobalData<I, U, D, M> {}
unsafe impl<I, D, U: Send + Sync, M> Sync for GlobalData<I, U, D, M> {}

impl<I: Resource + 'static, U: Send + Sync + 'static, D: GlobalDispatch<I, U> + 'static>
GlobalHandler<D> for GlobalData<I, U, D>
impl<I, U, D, M> GlobalHandler<D> for GlobalData<I, U, D, M>
where
I: Resource + 'static,
U: Send + Sync + 'static,
M: GlobalDispatch<I, U, D> + 'static,
D: 'static,
{
fn can_view(&self, id: ClientId, data: &Arc<dyn ClientData>, _: GlobalId) -> bool {
let client = Client { id, data: data.clone() };
<D as GlobalDispatch<I, U>>::can_view(client, &self.data)
<M as GlobalDispatch<I, U, D>>::can_view(client, &self.data)
}

fn bind(
Expand All @@ -39,7 +43,7 @@ impl<I: Resource + 'static, U: Send + Sync + 'static, D: GlobalDispatch<I, U> +
let mut new_data = None;
let mut protocol_error = None;

<D as GlobalDispatch<I, U>>::bind(
<M as GlobalDispatch<I, U, D>>::bind(
data,
&handle,
&client,
Expand Down
5 changes: 4 additions & 1 deletion wayland-server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -171,6 +171,9 @@ pub trait Resource: Clone + std::fmt::Debug + Sized {
/// Access the user-data associated with this object
fn data<U: 'static>(&self) -> Option<&U>;

/// Access the user-data associated with this object
fn delegated_data<U: 'static, DelegatedTo: 'static>(&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.
Expand Down

0 comments on commit 2d534c1

Please sign in to comment.