Skip to main content

spreadsheet_ods/
attrmap2.rs

1//!
2//! Defines the type AttrMap as container for different attribute-sets.
3//! And there are a number of traits working with AttrMap to set
4//! related families of attributes.
5//!
6
7use get_size2::GetSize;
8use std::mem::size_of;
9use std::slice;
10use string_cache::DefaultAtom;
11
12/// Container type for attributes.
13#[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    /// Are there any attributes?
37    #[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    /// Add from Slice
49    #[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    /// Adds an attribute.
58    #[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    /// Removes an attribute.
87    #[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    /// Returns the attribute.
99    #[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    /// Returns a property or a default.
110    #[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/// Iterator for an AttrMap.
134#[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}