1
0
Fork 0
forked from wry/wry

config: add client-rule infrastructure

This commit is contained in:
Julian Orth 2025-05-04 18:02:17 +02:00
parent 17e715cde4
commit fd2163d658
32 changed files with 1804 additions and 27 deletions

203
src/criteria/clm.rs Normal file
View file

@ -0,0 +1,203 @@
pub mod clm_matchers;
use {
crate::{
client::{Client, ClientId},
criteria::{
CritDestroyListener, CritMatcherId, CritMatcherIds, CritUpstreamNode, FixedRootMatcher,
RootMatcherMap,
crit_graph::{CritMgr, CritTarget, CritTargetOwner, WeakCritTargetOwner},
crit_leaf::{CritLeafEvent, CritLeafMatcher},
crit_matchers::critm_constant::CritMatchConstant,
},
state::State,
utils::{copyhashmap::CopyHashMap, hash_map_ext::HashMapExt, queue::AsyncQueue},
},
std::rc::{Rc, Weak},
};
bitflags! {
ClMatcherChange: u32;
CL_CHANGED_DESTROYED = 1 << 0,
CL_CHANGED_NEW = 1 << 1,
}
type ClmFixedRootMatcher<T> = FixedRootMatcher<Rc<Client>, T>;
pub struct ClMatcherManager {
ids: Rc<CritMatcherIds>,
changes: AsyncQueue<Rc<Client>>,
leaf_events: Rc<AsyncQueue<CritLeafEvent<Rc<Client>>>>,
constant: ClmFixedRootMatcher<CritMatchConstant<Rc<Client>>>,
matchers: Rc<RootMatchers>,
}
#[expect(dead_code)]
type ClmRootMatcherMap<T> = RootMatcherMap<Rc<Client>, T>;
#[derive(Default)]
pub struct RootMatchers {}
pub async fn handle_cl_changes(state: Rc<State>) {
let mgr = &state.cl_matcher_manager;
loop {
let tl = mgr.changes.pop().await;
mgr.update_matches(&tl);
}
}
pub async fn handle_cl_leaf_events(state: Rc<State>) {
let mgr = &state.cl_matcher_manager;
let debouncer = state.ring.debouncer(1000);
loop {
let event = mgr.leaf_events.pop().await;
event.run();
debouncer.debounce().await;
}
}
#[expect(dead_code)]
pub type ClmUpstreamNode = dyn CritUpstreamNode<Rc<Client>>;
pub type ClmLeafMatcher = CritLeafMatcher<Rc<Client>>;
impl ClMatcherManager {
pub fn new(ids: &Rc<CritMatcherIds>) -> Self {
let matchers = Rc::new(RootMatchers::default());
#[expect(unused_macros)]
macro_rules! bool {
($name:ident) => {{
static_map! {
v => CritRoot::new(
&matchers,
ids.next(),
CritRootFixed($name(v), PhantomData),
)
}
}};
}
Self {
constant: CritMatchConstant::create(&matchers, ids),
changes: Default::default(),
leaf_events: Default::default(),
ids: ids.clone(),
matchers,
}
}
pub fn clear(&self) {
self.changes.clear();
self.leaf_events.clear();
}
pub fn rematch_all(&self, state: &Rc<State>) {
for client in state.clients.clients.borrow().values() {
client.data.property_changed(CL_CHANGED_NEW);
}
}
pub fn changed(&self, client: &Rc<Client>) {
self.changes.push(client.clone());
}
fn update_matches(&self, data: &Rc<Client>) {
let mut changed = data.changed_properties.take();
if changed.contains(CL_CHANGED_DESTROYED) {
for destroyed in data.destroyed.lock().drain_values() {
if let Some(destroyed) = destroyed.upgrade() {
destroyed.destroyed(data.id);
}
}
return;
}
#[expect(unused_macros)]
macro_rules! handlers {
($name:ident) => {
self.matchers
.$name
.lock()
.values()
.filter_map(|m| m.upgrade())
};
}
#[expect(unused_macros)]
macro_rules! fixed {
($name:ident) => {
self.$name[false].handle(data);
self.$name[true].handle(data);
};
}
if changed.contains(CL_CHANGED_NEW) {
changed |= ClMatcherChange::all();
#[expect(unused_macros)]
macro_rules! unconditional {
($field:ident) => {
for m in handlers!($field) {
m.handle(data);
}
};
}
self.constant[true].handle(data);
}
}
}
impl CritTarget for Rc<Client> {
type Id = ClientId;
type Mgr = ClMatcherManager;
type RootMatchers = RootMatchers;
type LeafData = ClientId;
type Owner = Weak<Client>;
fn owner(&self) -> Self::Owner {
Rc::downgrade(self)
}
fn id(&self) -> Self::Id {
self.id
}
fn destroyed(&self) -> &CopyHashMap<CritMatcherId, Weak<dyn CritDestroyListener<Self>>> {
&self.destroyed
}
fn leaf_data(&self) -> Self::LeafData {
self.id
}
}
impl CritTargetOwner for Rc<Client> {
type Target = Rc<Client>;
fn data(&self) -> &Self::Target {
self
}
}
impl WeakCritTargetOwner for Weak<Client> {
type Target = Rc<Client>;
type Owner = Rc<Client>;
fn upgrade(&self) -> Option<Self::Owner> {
self.upgrade()
}
}
impl CritMgr for ClMatcherManager {
type Target = Rc<Client>;
fn id(&self) -> CritMatcherId {
self.ids.next()
}
fn leaf_events(&self) -> &Rc<AsyncQueue<CritLeafEvent<Self::Target>>> {
&self.leaf_events
}
fn match_constant(&self) -> &FixedRootMatcher<Self::Target, CritMatchConstant<Self::Target>> {
&self.constant
}
fn roots(&self) -> &Rc<<Self::Target as CritTarget>::RootMatchers> {
&self.matchers
}
}

View file

@ -0,0 +1,19 @@
#[expect(unused_macros)]
macro_rules! fixed_root_criterion {
($ty:ty, $field:ident) => {
impl crate::criteria::crit_graph::CritFixedRootCriterionBase<Rc<crate::client::Client>>
for $ty
{
fn constant(&self) -> bool {
self.0
}
fn not<'a>(
&self,
mgr: &'a crate::criteria::clm::ClMatcherManager,
) -> &'a crate::criteria::FixedRootMatcher<Rc<crate::client::Client>, Self> {
&mgr.$field
}
}
};
}

View file

@ -129,7 +129,6 @@ where
slf
}
#[expect(dead_code)]
pub fn handle(&self, target: &Target) {
let new = self.criterion.matches(target) ^ self.not;
let node = match new {

View file

@ -104,7 +104,6 @@ impl<Target> CritLeafEvent<Target>
where
Target: CritTarget,
{
#[expect(dead_code)]
pub fn run(self) {
let n = self.node;
n.needs_event.set(true);

View file

@ -16,7 +16,6 @@ impl<Target> CritMatchConstant<Target>
where
Target: CritTarget,
{
#[expect(dead_code)]
pub fn create(
roots: &Rc<Target::RootMatchers>,
ids: &CritMatcherIds,

View file

@ -41,7 +41,6 @@ pub trait CritDestroyListener<Target>: 'static
where
Target: CritTarget,
{
#[expect(dead_code)]
fn destroyed(&self, target_id: Target::Id);
}