1use bstr::{BStr, BString};
2
3use crate::{AsBStrOpt, AsKey, File, file::Metadata, value};
4
5impl File {
7 pub fn string(&self, key: impl AsKey) -> Option<BString> {
9 self.string_filter(key, |_| true)
10 }
11
12 pub fn string_by(
16 &self,
17 section_name: impl AsRef<str>,
18 subsection_name: impl AsBStrOpt,
19 value_name: impl AsRef<str>,
20 ) -> Option<BString> {
21 self.string_filter_by(section_name, subsection_name, value_name, |_| true)
22 }
23
24 pub fn string_filter(&self, key: impl AsKey, filter: impl FnMut(&Metadata) -> bool) -> Option<BString> {
26 let key = key.try_as_key()?;
27 self.raw_value_filter_by(key.section_name, key.subsection_name, key.value_name, filter)
28 .ok()
29 }
30
31 pub fn string_filter_by(
33 &self,
34 section_name: impl AsRef<str>,
35 subsection_name: impl AsBStrOpt,
36 value_name: impl AsRef<str>,
37 filter: impl FnMut(&Metadata) -> bool,
38 ) -> Option<BString> {
39 self.raw_value_filter_by(section_name, subsection_name, value_name, filter)
40 .ok()
41 }
42
43 pub fn path(&self, key: impl AsKey) -> Option<crate::Path> {
45 self.path_filter(key, |_| true)
46 }
47
48 pub fn path_by(
55 &self,
56 section_name: impl AsRef<str>,
57 subsection_name: impl AsBStrOpt,
58 value_name: impl AsRef<str>,
59 ) -> Option<crate::Path> {
60 self.path_filter_by(section_name, subsection_name, value_name, |_| true)
61 }
62
63 pub fn path_filter(&self, key: impl AsKey, filter: impl FnMut(&Metadata) -> bool) -> Option<crate::Path> {
65 let key = key.try_as_key()?;
66 self.path_filter_by(key.section_name, key.subsection_name, key.value_name, filter)
67 }
68
69 pub fn path_filter_by(
76 &self,
77 section_name: impl AsRef<str>,
78 subsection_name: impl AsBStrOpt,
79 value_name: impl AsRef<str>,
80 filter: impl FnMut(&Metadata) -> bool,
81 ) -> Option<crate::Path> {
82 self.raw_value_filter_by(section_name, subsection_name, value_name, filter)
83 .ok()
84 .map(crate::Path::from)
85 }
86
87 pub fn boolean(&self, key: impl AsKey) -> Result<Option<bool>, value::Error> {
89 self.boolean_filter(key, |_| true)
90 }
91
92 pub fn boolean_by(
94 &self,
95 section_name: impl AsRef<str>,
96 subsection_name: impl AsBStrOpt,
97 value_name: impl AsRef<str>,
98 ) -> Result<Option<bool>, value::Error> {
99 self.boolean_filter_by(section_name, subsection_name, value_name, |_| true)
100 }
101
102 pub fn boolean_filter(
104 &self,
105 key: impl AsKey,
106 filter: impl FnMut(&Metadata) -> bool,
107 ) -> Result<Option<bool>, value::Error> {
108 let Some(key) = key.try_as_key() else {
109 return Ok(None);
110 };
111 self.boolean_filter_by(key.section_name, key.subsection_name, key.value_name, filter)
112 }
113
114 pub fn boolean_filter_by(
116 &self,
117 section_name: impl AsRef<str>,
118 subsection_name: impl AsBStrOpt,
119 value_name: impl AsRef<str>,
120 mut filter: impl FnMut(&Metadata) -> bool,
121 ) -> Result<Option<bool>, value::Error> {
122 let section_name = section_name.as_ref();
123 let section_ids = self
124 .section_ids_by_name_and_subname(section_name, subsection_name.as_bstr_opt())
125 .ok();
126 let Some(section_ids) = section_ids else {
127 return Ok(None);
128 };
129 let key = value_name.as_ref();
130 for section_id in section_ids.rev() {
131 let section = self.sections.get(§ion_id).expect("known section id");
132 if !filter(section.meta()) {
133 continue;
134 }
135 match section.body.value_implicit_in(&self.backing, key) {
136 Some(Some(v)) => return crate::Boolean::try_from(v).map(|value| Some(value.into())),
137 Some(None) => return Ok(Some(true)),
138 None => continue,
139 }
140 }
141 Ok(None)
142 }
143
144 pub fn integer(&self, key: impl AsKey) -> Result<Option<i64>, value::Error> {
146 self.integer_filter(key, |_| true)
147 }
148
149 pub fn integer_by(
151 &self,
152 section_name: impl AsRef<str>,
153 subsection_name: impl AsBStrOpt,
154 value_name: impl AsRef<str>,
155 ) -> Result<Option<i64>, value::Error> {
156 self.integer_filter_by(section_name, subsection_name, value_name, |_| true)
157 }
158
159 pub fn integer_filter(
161 &self,
162 key: impl AsKey,
163 filter: impl FnMut(&Metadata) -> bool,
164 ) -> Result<Option<i64>, value::Error> {
165 let Some(key) = key.try_as_key() else {
166 return Ok(None);
167 };
168 self.integer_filter_by(key.section_name, key.subsection_name, key.value_name, filter)
169 }
170
171 pub fn integer_filter_by(
173 &self,
174 section_name: impl AsRef<str>,
175 subsection_name: impl AsBStrOpt,
176 value_name: impl AsRef<str>,
177 filter: impl FnMut(&Metadata) -> bool,
178 ) -> Result<Option<i64>, value::Error> {
179 let Some(int) = self
180 .raw_value_filter_by(section_name, subsection_name, value_name, filter)
181 .ok()
182 else {
183 return Ok(None);
184 };
185 crate::Integer::try_from(BStr::new(&int))
186 .and_then(|b| b.to_decimal().ok_or_else(|| value::Error::new("Integer overflow", int)))
187 .map(Some)
188 }
189
190 pub fn strings(&self, key: impl AsKey) -> Option<Vec<BString>> {
192 let key = key.try_as_key()?;
193 self.strings_by(key.section_name, key.subsection_name, key.value_name)
194 }
195
196 pub fn strings_by(
198 &self,
199 section_name: impl AsRef<str>,
200 subsection_name: impl AsBStrOpt,
201 value_name: impl AsRef<str>,
202 ) -> Option<Vec<BString>> {
203 self.raw_values_by(section_name, subsection_name, value_name).ok()
204 }
205
206 pub fn strings_filter(&self, key: impl AsKey, filter: impl FnMut(&Metadata) -> bool) -> Option<Vec<BString>> {
208 let key = key.try_as_key()?;
209 self.strings_filter_by(key.section_name, key.subsection_name, key.value_name, filter)
210 }
211
212 pub fn strings_filter_by(
214 &self,
215 section_name: impl AsRef<str>,
216 subsection_name: impl AsBStrOpt,
217 value_name: impl AsRef<str>,
218 filter: impl FnMut(&Metadata) -> bool,
219 ) -> Option<Vec<BString>> {
220 self.raw_values_filter_by(section_name, subsection_name, value_name, filter)
221 .ok()
222 }
223
224 pub fn integers(&self, key: impl AsKey) -> Result<Option<Vec<i64>>, value::Error> {
226 self.integers_filter(key, |_| true)
227 }
228
229 pub fn integers_by(
232 &self,
233 section_name: impl AsRef<str>,
234 subsection_name: impl AsBStrOpt,
235 value_name: impl AsRef<str>,
236 ) -> Result<Option<Vec<i64>>, value::Error> {
237 self.integers_filter_by(section_name, subsection_name, value_name, |_| true)
238 }
239
240 pub fn integers_filter(
242 &self,
243 key: impl AsKey,
244 filter: impl FnMut(&Metadata) -> bool,
245 ) -> Result<Option<Vec<i64>>, value::Error> {
246 let Some(key) = key.try_as_key() else {
247 return Ok(None);
248 };
249 self.integers_filter_by(key.section_name, key.subsection_name, key.value_name, filter)
250 }
251
252 pub fn integers_filter_by(
255 &self,
256 section_name: impl AsRef<str>,
257 subsection_name: impl AsBStrOpt,
258 value_name: impl AsRef<str>,
259 filter: impl FnMut(&Metadata) -> bool,
260 ) -> Result<Option<Vec<i64>>, value::Error> {
261 let Some(values) = self
262 .raw_values_filter_by(section_name, subsection_name, value_name, filter)
263 .ok()
264 else {
265 return Ok(None);
266 };
267 values
268 .into_iter()
269 .map(|v| {
270 crate::Integer::try_from(BStr::new(&v))
271 .and_then(|int| int.to_decimal().ok_or_else(|| value::Error::new("Integer overflow", v)))
272 })
273 .collect::<Result<Vec<_>, _>>()
274 .map(Some)
275 }
276}