criteria: add infrastructure
This commit is contained in:
parent
597636fba6
commit
17e715cde4
18 changed files with 1214 additions and 3 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -602,6 +602,7 @@ dependencies = [
|
|||
"pin-project",
|
||||
"png",
|
||||
"rand",
|
||||
"regex",
|
||||
"repc",
|
||||
"rustc-demangle",
|
||||
"serde",
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ rustc-demangle = { version = "0.1.24", optional = true }
|
|||
tracy-client-sys = { version = "0.24.1", features = ["ondemand", "manual-lifetime", "debuginfod", "demangle"], optional = true }
|
||||
kbvm = "0.1.4"
|
||||
tiny-skia = { version = "0.11.4", default-features = false, features = ["std"] }
|
||||
regex = "1.11.1"
|
||||
|
||||
[build-dependencies]
|
||||
repc = "0.1.1"
|
||||
|
|
|
|||
96
src/criteria.rs
Normal file
96
src/criteria.rs
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
mod crit_graph;
|
||||
pub mod crit_leaf;
|
||||
mod crit_matchers;
|
||||
mod crit_per_target_data;
|
||||
|
||||
use {
|
||||
crate::{
|
||||
criteria::{
|
||||
crit_graph::{CritMgr, CritMiddle, CritRoot, CritRootCriterion, CritRootFixed},
|
||||
crit_leaf::CritLeafMatcher,
|
||||
crit_matchers::{critm_any_or_all::CritMatchAnyOrAll, critm_exactly::CritMatchExactly},
|
||||
},
|
||||
utils::copyhashmap::CopyHashMap,
|
||||
},
|
||||
linearize::StaticMap,
|
||||
regex::Regex,
|
||||
std::rc::{Rc, Weak},
|
||||
};
|
||||
pub use {
|
||||
crit_graph::{CritTarget, CritUpstreamNode},
|
||||
crit_per_target_data::CritDestroyListener,
|
||||
};
|
||||
|
||||
linear_ids!(CritMatcherIds, CritMatcherId, u64);
|
||||
|
||||
type RootMatcherMap<Target, T> = CopyHashMap<CritMatcherId, Weak<CritRoot<Target, T>>>;
|
||||
type FixedRootMatcher<Target, T> = StaticMap<bool, Rc<CritRoot<Target, CritRootFixed<Target, T>>>>;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[expect(dead_code)]
|
||||
pub enum CritLiteralOrRegex {
|
||||
Literal(String),
|
||||
Regex(Regex),
|
||||
}
|
||||
|
||||
impl CritLiteralOrRegex {
|
||||
fn matches(&self, string: &str) -> bool {
|
||||
match self {
|
||||
CritLiteralOrRegex::Literal(p) => string == p,
|
||||
CritLiteralOrRegex::Regex(r) => r.is_match(string),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub trait CritMgrExt: CritMgr {
|
||||
fn list(
|
||||
&self,
|
||||
upstream: &[Rc<dyn CritUpstreamNode<Self::Target>>],
|
||||
all: bool,
|
||||
) -> Rc<dyn CritUpstreamNode<Self::Target>> {
|
||||
if upstream.is_empty() {
|
||||
return self.match_constant()[all].clone();
|
||||
}
|
||||
CritMiddle::new(self, upstream, CritMatchAnyOrAll::new(upstream, all))
|
||||
}
|
||||
|
||||
fn exactly(
|
||||
&self,
|
||||
upstream: &[Rc<dyn CritUpstreamNode<Self::Target>>],
|
||||
num: usize,
|
||||
) -> Rc<dyn CritUpstreamNode<Self::Target>> {
|
||||
if num > upstream.len() {
|
||||
return self.match_constant()[false].clone();
|
||||
}
|
||||
if num == 0 {
|
||||
let upstream: Vec<_> = upstream.iter().map(|u| u.not(self)).collect();
|
||||
return self.list(&upstream, true);
|
||||
}
|
||||
CritMiddle::new(self, upstream, CritMatchExactly::new(upstream, num))
|
||||
}
|
||||
|
||||
fn leaf(
|
||||
&self,
|
||||
upstream: &Rc<dyn CritUpstreamNode<Self::Target>>,
|
||||
on_match: impl Fn(<Self::Target as CritTarget>::LeafData) -> Box<dyn FnOnce()> + 'static,
|
||||
) -> Rc<CritLeafMatcher<Self::Target>> {
|
||||
CritLeafMatcher::new(self, upstream, on_match)
|
||||
}
|
||||
|
||||
fn not(
|
||||
&self,
|
||||
upstream: &Rc<dyn CritUpstreamNode<Self::Target>>,
|
||||
) -> Rc<dyn CritUpstreamNode<Self::Target>> {
|
||||
upstream.not(self)
|
||||
}
|
||||
|
||||
fn root<T>(&self, criterion: T) -> Rc<dyn CritUpstreamNode<Self::Target>>
|
||||
where
|
||||
T: CritRootCriterion<Self::Target>,
|
||||
{
|
||||
CritRoot::new(self.roots(), self.id(), criterion)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> CritMgrExt for T where T: CritMgr {}
|
||||
16
src/criteria/crit_graph.rs
Normal file
16
src/criteria/crit_graph.rs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
mod crit_downstream;
|
||||
mod crit_middle;
|
||||
mod crit_root;
|
||||
mod crit_target;
|
||||
mod crit_upstream;
|
||||
|
||||
pub use {
|
||||
crit_downstream::{CritDownstream, CritDownstreamData},
|
||||
crit_middle::{CritMiddle, CritMiddleCriterion},
|
||||
crit_root::{
|
||||
CritFixedRootCriterion, CritFixedRootCriterionBase, CritRoot, CritRootCriterion,
|
||||
CritRootFixed,
|
||||
},
|
||||
crit_target::{CritMgr, CritTarget, CritTargetOwner, WeakCritTargetOwner},
|
||||
crit_upstream::{CritUpstreamData, CritUpstreamNode},
|
||||
};
|
||||
52
src/criteria/crit_graph/crit_downstream.rs
Normal file
52
src/criteria/crit_graph/crit_downstream.rs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
use {
|
||||
crate::criteria::{
|
||||
CritMatcherId,
|
||||
crit_graph::{CritTarget, crit_upstream::CritUpstreamNode},
|
||||
},
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
pub struct CritDownstreamData<Target>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
id: CritMatcherId,
|
||||
pub(super) upstream: Vec<Rc<dyn CritUpstreamNode<Target>>>,
|
||||
}
|
||||
|
||||
pub trait CritDownstream<Target>: 'static {
|
||||
fn update_matched(self: Rc<Self>, target: &Target, matched: bool);
|
||||
}
|
||||
|
||||
impl<Target> CritDownstreamData<Target>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
pub fn new(id: CritMatcherId, upstream: &[Rc<dyn CritUpstreamNode<Target>>]) -> Self {
|
||||
Self {
|
||||
id,
|
||||
upstream: upstream.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn attach(&self, slf: &Rc<impl CritDownstream<Target>>) {
|
||||
for upstream in &self.upstream {
|
||||
upstream.attach(self.id, slf.clone() as _);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn not(&self, mgr: &Target::Mgr) -> Vec<Rc<dyn CritUpstreamNode<Target>>> {
|
||||
self.upstream.iter().map(|n| n.not(mgr)).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Target> Drop for CritDownstreamData<Target>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
for el in &self.upstream {
|
||||
el.detach(self.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
111
src/criteria/crit_graph/crit_middle.rs
Normal file
111
src/criteria/crit_graph/crit_middle.rs
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
use {
|
||||
crate::criteria::{
|
||||
CritUpstreamNode,
|
||||
crit_graph::{
|
||||
CritDownstream, CritDownstreamData, CritTarget, CritUpstreamData,
|
||||
crit_target::CritMgr,
|
||||
crit_upstream::{CritUpstreamNodeBase, CritUpstreamNodeData},
|
||||
},
|
||||
crit_per_target_data::{CritDestroyListenerBase, CritPerTargetData},
|
||||
},
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
pub struct CritMiddle<Target, T>
|
||||
where
|
||||
Target: CritTarget,
|
||||
T: CritMiddleCriterion<Target>,
|
||||
{
|
||||
upstream: CritDownstreamData<Target>,
|
||||
downstream: CritUpstreamData<Target, CritMiddleData<T::Data>>,
|
||||
criterion: T,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct CritMiddleData<T> {
|
||||
matches: usize,
|
||||
data: T,
|
||||
}
|
||||
|
||||
pub trait CritMiddleCriterion<Target>: Sized + 'static {
|
||||
type Data: Default;
|
||||
type Not: CritMiddleCriterion<Target>;
|
||||
|
||||
fn update_matched(&self, target: &Target, node: &mut Self::Data, matched: bool) -> bool;
|
||||
fn pull(&self, upstream: &[Rc<dyn CritUpstreamNode<Target>>], target: &Target) -> bool;
|
||||
fn not(&self) -> Self::Not;
|
||||
}
|
||||
|
||||
impl<Target, T> CritMiddle<Target, T>
|
||||
where
|
||||
Target: CritTarget,
|
||||
T: CritMiddleCriterion<Target>,
|
||||
{
|
||||
pub fn new(
|
||||
mgr: &Target::Mgr,
|
||||
upstream: &[Rc<dyn CritUpstreamNode<Target>>],
|
||||
criterion: T,
|
||||
) -> Rc<Self> {
|
||||
let id = mgr.id();
|
||||
let slf = Rc::new_cyclic(|slf| Self {
|
||||
upstream: CritDownstreamData::new(id, upstream),
|
||||
downstream: CritUpstreamData::new(slf, id),
|
||||
criterion,
|
||||
});
|
||||
slf.upstream.attach(&slf);
|
||||
slf
|
||||
}
|
||||
}
|
||||
|
||||
impl<Target, T> CritDownstream<Target> for CritMiddle<Target, T>
|
||||
where
|
||||
Target: CritTarget,
|
||||
T: CritMiddleCriterion<Target>,
|
||||
{
|
||||
fn update_matched(self: Rc<Self>, target: &Target, matched: bool) {
|
||||
let mut node = self.downstream.get_or_create(target);
|
||||
let change = self
|
||||
.criterion
|
||||
.update_matched(target, &mut node.data, matched);
|
||||
let matches = match matched {
|
||||
true => node.matches + 1,
|
||||
false => node.matches - 1,
|
||||
};
|
||||
node.matches = matches;
|
||||
self.downstream
|
||||
.update_matched(target, node, change, matches == 0);
|
||||
}
|
||||
}
|
||||
|
||||
impl<Target, T> CritUpstreamNodeBase<Target> for CritMiddle<Target, T>
|
||||
where
|
||||
Target: CritTarget,
|
||||
T: CritMiddleCriterion<Target>,
|
||||
{
|
||||
type Data = CritMiddleData<T::Data>;
|
||||
|
||||
fn data(&self) -> &CritUpstreamData<Target, Self::Data> {
|
||||
&self.downstream
|
||||
}
|
||||
|
||||
fn not(&self, mgr: &Target::Mgr) -> Rc<dyn CritUpstreamNode<Target>> {
|
||||
let upstream = self.upstream.not(mgr);
|
||||
CritMiddle::new(mgr, &upstream, self.criterion.not())
|
||||
}
|
||||
|
||||
fn pull(&self, target: &Target) -> bool {
|
||||
self.criterion.pull(&self.upstream.upstream, target)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Target, T> CritDestroyListenerBase<Target> for CritMiddle<Target, T>
|
||||
where
|
||||
Target: CritTarget,
|
||||
T: CritMiddleCriterion<Target>,
|
||||
{
|
||||
type Data = CritUpstreamNodeData<Target, CritMiddleData<T::Data>>;
|
||||
|
||||
fn data(&self) -> &CritPerTargetData<Target, Self::Data> {
|
||||
&self.downstream.nodes
|
||||
}
|
||||
}
|
||||
173
src/criteria/crit_graph/crit_root.rs
Normal file
173
src/criteria/crit_graph/crit_root.rs
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
use {
|
||||
crate::criteria::{
|
||||
CritMatcherId, CritUpstreamNode, FixedRootMatcher, RootMatcherMap,
|
||||
crit_graph::{
|
||||
CritTarget, CritUpstreamData,
|
||||
crit_target::CritMgr,
|
||||
crit_upstream::{CritUpstreamNodeBase, CritUpstreamNodeData},
|
||||
},
|
||||
crit_per_target_data::{CritDestroyListenerBase, CritPerTargetData},
|
||||
},
|
||||
std::{marker::PhantomData, rc::Rc},
|
||||
};
|
||||
|
||||
pub struct CritRoot<Target, T>
|
||||
where
|
||||
Target: CritTarget,
|
||||
T: CritRootCriterion<Target>,
|
||||
{
|
||||
id: CritMatcherId,
|
||||
downstream: CritUpstreamData<Target, ()>,
|
||||
not: bool,
|
||||
criterion: Rc<T>,
|
||||
roots: Rc<Target::RootMatchers>,
|
||||
}
|
||||
|
||||
pub struct CritRootFixed<Target, Crit>(pub Crit, pub PhantomData<fn(&Target)>);
|
||||
|
||||
pub trait CritRootCriterion<Target>: Sized + 'static
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
fn matches(&self, data: &Target) -> bool;
|
||||
fn nodes(roots: &Target::RootMatchers) -> Option<&RootMatcherMap<Target, Self>> {
|
||||
let _ = roots;
|
||||
None
|
||||
}
|
||||
fn not(&self, mgr: &Target::Mgr) -> Option<Rc<dyn CritUpstreamNode<Target>>> {
|
||||
let _ = mgr;
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CritFixedRootCriterionBase<Target>: Sized + 'static
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
fn constant(&self) -> bool;
|
||||
fn not<'a>(&self, mgr: &'a Target::Mgr) -> &'a FixedRootMatcher<Target, Self>
|
||||
where
|
||||
Self: CritFixedRootCriterion<Target>;
|
||||
}
|
||||
|
||||
pub trait CritFixedRootCriterion<Target>: CritFixedRootCriterionBase<Target>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
const COMPARE: bool = true;
|
||||
|
||||
fn matches(&self, data: &Target) -> bool;
|
||||
}
|
||||
|
||||
impl<Target, T> CritRootCriterion<Target> for CritRootFixed<Target, T>
|
||||
where
|
||||
Target: CritTarget,
|
||||
T: CritFixedRootCriterion<Target>,
|
||||
{
|
||||
fn matches(&self, data: &Target) -> bool {
|
||||
let mut res = self.0.matches(data);
|
||||
if T::COMPARE {
|
||||
res = res == self.0.constant();
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
fn not(&self, mgr: &Target::Mgr) -> Option<Rc<dyn CritUpstreamNode<Target>>> {
|
||||
Some(self.0.not(mgr)[!self.0.constant()].clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Target, T> CritUpstreamNodeBase<Target> for CritRoot<Target, T>
|
||||
where
|
||||
Target: CritTarget,
|
||||
T: CritRootCriterion<Target>,
|
||||
{
|
||||
type Data = ();
|
||||
|
||||
fn data(&self) -> &CritUpstreamData<Target, Self::Data> {
|
||||
&self.downstream
|
||||
}
|
||||
|
||||
fn not(&self, mgr: &Target::Mgr) -> Rc<dyn CritUpstreamNode<Target>> {
|
||||
if let Some(node) = self.criterion.not(mgr) {
|
||||
return node;
|
||||
}
|
||||
let id = mgr.id();
|
||||
Self::new_(&self.roots, id, self.criterion.clone(), !self.not)
|
||||
}
|
||||
|
||||
fn pull(&self, target: &Target) -> bool {
|
||||
self.criterion.matches(target) ^ self.not
|
||||
}
|
||||
}
|
||||
|
||||
impl<Target, T> CritRoot<Target, T>
|
||||
where
|
||||
Target: CritTarget,
|
||||
T: CritRootCriterion<Target>,
|
||||
{
|
||||
pub fn new(roots: &Rc<Target::RootMatchers>, id: CritMatcherId, criterion: T) -> Rc<Self> {
|
||||
Self::new_(roots, id, Rc::new(criterion), false)
|
||||
}
|
||||
|
||||
fn new_(
|
||||
roots: &Rc<Target::RootMatchers>,
|
||||
id: CritMatcherId,
|
||||
criterion: Rc<T>,
|
||||
not: bool,
|
||||
) -> Rc<Self> {
|
||||
let slf = Rc::new_cyclic(|slf| Self {
|
||||
id,
|
||||
downstream: CritUpstreamData::new(slf, id),
|
||||
not,
|
||||
criterion,
|
||||
roots: roots.clone(),
|
||||
});
|
||||
if let Some(nodes) = T::nodes(roots) {
|
||||
nodes.set(id, Rc::downgrade(&slf));
|
||||
}
|
||||
slf
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub fn handle(&self, target: &Target) {
|
||||
let new = self.criterion.matches(target) ^ self.not;
|
||||
let node = match new {
|
||||
true => self.downstream.get_or_create(target),
|
||||
false => match self.downstream.get(target) {
|
||||
Some(n) => n,
|
||||
None => return,
|
||||
},
|
||||
};
|
||||
self.downstream.update_matched(target, node, new, !new);
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub fn has_downstream(&self) -> bool {
|
||||
self.downstream.has_downstream()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Target, T> CritDestroyListenerBase<Target> for CritRoot<Target, T>
|
||||
where
|
||||
Target: CritTarget,
|
||||
T: CritRootCriterion<Target>,
|
||||
{
|
||||
type Data = CritUpstreamNodeData<Target, ()>;
|
||||
|
||||
fn data(&self) -> &CritPerTargetData<Target, Self::Data> {
|
||||
&self.downstream.nodes
|
||||
}
|
||||
}
|
||||
|
||||
impl<Target, T> Drop for CritRoot<Target, T>
|
||||
where
|
||||
Target: CritTarget,
|
||||
T: CritRootCriterion<Target>,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
if let Some(nodes) = T::nodes(&self.roots) {
|
||||
nodes.remove(&self.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
48
src/criteria/crit_graph/crit_target.rs
Normal file
48
src/criteria/crit_graph/crit_target.rs
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
use {
|
||||
crate::{
|
||||
criteria::{
|
||||
CritDestroyListener, CritMatcherId, FixedRootMatcher, crit_leaf::CritLeafEvent,
|
||||
crit_matchers::critm_constant::CritMatchConstant,
|
||||
},
|
||||
utils::{copyhashmap::CopyHashMap, queue::AsyncQueue},
|
||||
},
|
||||
std::{
|
||||
hash::Hash,
|
||||
rc::{Rc, Weak},
|
||||
},
|
||||
};
|
||||
|
||||
pub trait CritMgr: 'static {
|
||||
type Target: CritTarget<Mgr = Self>;
|
||||
|
||||
fn id(&self) -> CritMatcherId;
|
||||
fn leaf_events(&self) -> &Rc<AsyncQueue<CritLeafEvent<Self::Target>>>;
|
||||
fn match_constant(&self) -> &FixedRootMatcher<Self::Target, CritMatchConstant<Self::Target>>;
|
||||
fn roots(&self) -> &Rc<<Self::Target as CritTarget>::RootMatchers>;
|
||||
}
|
||||
|
||||
pub trait CritTarget: 'static {
|
||||
type Id: Copy + Hash + Eq;
|
||||
type Mgr: CritMgr<Target = Self>;
|
||||
type RootMatchers;
|
||||
type LeafData: Copy + Eq;
|
||||
type Owner: WeakCritTargetOwner<Target = Self>;
|
||||
|
||||
fn owner(&self) -> Self::Owner;
|
||||
fn id(&self) -> Self::Id;
|
||||
fn destroyed(&self) -> &CopyHashMap<CritMatcherId, Weak<dyn CritDestroyListener<Self>>>;
|
||||
fn leaf_data(&self) -> Self::LeafData;
|
||||
}
|
||||
|
||||
pub trait CritTargetOwner: 'static {
|
||||
type Target: CritTarget;
|
||||
|
||||
fn data(&self) -> &Self::Target;
|
||||
}
|
||||
|
||||
pub trait WeakCritTargetOwner: 'static {
|
||||
type Target: CritTarget;
|
||||
type Owner: CritTargetOwner<Target = Self::Target>;
|
||||
|
||||
fn upgrade(&self) -> Option<Self::Owner>;
|
||||
}
|
||||
176
src/criteria/crit_graph/crit_upstream.rs
Normal file
176
src/criteria/crit_graph/crit_upstream.rs
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
use {
|
||||
crate::{
|
||||
criteria::{
|
||||
CritDestroyListener, CritMatcherId,
|
||||
crit_graph::{
|
||||
WeakCritTargetOwner,
|
||||
crit_downstream::CritDownstream,
|
||||
crit_target::{CritTarget, CritTargetOwner},
|
||||
},
|
||||
crit_per_target_data::CritPerTargetData,
|
||||
},
|
||||
utils::copyhashmap::CopyHashMap,
|
||||
},
|
||||
std::{
|
||||
cell::RefMut,
|
||||
mem,
|
||||
ops::{Deref, DerefMut},
|
||||
rc::{Rc, Weak},
|
||||
},
|
||||
};
|
||||
|
||||
pub struct CritUpstreamData<Target, T>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
downstream: CopyHashMap<CritMatcherId, Weak<dyn CritDownstream<Target>>>,
|
||||
pub nodes: CritPerTargetData<Target, CritUpstreamNodeData<Target, T>>,
|
||||
}
|
||||
|
||||
pub struct CritUpstreamNodeData<Target, T>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
matched: bool,
|
||||
tl: Target::Owner,
|
||||
data: T,
|
||||
}
|
||||
|
||||
pub trait CritUpstreamNodeBase<Target>: 'static
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
type Data;
|
||||
|
||||
fn data(&self) -> &CritUpstreamData<Target, Self::Data>;
|
||||
fn not(&self, mgr: &Target::Mgr) -> Rc<dyn CritUpstreamNode<Target>>;
|
||||
fn pull(&self, target: &Target) -> bool;
|
||||
}
|
||||
|
||||
pub trait CritUpstreamNode<Target>: 'static
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
fn attach(&self, id: CritMatcherId, downstream: Rc<dyn CritDownstream<Target>>);
|
||||
fn detach(&self, id: CritMatcherId);
|
||||
fn not(&self, mgr: &Target::Mgr) -> Rc<dyn CritUpstreamNode<Target>>;
|
||||
fn pull(&self, target: &Target) -> bool;
|
||||
#[expect(dead_code)]
|
||||
fn get(&self, target: &Target) -> bool;
|
||||
}
|
||||
|
||||
impl<Target, T> CritUpstreamNode<Target> for T
|
||||
where
|
||||
Target: CritTarget,
|
||||
T: CritUpstreamNodeBase<Target>,
|
||||
{
|
||||
fn attach(&self, id: CritMatcherId, downstream: Rc<dyn CritDownstream<Target>>) {
|
||||
let data = self.data();
|
||||
for n in data.nodes.borrow_mut().values_mut() {
|
||||
if !n.matched {
|
||||
continue;
|
||||
}
|
||||
let Some(target) = n.tl.upgrade() else {
|
||||
continue;
|
||||
};
|
||||
downstream.clone().update_matched(target.data(), true);
|
||||
}
|
||||
data.downstream.set(id, Rc::downgrade(&downstream));
|
||||
}
|
||||
|
||||
fn detach(&self, id: CritMatcherId) {
|
||||
self.data().downstream.remove(&id);
|
||||
}
|
||||
|
||||
fn not(&self, mgr: &Target::Mgr) -> Rc<dyn CritUpstreamNode<Target>> {
|
||||
<T as CritUpstreamNodeBase<Target>>::not(self, mgr)
|
||||
}
|
||||
|
||||
fn pull(&self, target: &Target) -> bool {
|
||||
<T as CritUpstreamNodeBase<Target>>::pull(self, target)
|
||||
}
|
||||
|
||||
fn get(&self, target: &Target) -> bool {
|
||||
<T as CritUpstreamNodeBase<Target>>::data(self).matched(target)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Target, T> Deref for CritUpstreamNodeData<Target, T>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<Target, T> DerefMut for CritUpstreamNodeData<Target, T>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<Target, T> CritUpstreamData<Target, T>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
pub fn new(slf: &Weak<impl CritDestroyListener<Target>>, id: CritMatcherId) -> Self {
|
||||
Self {
|
||||
downstream: Default::default(),
|
||||
nodes: CritPerTargetData::new(slf, id),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_matched(
|
||||
&self,
|
||||
target: &Target,
|
||||
mut node: RefMut<CritUpstreamNodeData<Target, T>>,
|
||||
matched: bool,
|
||||
remove: bool,
|
||||
) {
|
||||
let unchanged = mem::replace(&mut node.matched, matched) == matched;
|
||||
drop(node);
|
||||
if remove {
|
||||
self.nodes.remove(target.id());
|
||||
}
|
||||
if unchanged {
|
||||
return;
|
||||
}
|
||||
for el in self.downstream.lock().values() {
|
||||
if let Some(el) = el.upgrade() {
|
||||
el.update_matched(target, matched);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_or_create(&self, target: &Target) -> RefMut<CritUpstreamNodeData<Target, T>>
|
||||
where
|
||||
T: Default,
|
||||
{
|
||||
self.nodes.get_or_create(target, || CritUpstreamNodeData {
|
||||
matched: false,
|
||||
tl: target.owner(),
|
||||
data: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get(&self, target: &Target) -> Option<RefMut<CritUpstreamNodeData<Target, T>>> {
|
||||
self.nodes.get(target)
|
||||
}
|
||||
|
||||
pub fn has_downstream(&self) -> bool {
|
||||
self.downstream.is_not_empty()
|
||||
}
|
||||
|
||||
pub fn matched(&self, target: &Target) -> bool {
|
||||
let Some(node) = self.nodes.get(target) else {
|
||||
return false;
|
||||
};
|
||||
node.matched
|
||||
}
|
||||
}
|
||||
156
src/criteria/crit_leaf.rs
Normal file
156
src/criteria/crit_leaf.rs
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
use {
|
||||
crate::{
|
||||
criteria::{
|
||||
CritUpstreamNode,
|
||||
crit_graph::{CritDownstream, CritDownstreamData, CritMgr, CritTarget},
|
||||
crit_per_target_data::{CritDestroyListenerBase, CritPerTargetData},
|
||||
},
|
||||
utils::{cell_ext::CellExt, queue::AsyncQueue},
|
||||
},
|
||||
std::{
|
||||
cell::Cell,
|
||||
rc::{Rc, Weak},
|
||||
},
|
||||
};
|
||||
|
||||
pub struct CritLeafMatcher<Target>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
upstream: CritDownstreamData<Target>,
|
||||
on_match: Box<dyn Fn(Target::LeafData) -> Box<dyn FnOnce()>>,
|
||||
targets: CritPerTargetData<Target, NodeHolder<Target>>,
|
||||
events: Rc<AsyncQueue<CritLeafEvent<Target>>>,
|
||||
}
|
||||
|
||||
pub(in crate::criteria) struct NodeHolder<Target>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
node: Rc<Node<Target>>,
|
||||
}
|
||||
|
||||
struct Node<Target>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
leaf: Weak<CritLeafMatcher<Target>>,
|
||||
target_id: Target::Id,
|
||||
needs_event: Cell<bool>,
|
||||
new_data: Cell<Option<Target::LeafData>>,
|
||||
data: Cell<Option<Target::LeafData>>,
|
||||
on_unmatch: Cell<Option<Box<dyn FnOnce()>>>,
|
||||
}
|
||||
|
||||
pub struct CritLeafEvent<Target>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
node: Rc<Node<Target>>,
|
||||
}
|
||||
|
||||
impl<Target> CritDownstream<Target> for CritLeafMatcher<Target>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
fn update_matched(self: Rc<Self>, data: &Target, matched: bool) {
|
||||
let node = &self
|
||||
.targets
|
||||
.get_or_create(data, || {
|
||||
let node = Rc::new(Node {
|
||||
leaf: Rc::downgrade(&self),
|
||||
target_id: data.id(),
|
||||
needs_event: Cell::new(true),
|
||||
new_data: Cell::new(None),
|
||||
data: Cell::new(None),
|
||||
on_unmatch: Cell::new(None),
|
||||
});
|
||||
NodeHolder { node: node.clone() }
|
||||
})
|
||||
.node;
|
||||
self.push_event(node, matched.then_some(data.leaf_data()));
|
||||
}
|
||||
}
|
||||
|
||||
impl<Target> CritLeafMatcher<Target>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
pub(in crate::criteria) fn new(
|
||||
mgr: &Target::Mgr,
|
||||
upstream: &Rc<dyn CritUpstreamNode<Target>>,
|
||||
on_match: impl Fn(Target::LeafData) -> Box<dyn FnOnce()> + 'static,
|
||||
) -> Rc<Self> {
|
||||
let id = mgr.id();
|
||||
let slf = Rc::new_cyclic(|slf| Self {
|
||||
targets: CritPerTargetData::new(slf, id),
|
||||
on_match: Box::new(on_match),
|
||||
events: mgr.leaf_events().clone(),
|
||||
upstream: CritDownstreamData::new(id, &[upstream.clone()]),
|
||||
});
|
||||
slf.upstream.attach(&slf);
|
||||
slf
|
||||
}
|
||||
|
||||
fn push_event(&self, node: &Rc<Node<Target>>, new_data: Option<Target::LeafData>) {
|
||||
node.new_data.set(new_data);
|
||||
if node.needs_event.replace(false) {
|
||||
self.events.push(CritLeafEvent { node: node.clone() });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Target> CritLeafEvent<Target>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
#[expect(dead_code)]
|
||||
pub fn run(self) {
|
||||
let n = self.node;
|
||||
n.needs_event.set(true);
|
||||
if n.new_data != n.data {
|
||||
if let Some(on_unmatch) = n.on_unmatch.take() {
|
||||
if n.leaf.strong_count() == 0 {
|
||||
return;
|
||||
}
|
||||
on_unmatch();
|
||||
}
|
||||
}
|
||||
n.data.set(n.new_data.get());
|
||||
if n.data.is_some() != n.on_unmatch.is_some() {
|
||||
let Some(leaf) = n.leaf.upgrade() else {
|
||||
return;
|
||||
};
|
||||
if let Some(id) = n.data.get() {
|
||||
n.on_unmatch.set(Some((leaf.on_match)(id)));
|
||||
} else {
|
||||
if let Some(on_unmatch) = n.on_unmatch.take() {
|
||||
on_unmatch();
|
||||
}
|
||||
leaf.targets.remove(n.target_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Target> Drop for NodeHolder<Target>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
if let Some(leaf) = self.node.leaf.upgrade() {
|
||||
leaf.push_event(&self.node, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Target> CritDestroyListenerBase<Target> for CritLeafMatcher<Target>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
type Data = NodeHolder<Target>;
|
||||
|
||||
fn data(&self) -> &CritPerTargetData<Target, Self::Data> {
|
||||
&self.targets
|
||||
}
|
||||
}
|
||||
4
src/criteria/crit_matchers.rs
Normal file
4
src/criteria/crit_matchers.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
pub mod critm_any_or_all;
|
||||
pub mod critm_constant;
|
||||
pub mod critm_exactly;
|
||||
pub mod critm_string;
|
||||
73
src/criteria/crit_matchers/critm_any_or_all.rs
Normal file
73
src/criteria/crit_matchers/critm_any_or_all.rs
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
use {
|
||||
crate::criteria::crit_graph::{CritMiddleCriterion, CritTarget, CritUpstreamNode},
|
||||
std::{marker::PhantomData, rc::Rc},
|
||||
};
|
||||
|
||||
pub struct CritMatchAnyOrAll<Target>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
all: bool,
|
||||
total: usize,
|
||||
_phantom: PhantomData<fn(&Target)>,
|
||||
}
|
||||
|
||||
impl<Target> CritMatchAnyOrAll<Target>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
pub fn new(upstream: &[Rc<dyn CritUpstreamNode<Target>>], all: bool) -> Self {
|
||||
Self {
|
||||
all,
|
||||
total: upstream.len(),
|
||||
_phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Target> CritMiddleCriterion<Target> for CritMatchAnyOrAll<Target>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
type Data = usize;
|
||||
type Not = Self;
|
||||
|
||||
fn update_matched(&self, _data: &Target, node: &mut usize, matched: bool) -> bool {
|
||||
if matched {
|
||||
*node += 1;
|
||||
} else {
|
||||
*node -= 1;
|
||||
}
|
||||
if self.all {
|
||||
*node == self.total
|
||||
} else {
|
||||
*node > 0
|
||||
}
|
||||
}
|
||||
|
||||
fn pull(&self, upstream: &[Rc<dyn CritUpstreamNode<Target>>], node: &Target) -> bool {
|
||||
for upstream in upstream {
|
||||
if upstream.pull(node) {
|
||||
if !self.all {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if self.all {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.all
|
||||
}
|
||||
|
||||
fn not(&self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Self {
|
||||
all: !self.all,
|
||||
total: self.total,
|
||||
_phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
59
src/criteria/crit_matchers/critm_constant.rs
Normal file
59
src/criteria/crit_matchers/critm_constant.rs
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
use {
|
||||
crate::criteria::{
|
||||
CritMatcherIds, FixedRootMatcher,
|
||||
crit_graph::{
|
||||
CritFixedRootCriterion, CritFixedRootCriterionBase, CritMgr, CritRoot, CritRootFixed,
|
||||
CritTarget,
|
||||
},
|
||||
},
|
||||
linearize::static_map,
|
||||
std::{marker::PhantomData, rc::Rc},
|
||||
};
|
||||
|
||||
pub struct CritMatchConstant<Target>(pub bool, pub PhantomData<fn(&Target)>);
|
||||
|
||||
impl<Target> CritMatchConstant<Target>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
#[expect(dead_code)]
|
||||
pub fn create(
|
||||
roots: &Rc<Target::RootMatchers>,
|
||||
ids: &CritMatcherIds,
|
||||
) -> FixedRootMatcher<Target, CritMatchConstant<Target>> {
|
||||
static_map! {
|
||||
v => CritRoot::new(
|
||||
roots,
|
||||
ids.next(),
|
||||
CritRootFixed(Self(v, PhantomData), PhantomData),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Target> CritFixedRootCriterionBase<Target> for CritMatchConstant<Target>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
fn constant(&self) -> bool {
|
||||
self.0
|
||||
}
|
||||
|
||||
fn not<'a>(&self, mgr: &'a Target::Mgr) -> &'a FixedRootMatcher<Target, Self>
|
||||
where
|
||||
Self: CritFixedRootCriterion<Target>,
|
||||
{
|
||||
mgr.match_constant()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Target> CritFixedRootCriterion<Target> for CritMatchConstant<Target>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
const COMPARE: bool = false;
|
||||
|
||||
fn matches(&self, _data: &Target) -> bool {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
61
src/criteria/crit_matchers/critm_exactly.rs
Normal file
61
src/criteria/crit_matchers/critm_exactly.rs
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
use {
|
||||
crate::criteria::crit_graph::{CritMiddleCriterion, CritTarget, CritUpstreamNode},
|
||||
std::{marker::PhantomData, rc::Rc},
|
||||
};
|
||||
|
||||
pub struct CritMatchExactly<Target> {
|
||||
total: usize,
|
||||
num: usize,
|
||||
not: bool,
|
||||
_phantom: PhantomData<fn(&Target)>,
|
||||
}
|
||||
|
||||
impl<Target> CritMatchExactly<Target> {
|
||||
pub fn new(upstream: &[Rc<dyn CritUpstreamNode<Target>>], num: usize) -> Self {
|
||||
Self {
|
||||
total: upstream.len(),
|
||||
num,
|
||||
not: false,
|
||||
_phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Target> CritMiddleCriterion<Target> for CritMatchExactly<Target>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
type Data = usize;
|
||||
type Not = Self;
|
||||
|
||||
fn update_matched(&self, _data: &Target, node: &mut usize, matched: bool) -> bool {
|
||||
if matched {
|
||||
*node += 1;
|
||||
} else {
|
||||
*node -= 1;
|
||||
}
|
||||
(*node == self.num) ^ self.not
|
||||
}
|
||||
|
||||
fn pull(&self, upstream: &[Rc<dyn CritUpstreamNode<Target>>], node: &Target) -> bool {
|
||||
let mut n = 0;
|
||||
for upstream in upstream {
|
||||
if upstream.pull(node) {
|
||||
n += 1;
|
||||
}
|
||||
}
|
||||
(n == self.num) ^ self.not
|
||||
}
|
||||
|
||||
fn not(&self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Self {
|
||||
total: self.total,
|
||||
num: self.total - self.num,
|
||||
not: !self.not,
|
||||
_phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
46
src/criteria/crit_matchers/critm_string.rs
Normal file
46
src/criteria/crit_matchers/critm_string.rs
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
use {
|
||||
crate::criteria::{
|
||||
CritLiteralOrRegex, RootMatcherMap,
|
||||
crit_graph::{CritRootCriterion, CritTarget},
|
||||
},
|
||||
std::marker::PhantomData,
|
||||
};
|
||||
|
||||
pub struct CritMatchString<Target, A> {
|
||||
string: CritLiteralOrRegex,
|
||||
_phantom: PhantomData<(fn(&Target), A)>,
|
||||
}
|
||||
|
||||
pub trait StringAccess<Target>: Sized + 'static
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
fn with_string(data: &Target, f: impl FnOnce(&str) -> bool) -> bool;
|
||||
fn nodes(
|
||||
roots: &Target::RootMatchers,
|
||||
) -> &RootMatcherMap<Target, CritMatchString<Target, Self>>;
|
||||
}
|
||||
|
||||
impl<Target, A> CritMatchString<Target, A> {
|
||||
#[expect(dead_code)]
|
||||
pub fn new(string: CritLiteralOrRegex) -> Self {
|
||||
Self {
|
||||
string,
|
||||
_phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Target, A> CritRootCriterion<Target> for CritMatchString<Target, A>
|
||||
where
|
||||
Target: CritTarget,
|
||||
A: StringAccess<Target>,
|
||||
{
|
||||
fn matches(&self, data: &Target) -> bool {
|
||||
A::with_string(data, |s| self.string.matches(s))
|
||||
}
|
||||
|
||||
fn nodes(roots: &Target::RootMatchers) -> Option<&RootMatcherMap<Target, Self>> {
|
||||
Some(A::nodes(roots))
|
||||
}
|
||||
}
|
||||
136
src/criteria/crit_per_target_data.rs
Normal file
136
src/criteria/crit_per_target_data.rs
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
use {
|
||||
crate::criteria::{
|
||||
CritMatcherId,
|
||||
crit_graph::{CritTarget, CritTargetOwner, WeakCritTargetOwner},
|
||||
},
|
||||
ahash::AHashMap,
|
||||
std::{
|
||||
cell::{RefCell, RefMut},
|
||||
ops::{Deref, DerefMut},
|
||||
rc::Weak,
|
||||
},
|
||||
};
|
||||
|
||||
pub struct CritPerTargetData<Target, T>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
id: CritMatcherId,
|
||||
slf: Weak<dyn CritDestroyListener<Target>>,
|
||||
data: RefCell<AHashMap<Target::Id, PerTreeNodeData<Target, T>>>,
|
||||
}
|
||||
|
||||
pub struct PerTreeNodeData<Target, T>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
node: Target::Owner,
|
||||
data: T,
|
||||
}
|
||||
|
||||
pub(super) trait CritDestroyListenerBase<Target>: 'static
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
type Data;
|
||||
|
||||
fn data(&self) -> &CritPerTargetData<Target, Self::Data>;
|
||||
}
|
||||
|
||||
pub trait CritDestroyListener<Target>: 'static
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
#[expect(dead_code)]
|
||||
fn destroyed(&self, target_id: Target::Id);
|
||||
}
|
||||
|
||||
impl<Target, T> CritPerTargetData<Target, T>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
pub fn new(slf: &Weak<impl CritDestroyListener<Target>>, id: CritMatcherId) -> Self {
|
||||
Self {
|
||||
id,
|
||||
slf: slf.clone() as _,
|
||||
data: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_or_create(&self, target: &Target, default: impl FnOnce() -> T) -> RefMut<T> {
|
||||
RefMut::map(self.data.borrow_mut(), |d| {
|
||||
&mut d
|
||||
.entry(target.id())
|
||||
.or_insert_with(|| {
|
||||
target.destroyed().set(self.id, self.slf.clone());
|
||||
PerTreeNodeData {
|
||||
node: target.owner(),
|
||||
data: default(),
|
||||
}
|
||||
})
|
||||
.data
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get(&self, target: &Target) -> Option<RefMut<T>> {
|
||||
RefMut::filter_map(self.data.borrow_mut(), |d| {
|
||||
d.get_mut(&target.id()).map(|d| &mut d.data)
|
||||
})
|
||||
.ok()
|
||||
}
|
||||
|
||||
pub fn remove(&self, target_id: Target::Id) {
|
||||
if let Some(node) = self.data.borrow_mut().remove(&target_id) {
|
||||
if let Some(node) = node.node.upgrade() {
|
||||
node.data().destroyed().remove(&self.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn borrow_mut(&self) -> RefMut<'_, AHashMap<Target::Id, PerTreeNodeData<Target, T>>> {
|
||||
self.data.borrow_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Target, T> Drop for CritPerTargetData<Target, T>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
for d in self.data.borrow().values() {
|
||||
if let Some(n) = d.node.upgrade() {
|
||||
n.data().destroyed().remove(&self.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Target, T> CritDestroyListener<Target> for T
|
||||
where
|
||||
Target: CritTarget,
|
||||
T: CritDestroyListenerBase<Target>,
|
||||
{
|
||||
fn destroyed(&self, target_id: Target::Id) {
|
||||
let _v = self.data().data.borrow_mut().remove(&target_id);
|
||||
}
|
||||
}
|
||||
|
||||
impl<Target, T> Deref for PerTreeNodeData<Target, T>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<Target, T> DerefMut for PerTreeNodeData<Target, T>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.data
|
||||
}
|
||||
}
|
||||
|
|
@ -181,10 +181,10 @@ macro_rules! shared_ids {
|
|||
}
|
||||
|
||||
macro_rules! linear_ids {
|
||||
($ids:ident, $id:ident $(,)?) => {
|
||||
linear_ids!($ids, $id, u32);
|
||||
($(#[$attr1:meta])* $ids:ident, $id:ident $(,)?) => {
|
||||
linear_ids!($(#[$attr1])* $ids, $id, u32);
|
||||
};
|
||||
($ids:ident, $id:ident, $ty:ty $(,)?) => {
|
||||
($(#[$attr1:meta])* $ids:ident, $id:ident, $ty:ty $(,)?) => {
|
||||
pub struct $ids {
|
||||
next: crate::utils::numcell::NumCell<$ty>,
|
||||
}
|
||||
|
|
@ -197,6 +197,7 @@ macro_rules! linear_ids {
|
|||
}
|
||||
}
|
||||
|
||||
$(#[$attr1])*
|
||||
impl $ids {
|
||||
pub fn next(&self) -> $id {
|
||||
$id(self.next.fetch_add(1))
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ mod cmm;
|
|||
mod compositor;
|
||||
mod config;
|
||||
mod cpu_worker;
|
||||
mod criteria;
|
||||
mod cursor;
|
||||
mod cursor_user;
|
||||
mod damage;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue