1 //! Internal entry map
2 //!
3 //! The map uses unsafe code and this module provides a safe but
4 //! unergonomic API for use by the nicer API.
5 use crate::{parser::parse_entry, ParseError};
6 use std::{
7     collections::{hash_map::Keys, HashMap},
8     fmt::{Debug, Formatter},
9     hash::Hash,
10     intrinsics::transmute,
11     marker::PhantomPinned,
12     pin::Pin,
13     ptr::NonNull,
14 };
15 
16 pub struct AttrValue {
17     value: Option<SP>,
18     param_map: Option<ParamMap>,
19 }
20 
21 /// <section, <attribute, {value, <param, param_vale>}>>
22 type InternalMap = HashMap<SP, AttrMap>;
23 
24 pub(crate) struct AttrMap(HashMap<SP, AttrValue>);
25 pub(crate) struct ParamMap(HashMap<SP, SP>);
26 
27 pub(crate) struct Internal {
28     map: Option<InternalMap>,
29     data: Vec<u8>,
30     _pin: PhantomPinned,
31 }
32 
33 impl Internal {
new(data: Vec<u8>) -> Result<Pin<Box<Self>>, ParseError>34     pub(crate) fn new(data: Vec<u8>) -> Result<Pin<Box<Self>>, ParseError> {
35         let this = Self {
36             map: None,
37             data,
38             _pin: PhantomPinned,
39         };
40         let mut boxed = Box::pin(this);
41 
42         let entry_bytes =
43             parse_entry(&boxed.data).collect::<Result<Vec<_>, _>>()?;
44 
45         let mut sections: InternalMap = HashMap::new();
46 
47         for section_bytes in entry_bytes {
48             let section = parse_str(section_bytes.title)?;
49             let mut map: HashMap<SP, AttrValue> = HashMap::new();
50             for attr_bytes in section_bytes.attrs {
51                 let value = parse_str(attr_bytes.value)?;
52 
53                 match attr_bytes.param {
54                     Some(param) => {
55                         let name = parse_str(param.attr_name)?;
56                         let param = parse_str(param.param)?;
57                         map.entry(SP::from(name))
58                             .and_modify(|attr| {
59                                 attr.param_map
60                                     .get_or_insert_with(ParamMap::new)
61                                     .0
62                                     .insert(SP::from(param), SP::from(value));
63                             })
64                             .or_insert(AttrValue {
65                                 value: None,
66                                 param_map: {
67                                     let mut map = HashMap::new();
68                                     map.insert(
69                                         SP::from(param),
70                                         SP::from(value),
71                                     );
72                                     Some(ParamMap(map))
73                                 },
74                             });
75                     }
76                     None => {
77                         let name = parse_str(attr_bytes.name)?;
78                         map.entry(SP::from(name))
79                             .and_modify(|attr| {
80                                 attr.value = Some(SP::from(value))
81                             })
82                             .or_insert(AttrValue {
83                                 value: Some(SP::from(value)),
84                                 param_map: None,
85                             });
86                     }
87                 }
88             }
89             sections.insert(SP::from(section), AttrMap(map));
90         }
91         // SAFETY: we know this is safe because modifying a field doesn't move the whole struct
92         unsafe {
93             let mut_ref: Pin<&mut Internal> = Pin::as_mut(&mut boxed);
94             Pin::get_unchecked_mut(mut_ref).map = Some(sections);
95         }
96         Ok(boxed)
97     }
98 
get_section<'a>( self: &'a Pin<Box<Self>>, section_name: &str, ) -> Option<&'a AttrMap>99     fn get_section<'a>(
100         self: &'a Pin<Box<Self>>,
101         section_name: &str,
102     ) -> Option<&'a AttrMap> {
103         self.map.as_ref().unwrap().get(&SP::from(section_name))
104     }
105 
get<'a>( self: &'a Pin<Box<Self>>, section_name: &str, attr_name: &str, param_name: Option<&str>, ) -> Option<&'a str>106     pub(crate) fn get<'a>(
107         self: &'a Pin<Box<Self>>,
108         section_name: &str,
109         attr_name: &str,
110         param_name: Option<&str>,
111     ) -> Option<&'a str> {
112         let section_map = self.get_section(section_name)?;
113         let attr_val = section_map.get_attr(attr_name)?;
114         match param_name {
115             Some(param_name) => {
116                 let param_map = attr_val.param_map.as_ref()?;
117                 param_map.get_param(param_name)
118             }
119             None => attr_val.get_value(),
120         }
121     }
122 
get_attr<'a>( self: &'a Pin<Box<Self>>, section_name: &str, attr_name: &str, ) -> Option<&'a AttrValue>123     pub(crate) fn get_attr<'a>(
124         self: &'a Pin<Box<Self>>,
125         section_name: &str,
126         attr_name: &str,
127     ) -> Option<&'a AttrValue> {
128         let section_map = self.get_section(section_name)?;
129         section_map.get_attr(attr_name)
130     }
131 
has_section( self: &Pin<Box<Self>>, section_name: &str, ) -> bool132     pub(crate) fn has_section(
133         self: &Pin<Box<Self>>,
134         section_name: &str,
135     ) -> bool {
136         self.get_section(section_name).is_some()
137     }
138 
139     // Clippy is wrong here
140     #[allow(clippy::needless_lifetimes)]
section_names_iter<'a>( self: &'a Pin<Box<Self>>, ) -> SectionNamesIter<'a>141     pub(crate) fn section_names_iter<'a>(
142         self: &'a Pin<Box<Self>>,
143     ) -> SectionNamesIter<'a> {
144         KeysIter(self.map.as_ref().unwrap().keys())
145     }
146 
attr_names_iter<'a>( self: &'a Pin<Box<Self>>, section_name: &str, ) -> Option<AttrNamesIter<'a>>147     pub(crate) fn attr_names_iter<'a>(
148         self: &'a Pin<Box<Self>>,
149         section_name: &str,
150     ) -> Option<AttrNamesIter<'a>> {
151         Some(KeysIter(self.get_section(section_name)?.0.keys()))
152     }
153 
param_names_iter<'a>( self: &'a Pin<Box<Self>>, section_name: &str, attr_name: &str, ) -> Option<ParamNamesIter<'a>>154     pub(crate) fn param_names_iter<'a>(
155         self: &'a Pin<Box<Self>>,
156         section_name: &str,
157         attr_name: &str,
158     ) -> Option<ParamNamesIter<'a>> {
159         let section_map = self.get_section(section_name)?;
160         let attr_val = section_map.get_attr(attr_name)?;
161         let param_map = attr_val.param_map.as_ref()?;
162         Some(KeysIter(param_map.0.keys()))
163     }
164 }
165 
166 impl AttrMap {
get_attr(&self, attr_name: &str) -> Option<&AttrValue>167     pub(crate) fn get_attr(&self, attr_name: &str) -> Option<&AttrValue> {
168         self.0.get(&SP::from(attr_name))
169     }
170 }
171 
172 impl AttrValue {
get_value(&self) -> Option<&str>173     pub(crate) fn get_value(&self) -> Option<&str> {
174         // SAFETY: This is safe because the string has the same lifetime as Entry
175         self.value
176             .as_ref()
177             .map(|s| unsafe { transmute(&*s.0.as_ptr()) })
178     }
179 
get_params(&self) -> Option<&ParamMap>180     pub(crate) fn get_params(&self) -> Option<&ParamMap> {
181         self.param_map.as_ref()
182     }
183 }
184 
185 impl ParamMap {
new() -> ParamMap186     fn new() -> ParamMap {
187         ParamMap(HashMap::new())
188     }
189 
get_param<'a>(&'a self, param_val: &str) -> Option<&'a str>190     pub(crate) fn get_param<'a>(&'a self, param_val: &str) -> Option<&'a str> {
191         self.0
192             .get(&SP::from(param_val))
193             // SAFETY: This is safe because the string has the same lifetime as Entry
194             .map(|s| unsafe { transmute(&*s.0.as_ptr()) })
195     }
196 }
197 
198 pub(crate) struct KeysIter<'a, T>(Keys<'a, SP, T>);
199 
200 impl<'a, T> Iterator for KeysIter<'a, T> {
201     type Item = &'a str;
next(&mut self) -> Option<Self::Item>202     fn next(&mut self) -> Option<Self::Item> {
203         self.0.next().map(|sp| unsafe { transmute(&*sp.0.as_ptr()) })
204     }
205 }
206 
207 pub(crate) type SectionNamesIter<'a> = KeysIter<'a, AttrMap>;
208 pub(crate) type AttrNamesIter<'a> = KeysIter<'a, AttrValue>;
209 pub(crate) type ParamNamesIter<'a> = KeysIter<'a, SP>;
210 
211 /// str pointer
212 #[derive(Eq)]
213 pub(crate) struct SP(NonNull<str>);
214 
215 impl SP {
from(s: &str) -> Self216     fn from(s: &str) -> Self {
217         SP(NonNull::from(s))
218     }
219 }
220 
221 impl PartialEq for SP {
eq(&self, other: &Self) -> bool222     fn eq(&self, other: &Self) -> bool {
223         // SAFETY: This is safe because both references are dropped at the end
224         // of the fn
225         unsafe { *self.0.as_ref() == *other.0.as_ref() }
226     }
227 }
228 
229 impl Hash for SP {
hash<H: std::hash::Hasher>(&self, state: &mut H)230     fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
231         // SAFETY: This is safe because the reference is dropped at the end
232         // of the fn
233         unsafe { self.0.as_ref().hash(state) }
234     }
235 }
236 
237 impl Debug for SP {
fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result238     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
239         // SAFETY: This is safe because the reference is dropped at the end of
240         // the fn
241         unsafe { self.0.as_ref().fmt(f) }
242     }
243 }
244 
245 #[inline]
parse_str(input: &[u8]) -> Result<&str, ParseError>246 fn parse_str(input: &[u8]) -> Result<&str, ParseError> {
247     std::str::from_utf8(input).map_err(|e| ParseError::Utf8Error {
248         bytes: input.to_owned(),
249         source: e,
250     })
251 }
252