• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #[derive(Default)]
2 pub struct Properties<T> {
3     props: Vec<T>,
4 }
5 
6 /// This encapsulates a C property array, where the list is 0 terminated.
7 impl<T> Properties<T> {
8     /// Creates a Properties object copying from the supplied pointer.
9     ///
10     /// It returns `None` if any property is found twice.
11     ///
12     /// If `p` is null the saved list of properties will be empty. Otherwise it will be 0
13     /// terminated.
14     ///
15     /// # Safety
16     ///
17     /// Besides `p` being valid to be dereferenced, it also needs to point to a `T::default()`
18     /// terminated array of `T`.
new(mut p: *const T) -> Option<Self> where T: Copy + Default + PartialEq,19     pub unsafe fn new(mut p: *const T) -> Option<Self>
20     where
21         T: Copy + Default + PartialEq,
22     {
23         let mut res = Self::default();
24         if !p.is_null() {
25             unsafe {
26                 while *p != T::default() {
27                     // Property lists are expected to be small, so no point in using HashSet or
28                     // sorting.
29                     if res.get(&*p).is_some() {
30                         return None;
31                     }
32 
33                     res.props.push(*p);
34                     res.props.push(*p.add(1));
35 
36                     // Advance by two as we read through a list of pairs.
37                     p = p.add(2);
38                 }
39             }
40 
41             // terminate the array
42             res.props.push(T::default());
43         }
44 
45         Some(res)
46     }
47 
48     /// Returns the value for the given `key` if existent.
get(&self, key: &T) -> Option<&T> where T: PartialEq,49     pub fn get(&self, key: &T) -> Option<&T>
50     where
51         T: PartialEq,
52     {
53         self.iter().find_map(|(k, v)| (k == key).then_some(v))
54     }
55 
56     /// Returns true when there is no property available.
is_empty(&self) -> bool57     pub fn is_empty(&self) -> bool {
58         self.props.len() <= 1
59     }
60 
iter(&self) -> impl Iterator<Item = (&T, &T)>61     pub fn iter(&self) -> impl Iterator<Item = (&T, &T)> {
62         // TODO: use array_chuncks once stabilized
63         self.props
64             .chunks_exact(2)
65             .map(|elems| (&elems[0], &elems[1]))
66     }
67 
68     /// Returns the amount of key/value pairs available.
len(&self) -> usize69     pub fn len(&self) -> usize {
70         // only valid lengths are all uneven numbers and 0, so division by 2 gives us always the
71         // correct result.
72         self.props.len() / 2
73     }
74 
75     /// Returns a slice to the raw buffer.
76     ///
77     /// It will return an empty slice if `self` was created with a null pointer. A `T::default()`
78     /// terminated one otherwise.
raw_data(&self) -> &[T]79     pub fn raw_data(&self) -> &[T] {
80         &self.props
81     }
82 }
83