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