1
0
Fork 0
forked from wry/wry
wry/src/ifs/head_management/head_management_macros.rs

406 lines
14 KiB
Rust

use {
crate::{
client::ClientError,
ifs::head_management::{
Head, HeadState,
jay_head_manager_session_v1::{JayHeadManagerSessionV1, JayHeadManagerSessionV1Error},
jay_head_manager_v1::JayHeadManagerV1,
jay_head_v1::JayHeadV1,
},
object::{ObjectId, Version},
state::ConnectorData,
utils::clonecell::CloneCell,
},
std::rc::Rc,
};
macro_rules! error_ {
($error_name:ident, $($tt:tt)*) => {
#[derive(Debug, thiserror::Error)]
pub enum $error_name {
#[error(transparent)]
ClientError(Box<crate::client::ClientError>),
#[error(transparent)]
Common(#[from] super::super::HeadCommonError),
$($tt)*
}
efrom!($error_name, ClientError, crate::client::ClientError);
};
}
macro_rules! impl_head_ext {
(
$snake:ident,
$camel:ident,
$macro_name:ident,
$mgr_module:ident,
$mgr_name:ident,
$mgr_id_name:ident,
$head_module:ident,
$head_name:ident,
$head_id_name:ident,
$version:expr,
$(filter = $filter:ident,)?
$(after_announce = $after_announce:ident,)?
$(after_transaction = $after_transaction:ident,)?
) => {
pub(in super::super) struct $mgr_name {
pub(in super::super) id: crate::wire::$mgr_id_name,
pub(in super::super) client: std::rc::Rc<crate::client::Client>,
pub(in super::super) tracker: crate::leaks::Tracker<Self>,
pub(in super::super) version: crate::object::Version,
pub(in super::super) common: std::rc::Rc<super::super::HeadMgrCommon>,
}
impl $mgr_name {
pub(in super::super) const VERSION: crate::object::Version = crate::object::Version($version);
pub(in super::super) const NAME: &str = concat!("jay_head_manager_ext_", stringify!($snake));
}
object_base! {
self = $mgr_name;
version = self.version;
}
impl crate::object::Object for $mgr_name {}
simple_add_obj!($mgr_name);
pub(in super::super) struct $head_name {
pub(in super::super) id: crate::wire::$head_id_name,
pub(in super::super) client: std::rc::Rc<crate::client::Client>,
pub(in super::super) tracker: crate::leaks::Tracker<Self>,
pub(in super::super) version: crate::object::Version,
pub(in super::super) common: std::rc::Rc<super::super::HeadCommon>,
}
object_base! {
self = $head_name;
version = self.version;
}
impl crate::object::Object for $head_name {}
simple_add_obj!($head_name);
impl $mgr_name {
pub(in super::super) fn announce(
&self,
#[allow(clippy::allow_attributes, unused_variables)]
connector: &crate::state::ConnectorData,
common: &std::rc::Rc<super::super::HeadCommon>,
) -> Result<Option<std::rc::Rc<$head_name>>, crate::client::ClientError> {
$(
if !self.$filter(connector, common) {
return Ok(None);
}
)?
let obj = std::rc::Rc::new($head_name {
id: self.client.new_id()?,
client: self.client.clone(),
tracker: Default::default(),
version: self.version,
common: common.clone(),
});
track!(self.client, obj);
self.client.add_server_obj(&obj);
self.send_head(&obj);
Ok(Some(obj))
}
fn send_head(&self, obj: &$head_name) {
self.client.event(crate::wire::$mgr_module::Head {
self_id: self.id,
head: obj.id,
});
}
}
impl $head_name {
pub(in super::super) fn after_announce_wrapper(
&self,
#[allow(clippy::allow_attributes, unused_variables)]
shared: &super::super::HeadState,
) {
$(
self.$after_announce(shared);
)?
}
pub(in super::super) fn after_transaction_wrapper(
&self,
#[allow(clippy::allow_attributes, unused_variables)]
shared: &super::super::HeadState,
#[allow(clippy::allow_attributes, unused_variables)]
tran: &super::super::HeadState,
) {
$(
self.$after_transaction(shared, tran);
)?
}
}
}
}
#[rustfmt::skip]
macro_rules! declare_extension_type_macro {
(
($dollar:tt),
$snake:ident,
$camel:ident,
$macro_name:ident,
$macro_name_int:ident,
$mgr_module:ident,
$mgr_name:ident,
$mgr_id_name:ident,
$mgr_request_handler:ident,
$head_module:ident,
$head_name:ident,
$head_id_name:ident,
$head_request_handler:ident,
$error_name:ident,
) => {
macro_rules! $macro_name {
(
version = $version:expr,
$dollar(filter = $filter:ident,)?
$dollar(after_announce = $after_announce:ident,)?
$dollar(after_transaction = $after_transaction:ident,)?
) => {
$macro_name_int! {
($),
version = $version,
$dollar(filter = $filter,)?
$dollar(after_announce = $after_announce,)?
$dollar(after_transaction = $after_transaction,)?
}
}
}
macro_rules! $macro_name_int {
(
($dollar2:tt),
version = $version:expr,
$dollar(filter = $filter:ident,)?
$dollar(after_announce = $after_announce:ident,)?
$dollar(after_transaction = $after_transaction:ident,)?
) => {
impl_head_ext!(
$snake,
$camel,
$macro_name,
$mgr_module,
$mgr_name,
$mgr_id_name,
$head_module,
$head_name,
$head_id_name,
$version,
$dollar(filter = $filter,)?
$dollar(after_announce = $after_announce,)?
$dollar(after_transaction = $after_transaction,)?
);
macro_rules! head_common_req {
() => {
head_common_req_!($snake);
}
}
macro_rules! mgr_common_req {
() => {
mgr_common_req_!($snake);
}
}
type ErrorName = $error_name;
type MgrName = $mgr_name;
type HeadName = $head_name;
macro_rules! error {
($dollar2($tt:tt)*) => {
error_!($error_name, $dollar2($tt)*);
}
}
}
}
};
}
macro_rules! mgr_common_req_ {
($snake:ident) => {
with_builtin_macros::with_eager_expansions! {
fn destroy(
&self,
_req: crate::wire::#{concat_idents!(jay_head_manager_ext_, $snake)}::Destroy,
_slf: &Rc<Self>,
) -> Result<(), Self::Error> {
self.common.assert_stopped()?;
self.client.remove_obj(self)?;
Ok(())
}
}
};
}
macro_rules! head_common_req_ {
($snake:ident) => {
with_builtin_macros::with_eager_expansions! {
fn destroy(
&self,
_req: crate::wire::#{concat_idents!(jay_head_ext_, $snake)}::Destroy,
_slf: &Rc<Self>,
) -> Result<(), Self::Error> {
self.common.assert_removed()?;
self.client.remove_obj(self)?;
Ok(())
}
}
};
}
macro_rules! declare_extensions {
($($snake:ident: $camel:ident,)*) => {
#[derive(linearize::Linearize)]
pub(super) enum HeadExtension {
$($camel,)*
}
pub(super) fn send_available_extensions(mgr: &JayHeadManagerV1) {
use linearize::Linearize;
with_builtin_macros::with_eager_expansions! {
$(
type $camel = super::jay_head_ext::#{concat_idents!(jay_head_ext_, $snake)}::#{concat_idents!(JayHeadManagerExt, $camel)};
mgr.send_extension(
HeadExtension::$camel.linearize() as _,
$camel::NAME,
$camel::VERSION,
);
)*
}
}
pub(super) fn announce_head(
session: &Rc<JayHeadManagerSessionV1>,
head: &Rc<JayHeadV1>,
connector: &ConnectorData,
) -> Result<Rc<Head>, ClientError> {
session.send_head_start(head, connector.head_managers.name);
let head = super::Head {
session: session.clone(),
common: head.common.clone(),
head: head.clone(),
ext: HeadExts {
$(
$snake: match session.ext.$snake.get() {
Some(f) => f.announce(connector, &head.common)?,
_ => None,
},
)*
},
};
session.send_head_complete();
let shared = &*connector.head_managers.state.borrow();
$(
if let Some(ext) = &head.ext.$snake {
ext.after_announce_wrapper(shared);
}
)*
Ok(Rc::new(head))
}
pub(super) fn bind_extension(session: &JayHeadManagerSessionV1, ext: HeadExtension, name: u32, version: u32, id: ObjectId) -> Result<(), JayHeadManagerSessionV1Error> {
match ext {
$(
HeadExtension::$camel => {
if session.ext.$snake.is_some() {
return Err(JayHeadManagerSessionV1Error::AlreadyBound(name));
}
let version = Version(version);
with_builtin_macros::with_eager_expansions! {
type T = super::jay_head_ext::#{concat_idents!(jay_head_ext_, $snake)}::#{concat_idents!(JayHeadManagerExt, $camel)};
if version > T::VERSION {
return Err(JayHeadManagerSessionV1Error::UnsupportedVersion(name, version));
}
let obj = Rc::new(T {
id: id.into(),
client: session.client.clone(),
tracker: Default::default(),
version,
common: session.common.clone(),
});
}
track!(session.client, obj);
session.client.add_client_obj(&obj)?;
session.ext.$snake.set(Some(obj));
}
)*
}
Ok(())
}
with_builtin_macros::with_eager_expansions! {
#[derive(Default)]
pub(super) struct MgrExts {
$(
pub(super) $snake: CloneCell<Option<Rc<super::jay_head_ext::#{concat_idents!(jay_head_ext_, $snake)}::#{concat_idents!(JayHeadManagerExt, $camel)}>>>,
)*
}
pub(super) struct HeadExts {
$(
pub(super) $snake: Option<Rc<super::jay_head_ext::#{concat_idents!(jay_head_ext_, $snake)}::#{concat_idents!(JayHeadExt, $camel)}>>,
)*
}
}
impl HeadExts {
pub(super) fn after_transaction(&self, shared: &HeadState, tran: &HeadState) {
$(
if let Some(ext) = &self.$snake {
ext.after_transaction_wrapper(shared, tran);
}
)*
}
}
with_builtin_macros::with_eager_expansions! {
$(
declare_extension_type_macro!(
($),
$snake,
$camel,
#{concat_idents!(impl_, $snake)},
#{concat_idents!(impl_, $snake, _int)},
#{concat_idents!(jay_head_manager_ext_, $snake)},
#{concat_idents!(JayHeadManagerExt, $camel)},
#{concat_idents!(JayHeadManagerExt, $camel, Id)},
#{concat_idents!(JayHeadManagerExt, $camel, RequestHandler)},
#{concat_idents!(jay_head_ext_, $snake)},
#{concat_idents!(JayHeadExt, $camel)},
#{concat_idents!(JayHeadExt, $camel, Id)},
#{concat_idents!(JayHeadExt, $camel, RequestHandler)},
#{concat_idents!(JayHeadExt, $camel, Error)},
);
)*
}
};
}
declare_extensions! {
core_info_v1: CoreInfoV1,
compositor_space_info_v1: CompositorSpaceInfoV1,
compositor_space_positioner_v1: CompositorSpacePositionerV1,
compositor_space_transformer_v1: CompositorSpaceTransformerV1,
compositor_space_scaler_v1: CompositorSpaceScalerV1,
compositor_space_enabler_v1: CompositorSpaceEnablerV1,
connector_info_v1: ConnectorInfoV1,
mode_info_v1: ModeInfoV1,
mode_setter_v1: ModeSetterV1,
physical_display_info_v1: PhysicalDisplayInfoV1,
non_desktop_info_v1: NonDesktopInfoV1,
vrr_state_v1: VrrStateV1,
tearing_state_v1: TearingStateV1,
format_info_v1: FormatInfoV1,
drm_color_space_info_v1: DrmColorSpaceInfoV1,
}