-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathslots.rs
More file actions
70 lines (63 loc) · 1.9 KB
/
Copy pathslots.rs
File metadata and controls
70 lines (63 loc) · 1.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
//! Projected `VNode`s and named/default projection bags.
use std::collections::HashMap;
use rangular_parser::matches_select;
#[derive(Clone, Debug, PartialEq)]
pub enum VNode {
Element {
tag: String,
attrs: Vec<(String, String)>,
children: Vec<Self>,
},
Text(String),
}
/// Projected roots partitioned into named selects and a default bucket.
#[derive(Clone, Debug, Default, PartialEq)]
pub struct ProjectionBag {
pub default: Vec<VNode>,
pub named: HashMap<String, Vec<VNode>>,
}
impl ProjectionBag {
#[must_use]
pub fn from_flat(roots: &[VNode], selects: &[String]) -> Self {
if selects.is_empty() {
return Self {
default: roots.to_vec(),
named: HashMap::new(),
};
}
let mut used = vec![false; roots.len()];
let mut named = HashMap::new();
for select in selects {
let mut matched = Vec::new();
for (i, root) in roots.iter().enumerate() {
if used[i] {
continue;
}
if vnode_matches(root, select) {
matched.push(root.clone());
used[i] = true;
}
}
named.insert(select.clone(), matched);
}
let default = roots
.iter()
.enumerate()
.filter(|(i, _)| !used[*i])
.map(|(_, v)| v.clone())
.collect();
Self { default, named }
}
#[must_use]
pub fn for_select(&self, select: Option<&str>) -> &[VNode] {
select.map_or(self.default.as_slice(), |sel| {
self.named.get(sel).map_or(&[], Vec::as_slice)
})
}
}
fn vnode_matches(node: &VNode, select: &str) -> bool {
match node {
VNode::Element { tag, attrs, .. } => matches_select(tag, attrs, select),
VNode::Text(_) => false,
}
}