spreadsheet_ods/
attrmap2.rs1use get_size2::GetSize;
8use std::mem::size_of;
9use std::slice;
10use string_cache::DefaultAtom;
11
12#[derive(Default, Clone, Debug, PartialEq)]
14pub struct AttrMap2 {
15 keys: Vec<DefaultAtom>,
16 values: Vec<Box<str>>,
17}
18
19impl GetSize for AttrMap2 {
20 fn get_heap_size(&self) -> usize {
21 self.keys.capacity() * size_of::<DefaultAtom>()
22 + self.values.capacity() * size_of::<Box<str>>()
23 + self.values.iter().map(|v| v.get_heap_size()).sum::<usize>()
24 }
25}
26
27impl AttrMap2 {
28 #[allow(dead_code)]
29 pub fn new() -> Self {
30 AttrMap2 {
31 keys: Default::default(),
32 values: Default::default(),
33 }
34 }
35
36 #[inline]
38 pub fn is_empty(&self) -> bool {
39 self.keys.is_empty()
40 }
41
42 #[inline]
43 pub fn shrink_to_fit(&mut self) {
44 self.keys.shrink_to_fit();
45 self.values.shrink_to_fit();
46 }
47
48 #[inline]
50 pub fn add_all<'a, V: Into<String>, I: IntoIterator<Item = (&'a str, V)>>(&mut self, data: I) {
51 for (k, v) in data {
52 self.keys.push(DefaultAtom::from(k));
53 self.values.push(v.into().into_boxed_str());
54 }
55 }
56
57 #[inline]
59 pub fn set_attr<S: Into<String>>(&mut self, name: &str, value: S) {
60 let k = DefaultAtom::from(name);
61 let v = value.into().into_boxed_str();
62 if let Some(idx) = self.find_idx(&k) {
63 self.keys[idx] = k;
64 self.values[idx] = v;
65 } else {
66 self.keys.push(k);
67 self.values.push(v);
68 }
69 }
70
71 #[inline]
72 pub(crate) fn push_attr<S: Into<String>>(&mut self, name: &str, value: S) {
73 self.keys.push(DefaultAtom::from(name));
74 self.values.push(value.into().into_boxed_str());
75 }
76
77 #[inline(always)]
78 fn find_idx(&self, test: &DefaultAtom) -> Option<usize> {
79 self.keys
80 .iter()
81 .enumerate()
82 .find(|v| v.1 == test)
83 .map(|v| v.0)
84 }
85
86 #[inline]
88 pub fn clear_attr(&mut self, name: &str) -> Option<String> {
89 let k = DefaultAtom::from(name);
90 if let Some(idx) = self.find_idx(&k) {
91 self.keys.remove(idx);
92 Some(self.values.remove(idx).into_string())
93 } else {
94 None
95 }
96 }
97
98 #[inline]
100 pub fn attr(&self, name: &str) -> Option<&str> {
101 let k = DefaultAtom::from(name);
102 if let Some(idx) = self.find_idx(&k) {
103 Some(&self.values[idx])
104 } else {
105 None
106 }
107 }
108
109 #[inline]
111 pub fn attr_def<'a, 'b, S>(&'a self, name: &'b str, default: S) -> &'a str
112 where
113 S: Into<&'a str>,
114 {
115 let k = DefaultAtom::from(name);
116 if let Some(idx) = self.find_idx(&k) {
117 &self.values[idx]
118 } else {
119 default.into()
120 }
121 }
122
123 pub fn iter(&self) -> AttrMapIter<'_> {
124 From::from(self)
125 }
126
127 #[inline]
128 pub fn len(&self) -> usize {
129 self.keys.len()
130 }
131}
132
133#[derive(Debug)]
135pub struct AttrMapIter<'a> {
136 it: slice::Iter<'a, DefaultAtom>,
137 jt: slice::Iter<'a, Box<str>>,
138}
139
140impl<'a> From<&'a AttrMap2> for AttrMapIter<'a> {
141 fn from(attrmap: &'a AttrMap2) -> Self {
142 Self {
143 it: attrmap.keys.iter(),
144 jt: attrmap.values.iter(),
145 }
146 }
147}
148
149impl<'a> Iterator for AttrMapIter<'a> {
150 type Item = (&'a DefaultAtom, &'a str);
151
152 fn next(&mut self) -> Option<Self::Item> {
153 let k = self.it.next();
154 let v = self.jt.next();
155
156 match (k, v) {
157 (Some(k), Some(v)) => Some((k, v)),
158 (None, None) => None,
159 _ => unreachable!(),
160 }
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use crate::attrmap2::AttrMap2;
167
168 #[test]
169 fn test_attrmap2() {
170 let mut m = AttrMap2::new();
171
172 m.add_all([("foo", "baz"), ("lol", "now"), ("ful", "uuu")]);
173 assert_eq!(m.attr("foo").unwrap(), "baz");
174
175 m.set_attr("lol", "loud!".to_string());
176 assert_eq!(m.attr("lol").unwrap(), "loud!");
177
178 m.clear_attr("ful");
179 assert_eq!(m.attr("ful"), None);
180 }
181}