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