indigo_core/
attributes.rs1use indigo_kernel::edit::{self, Edit};
2use roaring::RoaringBitmap;
3use std::{
4 borrow::Borrow,
5 collections::BTreeMap,
6 iter,
7 ops::{RangeBounds, RangeInclusive},
8};
9
10pub struct Attributes<A> {
11 pub inner: BTreeMap<A, RoaringBitmap>,
12}
13
14impl<A> Attributes<A> {
15 #[must_use]
16 pub fn new() -> Self {
17 Self::default()
18 }
19
20 pub fn insert<R>(&mut self, range: R, attribute: A)
21 where
22 R: RangeBounds<u32>,
23 A: Ord,
24 {
25 self.inner.entry(attribute).or_default().insert_range(range);
26 }
27
28 pub fn remove<R, Q>(&mut self, range: R, attribute: &Q)
29 where
30 R: RangeBounds<u32>,
31 A: Borrow<Q> + Ord,
32 Q: Ord + ?Sized,
33 {
34 let attribute = attribute.borrow();
35 if let Some(ranges) = self.inner.get_mut(attribute) {
36 ranges.remove_range(range);
37 if ranges.is_empty() {
38 self.inner.remove(attribute);
39 }
40 }
41 }
42
43 #[must_use]
44 pub fn contains<R, Q>(&self, range: R, attribute: &Q) -> bool
45 where
46 R: RangeBounds<u32>,
47 A: Borrow<Q> + Ord,
48 Q: Ord + ?Sized,
49 {
50 match self.inner.get(attribute.borrow()) {
51 Some(ranges) => ranges.contains_range(range),
52 None => false,
53 }
54 }
55
56 #[must_use]
57 pub fn ranges<Q>(&self, attribute: &Q) -> Option<impl Iterator<Item = RangeInclusive<u32>>>
58 where
59 A: Borrow<Q> + Ord,
60 Q: Ord + ?Sized,
61 {
62 self.inner.get(attribute.borrow()).map(|ranges| Ranges {
63 iter: ranges.iter(),
64 })
65 }
66
67 pub fn attrs<R>(&self, range: R) -> impl Iterator<Item = &A>
68 where
69 R: RangeBounds<u32> + Clone,
70 {
71 iter::zip(self.inner.iter(), iter::repeat(range))
72 .filter_map(|((attr, ranges), range)| ranges.contains_range(range).then_some(attr))
73 }
74
75 pub fn transform(&mut self, ops: &Edit) {
76 for old_ranges in self.inner.values_mut() {
77 let mut iter = old_ranges.iter();
78 let mut offsets: Vec<usize> = iter::from_fn(|| iter.next_range())
79 .flat_map(|range| {
80 let start =
81 usize::try_from(*range.start()).expect("Machine has 64-bit pointers");
82 let end = usize::try_from(*range.end()).expect("Machine has 64-bit pointers");
83 [start, end]
84 })
85 .collect();
86 ops.map_positions_sorted(&mut offsets, edit::Bias::Forward);
87 let mut new_ranges = RoaringBitmap::new();
88 let (chunks, remainder) = offsets.as_chunks::<2>();
89 for pair in chunks {
90 let start = u32::try_from(pair[0]).expect("Byte offset does not exceed u32::MAX");
91 let end = u32::try_from(pair[1]).expect("Byte offset does not exceed u32::MAX");
92 new_ranges.insert_range(start..=end);
93 }
94 assert_eq!(remainder, []);
95 *old_ranges = new_ranges;
96 }
97 }
98}
99
100impl<A> Default for Attributes<A> {
101 fn default() -> Self {
102 Self {
103 inner: BTreeMap::default(),
104 }
105 }
106}
107
108pub struct Ranges<'a> {
112 iter: roaring::bitmap::Iter<'a>,
113}
114
115impl Iterator for Ranges<'_> {
116 type Item = RangeInclusive<u32>;
117 fn next(&mut self) -> Option<Self::Item> {
118 self.iter.next_range()
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 #[test]
127 fn demo() {
128 let mut attrs = Attributes::new();
129 attrs.insert(0..=4, String::from("foo"));
130 attrs.insert(2..=8, String::from("foo"));
131 assert!(attrs.contains(0..=8, "foo"));
132 attrs.remove(4..=6, "foo");
133 assert!(attrs.contains(0..=3, "foo"));
134 assert!(!attrs.contains(4..=6, "foo"));
135 assert!(attrs.contains(7..=8, "foo"));
136 let expected_ranges = vec![0..=3, 7..=8];
137 let actual_ranges: Vec<_> = attrs.ranges("foo").unwrap().collect();
138 assert_eq!(expected_ranges, actual_ranges);
139 let expected_attrs = vec!["foo"];
140 let actual_attrs: Vec<_> = attrs.attrs(0..=3).cloned().collect();
141 assert_eq!(expected_attrs, actual_attrs);
142 }
143
144 #[test]
145 fn inner() {
146 let mut attrs = Attributes::new();
147 attrs.insert(0..=10, String::from("color=red"));
148 attrs.insert(5..=15, String::from("color=green"));
149 attrs.insert(10..=20, String::from("color=blue"));
150 attrs.insert(0..=5, String::from("font=bold"));
151 attrs.insert(15..=25, String::from("font=italic"));
152
153 let color_attrs: Vec<_> = attrs
155 .inner
156 .range(String::from("color=")..String::from("color=\u{10ffff}"))
157 .map(|(attr, _)| attr.as_str())
158 .collect();
159 assert_eq!(color_attrs, vec!["color=blue", "color=green", "color=red"]);
160
161 let specific_colors: Vec<_> = attrs
163 .inner
164 .range(String::from("color=blue")..=String::from("color=green"))
165 .map(|(attr, _)| attr.as_str())
166 .collect();
167 assert_eq!(specific_colors, vec!["color=blue", "color=green"]);
168
169 let font_attrs: Vec<_> = attrs
171 .inner
172 .range(String::from("font=")..String::from("font=\u{10ffff}"))
173 .map(|(attr, _)| attr.as_str())
174 .collect();
175 assert_eq!(font_attrs, vec!["font=bold", "font=italic"]);
176
177 attrs.inner.retain(|attr, _| !attr.starts_with("color="));
179
180 let remaining_attrs: Vec<_> = attrs.inner.keys().collect();
182 assert_eq!(remaining_attrs, vec!["font=bold", "font=italic"]);
183 }
184}