1use std::borrow::Cow;
2
3use bstr::BStr;
4
5use crate::file::Metadata;
6use crate::{value, AsKey, File};
7
8impl File<'_> {
10 pub fn string(&self, key: impl AsKey) -> Option<Cow<'_, BStr>> {
12 self.string_filter(key, |_| true)
13 }
14
15 pub fn string_by(
19 &self,
20 section_name: impl AsRef<str>,
21 subsection_name: Option<&BStr>,
22 value_name: impl AsRef<str>,
23 ) -> Option<Cow<'_, BStr>> {
24 self.string_filter_by(section_name.as_ref(), subsection_name, value_name.as_ref(), |_| true)
25 }
26
27 pub fn string_filter(&self, key: impl AsKey, filter: impl FnMut(&Metadata) -> bool) -> Option<Cow<'_, BStr>> {
29 let key = key.try_as_key()?;
30 self.raw_value_filter_by(key.section_name, key.subsection_name, key.value_name, filter)
31 .ok()
32 }
33
34 pub fn string_filter_by(
36 &self,
37 section_name: impl AsRef<str>,
38 subsection_name: Option<&BStr>,
39 value_name: impl AsRef<str>,
40 filter: impl FnMut(&Metadata) -> bool,
41 ) -> Option<Cow<'_, BStr>> {
42 self.raw_value_filter_by(section_name.as_ref(), subsection_name, value_name.as_ref(), filter)
43 .ok()
44 }
45
46 pub fn path(&self, key: impl AsKey) -> Option<crate::Path<'_>> {
48 self.path_filter(key, |_| true)
49 }
50
51 pub fn path_by(
58 &self,
59 section_name: impl AsRef<str>,
60 subsection_name: Option<&BStr>,
61 value_name: impl AsRef<str>,
62 ) -> Option<crate::Path<'_>> {
63 self.path_filter_by(section_name.as_ref(), subsection_name, value_name.as_ref(), |_| true)
64 }
65
66 pub fn path_filter(&self, key: impl AsKey, filter: impl FnMut(&Metadata) -> bool) -> Option<crate::Path<'_>> {
68 let key = key.try_as_key()?;
69 self.path_filter_by(key.section_name, key.subsection_name, key.value_name, filter)
70 }
71
72 pub fn path_filter_by(
79 &self,
80 section_name: impl AsRef<str>,
81 subsection_name: Option<&BStr>,
82 value_name: impl AsRef<str>,
83 filter: impl FnMut(&Metadata) -> bool,
84 ) -> Option<crate::Path<'_>> {
85 self.raw_value_filter_by(section_name.as_ref(), subsection_name, value_name.as_ref(), filter)
86 .ok()
87 .map(crate::Path::from)
88 }
89
90 pub fn boolean(&self, key: impl AsKey) -> Option<Result<bool, value::Error>> {
92 self.boolean_filter(key, |_| true)
93 }
94
95 pub fn boolean_by(
97 &self,
98 section_name: impl AsRef<str>,
99 subsection_name: Option<&BStr>,
100 value_name: impl AsRef<str>,
101 ) -> Option<Result<bool, value::Error>> {
102 self.boolean_filter_by(section_name.as_ref(), subsection_name, value_name.as_ref(), |_| true)
103 }
104
105 pub fn boolean_filter(
107 &self,
108 key: impl AsKey,
109 filter: impl FnMut(&Metadata) -> bool,
110 ) -> Option<Result<bool, value::Error>> {
111 let key = key.try_as_key()?;
112 self.boolean_filter_by(key.section_name, key.subsection_name, key.value_name, filter)
113 }
114
115 pub fn boolean_filter_by(
117 &self,
118 section_name: impl AsRef<str>,
119 subsection_name: Option<&BStr>,
120 value_name: impl AsRef<str>,
121 mut filter: impl FnMut(&Metadata) -> bool,
122 ) -> Option<Result<bool, value::Error>> {
123 let section_name = section_name.as_ref();
124 let section_ids = self
125 .section_ids_by_name_and_subname(section_name, subsection_name)
126 .ok()?;
127 let key = value_name.as_ref();
128 for section_id in section_ids.rev() {
129 let section = self.sections.get(§ion_id).expect("known section id");
130 if !filter(section.meta()) {
131 continue;
132 }
133 match section.value_implicit(key) {
134 Some(Some(v)) => return Some(crate::Boolean::try_from(v).map(Into::into)),
135 Some(None) => return Some(Ok(true)),
136 None => continue,
137 }
138 }
139 None
140 }
141
142 pub fn integer(&self, key: impl AsKey) -> Option<Result<i64, value::Error>> {
144 self.integer_filter(key, |_| true)
145 }
146
147 pub fn integer_by(
149 &self,
150 section_name: impl AsRef<str>,
151 subsection_name: Option<&BStr>,
152 value_name: impl AsRef<str>,
153 ) -> Option<Result<i64, value::Error>> {
154 self.integer_filter_by(section_name, subsection_name, value_name, |_| true)
155 }
156
157 pub fn integer_filter(
159 &self,
160 key: impl AsKey,
161 filter: impl FnMut(&Metadata) -> bool,
162 ) -> Option<Result<i64, value::Error>> {
163 let key = key.try_as_key()?;
164 self.integer_filter_by(key.section_name, key.subsection_name, key.value_name, filter)
165 }
166
167 pub fn integer_filter_by(
169 &self,
170 section_name: impl AsRef<str>,
171 subsection_name: Option<&BStr>,
172 value_name: impl AsRef<str>,
173 filter: impl FnMut(&Metadata) -> bool,
174 ) -> Option<Result<i64, value::Error>> {
175 let int = self
176 .raw_value_filter_by(section_name.as_ref(), subsection_name, value_name.as_ref(), filter)
177 .ok()?;
178 Some(crate::Integer::try_from(int.as_ref()).and_then(|b| {
179 b.to_decimal()
180 .ok_or_else(|| value::Error::new("Integer overflow", int.into_owned()))
181 }))
182 }
183
184 pub fn strings(&self, key: impl AsKey) -> Option<Vec<Cow<'_, BStr>>> {
186 let key = key.try_as_key()?;
187 self.strings_by(key.section_name, key.subsection_name, key.value_name)
188 }
189
190 pub fn strings_by(
192 &self,
193 section_name: impl AsRef<str>,
194 subsection_name: Option<&BStr>,
195 value_name: impl AsRef<str>,
196 ) -> Option<Vec<Cow<'_, BStr>>> {
197 self.raw_values_by(section_name.as_ref(), subsection_name, value_name.as_ref())
198 .ok()
199 }
200
201 pub fn strings_filter(&self, key: impl AsKey, filter: impl FnMut(&Metadata) -> bool) -> Option<Vec<Cow<'_, BStr>>> {
203 let key = key.try_as_key()?;
204 self.strings_filter_by(key.section_name, key.subsection_name, key.value_name, filter)
205 }
206
207 pub fn strings_filter_by(
209 &self,
210 section_name: impl AsRef<str>,
211 subsection_name: Option<&BStr>,
212 value_name: impl AsRef<str>,
213 filter: impl FnMut(&Metadata) -> bool,
214 ) -> Option<Vec<Cow<'_, BStr>>> {
215 self.raw_values_filter_by(section_name.as_ref(), subsection_name, value_name.as_ref(), filter)
216 .ok()
217 }
218
219 pub fn integers(&self, key: impl AsKey) -> Option<Result<Vec<i64>, value::Error>> {
221 self.integers_filter(key, |_| true)
222 }
223
224 pub fn integers_by(
227 &self,
228 section_name: impl AsRef<str>,
229 subsection_name: Option<&BStr>,
230 value_name: impl AsRef<str>,
231 ) -> Option<Result<Vec<i64>, value::Error>> {
232 self.integers_filter_by(section_name.as_ref(), subsection_name, value_name.as_ref(), |_| true)
233 }
234
235 pub fn integers_filter(
237 &self,
238 key: impl AsKey,
239 filter: impl FnMut(&Metadata) -> bool,
240 ) -> Option<Result<Vec<i64>, value::Error>> {
241 let key = key.try_as_key()?;
242 self.integers_filter_by(key.section_name, key.subsection_name, key.value_name, filter)
243 }
244
245 pub fn integers_filter_by(
248 &self,
249 section_name: impl AsRef<str>,
250 subsection_name: Option<&BStr>,
251 value_name: impl AsRef<str>,
252 filter: impl FnMut(&Metadata) -> bool,
253 ) -> Option<Result<Vec<i64>, value::Error>> {
254 self.raw_values_filter_by(section_name.as_ref(), subsection_name, value_name.as_ref(), filter)
255 .ok()
256 .map(|values| {
257 values
258 .into_iter()
259 .map(|v| {
260 crate::Integer::try_from(v.as_ref()).and_then(|int| {
261 int.to_decimal()
262 .ok_or_else(|| value::Error::new("Integer overflow", v.into_owned()))
263 })
264 })
265 .collect()
266 })
267 }
268}