1use bstr::{BStr, BString};
2use gix_error::ExnMessageResult;
3use gix_error::{ErrorExt, validation};
4
5use crate::{AsBStrOpt, AsKey, File, file::Metadata};
6
7impl File {
9 pub fn string(&self, key: impl AsKey) -> Option<BString> {
11 self.string_filter(key, |_| true)
12 }
13
14 pub fn string_by(
18 &self,
19 section_name: impl AsRef<str>,
20 subsection_name: impl AsBStrOpt,
21 value_name: impl AsRef<str>,
22 ) -> Option<BString> {
23 self.string_filter_by(section_name, subsection_name, value_name, |_| true)
24 }
25
26 pub fn string_filter(&self, key: impl AsKey, filter: impl FnMut(&Metadata) -> bool) -> Option<BString> {
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: impl AsBStrOpt,
38 value_name: impl AsRef<str>,
39 filter: impl FnMut(&Metadata) -> bool,
40 ) -> Option<BString> {
41 self.raw_value_filter_by(section_name, subsection_name, value_name, 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: impl AsBStrOpt,
60 value_name: impl AsRef<str>,
61 ) -> Option<crate::Path> {
62 self.path_filter_by(section_name, subsection_name, value_name, |_| 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: impl AsBStrOpt,
81 value_name: impl AsRef<str>,
82 filter: impl FnMut(&Metadata) -> bool,
83 ) -> Option<crate::Path> {
84 self.raw_value_filter_by(section_name, subsection_name, value_name, filter)
85 .ok()
86 .map(crate::Path::from)
87 }
88
89 pub fn boolean(&self, key: impl AsKey) -> ExnMessageResult<Option<bool>> {
91 self.boolean_filter(key, |_| true)
92 }
93
94 pub fn boolean_by(
96 &self,
97 section_name: impl AsRef<str>,
98 subsection_name: impl AsBStrOpt,
99 value_name: impl AsRef<str>,
100 ) -> ExnMessageResult<Option<bool>> {
101 self.boolean_filter_by(section_name, subsection_name, value_name, |_| true)
102 }
103
104 pub fn boolean_filter(
106 &self,
107 key: impl AsKey,
108 filter: impl FnMut(&Metadata) -> bool,
109 ) -> ExnMessageResult<Option<bool>> {
110 let Some(key) = key.try_as_key() else {
111 return Ok(None);
112 };
113 self.boolean_filter_by(key.section_name, key.subsection_name, key.value_name, filter)
114 }
115
116 pub fn boolean_filter_by(
118 &self,
119 section_name: impl AsRef<str>,
120 subsection_name: impl AsBStrOpt,
121 value_name: impl AsRef<str>,
122 mut filter: impl FnMut(&Metadata) -> bool,
123 ) -> ExnMessageResult<Option<bool>> {
124 let section_name = section_name.as_ref();
125 let section_ids = self
126 .section_ids_by_name_and_subname(section_name, subsection_name.as_bstr_opt())
127 .ok();
128 let Some(section_ids) = section_ids else {
129 return Ok(None);
130 };
131 let key = value_name.as_ref();
132 for section_id in section_ids.rev() {
133 let section = self.sections.get(§ion_id).expect("known section id");
134 if !filter(section.meta()) {
135 continue;
136 }
137 match section.body.value_implicit_in(&self.backing, key) {
138 Some(Some(v)) => return crate::Boolean::try_from(v).map(|value| Some(value.into())),
139 Some(None) => return Ok(Some(true)),
140 None => continue,
141 }
142 }
143 Ok(None)
144 }
145
146 pub fn integer(&self, key: impl AsKey) -> ExnMessageResult<Option<i64>> {
148 self.integer_filter(key, |_| true)
149 }
150
151 pub fn integer_by(
153 &self,
154 section_name: impl AsRef<str>,
155 subsection_name: impl AsBStrOpt,
156 value_name: impl AsRef<str>,
157 ) -> ExnMessageResult<Option<i64>> {
158 self.integer_filter_by(section_name, subsection_name, value_name, |_| true)
159 }
160
161 pub fn integer_filter(
163 &self,
164 key: impl AsKey,
165 filter: impl FnMut(&Metadata) -> bool,
166 ) -> ExnMessageResult<Option<i64>> {
167 let Some(key) = key.try_as_key() else {
168 return Ok(None);
169 };
170 self.integer_filter_by(key.section_name, key.subsection_name, key.value_name, filter)
171 }
172
173 pub fn integer_filter_by(
176 &self,
177 section_name: impl AsRef<str>,
178 subsection_name: impl AsBStrOpt,
179 value_name: impl AsRef<str>,
180 filter: impl FnMut(&Metadata) -> bool,
181 ) -> ExnMessageResult<Option<i64>> {
182 let Some(int) = self
183 .raw_value_filter_by(section_name, subsection_name, value_name, filter)
184 .ok()
185 else {
186 return Ok(None);
187 };
188 crate::Integer::try_from(BStr::new(&int))
189 .and_then(|b| {
190 b.to_decimal()
191 .ok_or_else(|| validation("Integer overflow").with("input", BStr::new(&int)).raise())
192 })
193 .map(Some)
194 }
195
196 pub fn strings(&self, key: impl AsKey) -> Option<Vec<BString>> {
198 let key = key.try_as_key()?;
199 self.strings_by(key.section_name, key.subsection_name, key.value_name)
200 }
201
202 pub fn strings_by(
204 &self,
205 section_name: impl AsRef<str>,
206 subsection_name: impl AsBStrOpt,
207 value_name: impl AsRef<str>,
208 ) -> Option<Vec<BString>> {
209 self.raw_values_by(section_name, subsection_name, value_name).ok()
210 }
211
212 pub fn strings_filter(&self, key: impl AsKey, filter: impl FnMut(&Metadata) -> bool) -> Option<Vec<BString>> {
214 let key = key.try_as_key()?;
215 self.strings_filter_by(key.section_name, key.subsection_name, key.value_name, filter)
216 }
217
218 pub fn strings_filter_by(
220 &self,
221 section_name: impl AsRef<str>,
222 subsection_name: impl AsBStrOpt,
223 value_name: impl AsRef<str>,
224 filter: impl FnMut(&Metadata) -> bool,
225 ) -> Option<Vec<BString>> {
226 self.raw_values_filter_by(section_name, subsection_name, value_name, filter)
227 .ok()
228 }
229
230 pub fn integers(&self, key: impl AsKey) -> ExnMessageResult<Option<Vec<i64>>> {
232 self.integers_filter(key, |_| true)
233 }
234
235 pub fn integers_by(
238 &self,
239 section_name: impl AsRef<str>,
240 subsection_name: impl AsBStrOpt,
241 value_name: impl AsRef<str>,
242 ) -> ExnMessageResult<Option<Vec<i64>>> {
243 self.integers_filter_by(section_name, subsection_name, value_name, |_| true)
244 }
245
246 pub fn integers_filter(
248 &self,
249 key: impl AsKey,
250 filter: impl FnMut(&Metadata) -> bool,
251 ) -> ExnMessageResult<Option<Vec<i64>>> {
252 let Some(key) = key.try_as_key() else {
253 return Ok(None);
254 };
255 self.integers_filter_by(key.section_name, key.subsection_name, key.value_name, filter)
256 }
257
258 pub fn integers_filter_by(
262 &self,
263 section_name: impl AsRef<str>,
264 subsection_name: impl AsBStrOpt,
265 value_name: impl AsRef<str>,
266 filter: impl FnMut(&Metadata) -> bool,
267 ) -> ExnMessageResult<Option<Vec<i64>>> {
268 let Some(values) = self
269 .raw_values_filter_by(section_name, subsection_name, value_name, filter)
270 .ok()
271 else {
272 return Ok(None);
273 };
274 values
275 .into_iter()
276 .map(|v| {
277 crate::Integer::try_from(BStr::new(&v)).and_then(|int| {
278 int.to_decimal()
279 .ok_or_else(|| validation("Integer overflow").with("input", BStr::new(&v)).raise())
280 })
281 })
282 .collect::<Result<Vec<_>, _>>()
283 .map(Some)
284 }
285}