| use std::borrow::Cow; |
| |
| use bstr::BStr; |
| |
| use crate::{file::MetadataFilter, value, File}; |
| |
| /// Comfortable API for accessing values |
| impl<'event> File<'event> { |
| /// Like [`value()`][File::value()], but returning `None` if the string wasn't found. |
| /// |
| /// As strings perform no conversions, this will never fail. |
| pub fn string( |
| &self, |
| section_name: impl AsRef<str>, |
| subsection_name: Option<&BStr>, |
| key: impl AsRef<str>, |
| ) -> Option<Cow<'_, BStr>> { |
| self.string_filter(section_name, subsection_name, key, &mut |_| true) |
| } |
| |
| /// Like [`string()`][File::string()], but suitable for statically known `key`s like `remote.origin.url`. |
| pub fn string_by_key<'a>(&self, key: impl Into<&'a BStr>) -> Option<Cow<'_, BStr>> { |
| self.string_filter_by_key(key, &mut |_| true) |
| } |
| |
| /// Like [`string()`][File::string()], but the section containing the returned value must pass `filter` as well. |
| pub fn string_filter( |
| &self, |
| section_name: impl AsRef<str>, |
| subsection_name: Option<&BStr>, |
| key: impl AsRef<str>, |
| filter: &mut MetadataFilter, |
| ) -> Option<Cow<'_, BStr>> { |
| self.raw_value_filter(section_name.as_ref(), subsection_name, key.as_ref(), filter) |
| .ok() |
| } |
| |
| /// Like [`string_filter()`][File::string_filter()], but suitable for statically known `key`s like `remote.origin.url`. |
| pub fn string_filter_by_key<'a>( |
| &self, |
| key: impl Into<&'a BStr>, |
| filter: &mut MetadataFilter, |
| ) -> Option<Cow<'_, BStr>> { |
| let key = crate::parse::key(key.into())?; |
| self.raw_value_filter(key.section_name, key.subsection_name, key.value_name, filter) |
| .ok() |
| } |
| |
| /// Like [`value()`][File::value()], but returning `None` if the path wasn't found. |
| /// |
| /// Note that this path is not vetted and should only point to resources which can't be used |
| /// to pose a security risk. Prefer using [`path_filter()`][File::path_filter()] instead. |
| /// |
| /// As paths perform no conversions, this will never fail. |
| pub fn path( |
| &self, |
| section_name: impl AsRef<str>, |
| subsection_name: Option<&BStr>, |
| key: impl AsRef<str>, |
| ) -> Option<crate::Path<'_>> { |
| self.path_filter(section_name, subsection_name, key, &mut |_| true) |
| } |
| |
| /// Like [`path()`][File::path()], but suitable for statically known `key`s like `remote.origin.url`. |
| pub fn path_by_key<'a>(&self, key: impl Into<&'a BStr>) -> Option<crate::Path<'_>> { |
| self.path_filter_by_key(key, &mut |_| true) |
| } |
| |
| /// Like [`path()`][File::path()], but the section containing the returned value must pass `filter` as well. |
| /// |
| /// This should be the preferred way of accessing paths as those from untrusted |
| /// locations can be |
| /// |
| /// As paths perform no conversions, this will never fail. |
| pub fn path_filter( |
| &self, |
| section_name: impl AsRef<str>, |
| subsection_name: Option<&BStr>, |
| key: impl AsRef<str>, |
| filter: &mut MetadataFilter, |
| ) -> Option<crate::Path<'_>> { |
| self.raw_value_filter(section_name.as_ref(), subsection_name, key.as_ref(), filter) |
| .ok() |
| .map(crate::Path::from) |
| } |
| |
| /// Like [`path_filter()`][File::path_filter()], but suitable for statically known `key`s like `remote.origin.url`. |
| pub fn path_filter_by_key<'a>( |
| &self, |
| key: impl Into<&'a BStr>, |
| filter: &mut MetadataFilter, |
| ) -> Option<crate::Path<'_>> { |
| let key = crate::parse::key(key.into())?; |
| self.path_filter(key.section_name, key.subsection_name, key.value_name, filter) |
| } |
| |
| /// Like [`value()`][File::value()], but returning `None` if the boolean value wasn't found. |
| pub fn boolean( |
| &self, |
| section_name: impl AsRef<str>, |
| subsection_name: Option<&BStr>, |
| key: impl AsRef<str>, |
| ) -> Option<Result<bool, value::Error>> { |
| self.boolean_filter(section_name, subsection_name, key, &mut |_| true) |
| } |
| |
| /// Like [`boolean()`][File::boolean()], but suitable for statically known `key`s like `remote.origin.url`. |
| pub fn boolean_by_key<'a>(&self, key: impl Into<&'a BStr>) -> Option<Result<bool, value::Error>> { |
| self.boolean_filter_by_key(key, &mut |_| true) |
| } |
| |
| /// Like [`boolean()`][File::boolean()], but the section containing the returned value must pass `filter` as well. |
| pub fn boolean_filter( |
| &self, |
| section_name: impl AsRef<str>, |
| subsection_name: Option<&BStr>, |
| key: impl AsRef<str>, |
| filter: &mut MetadataFilter, |
| ) -> Option<Result<bool, value::Error>> { |
| let section_name = section_name.as_ref(); |
| let section_ids = self |
| .section_ids_by_name_and_subname(section_name, subsection_name) |
| .ok()?; |
| let key = key.as_ref(); |
| for section_id in section_ids.rev() { |
| let section = self.sections.get(§ion_id).expect("known section id"); |
| if !filter(section.meta()) { |
| continue; |
| } |
| match section.value_implicit(key) { |
| Some(Some(v)) => return Some(crate::Boolean::try_from(v).map(Into::into)), |
| Some(None) => return Some(Ok(true)), |
| None => continue, |
| } |
| } |
| None |
| } |
| |
| /// Like [`boolean_filter()`][File::boolean_filter()], but suitable for statically known `key`s like `remote.origin.url`. |
| pub fn boolean_filter_by_key<'a>( |
| &self, |
| key: impl Into<&'a BStr>, |
| filter: &mut MetadataFilter, |
| ) -> Option<Result<bool, value::Error>> { |
| let key = crate::parse::key(key.into())?; |
| self.boolean_filter(key.section_name, key.subsection_name, key.value_name, filter) |
| } |
| |
| /// Like [`value()`][File::value()], but returning an `Option` if the integer wasn't found. |
| pub fn integer( |
| &self, |
| section_name: impl AsRef<str>, |
| subsection_name: Option<&BStr>, |
| key: impl AsRef<str>, |
| ) -> Option<Result<i64, value::Error>> { |
| self.integer_filter(section_name, subsection_name, key, &mut |_| true) |
| } |
| |
| /// Like [`integer()`][File::integer()], but suitable for statically known `key`s like `remote.origin.url`. |
| pub fn integer_by_key<'a>(&self, key: impl Into<&'a BStr>) -> Option<Result<i64, value::Error>> { |
| self.integer_filter_by_key(key, &mut |_| true) |
| } |
| |
| /// Like [`integer()`][File::integer()], but the section containing the returned value must pass `filter` as well. |
| pub fn integer_filter( |
| &self, |
| section_name: impl AsRef<str>, |
| subsection_name: Option<&BStr>, |
| key: impl AsRef<str>, |
| filter: &mut MetadataFilter, |
| ) -> Option<Result<i64, value::Error>> { |
| let int = self |
| .raw_value_filter(section_name.as_ref(), subsection_name, key.as_ref(), filter) |
| .ok()?; |
| Some(crate::Integer::try_from(int.as_ref()).and_then(|b| { |
| b.to_decimal() |
| .ok_or_else(|| value::Error::new("Integer overflow", int.into_owned())) |
| })) |
| } |
| |
| /// Like [`integer_filter()`][File::integer_filter()], but suitable for statically known `key`s like `remote.origin.url`. |
| pub fn integer_filter_by_key<'a>( |
| &self, |
| key: impl Into<&'a BStr>, |
| filter: &mut MetadataFilter, |
| ) -> Option<Result<i64, value::Error>> { |
| let key = crate::parse::key(key.into())?; |
| self.integer_filter(key.section_name, key.subsection_name, key.value_name, filter) |
| } |
| |
| /// Similar to [`values(…)`][File::values()] but returning strings if at least one of them was found. |
| pub fn strings( |
| &self, |
| section_name: impl AsRef<str>, |
| subsection_name: Option<&BStr>, |
| key: impl AsRef<str>, |
| ) -> Option<Vec<Cow<'_, BStr>>> { |
| self.raw_values(section_name.as_ref(), subsection_name, key.as_ref()) |
| .ok() |
| } |
| |
| /// Like [`strings()`][File::strings()], but suitable for statically known `key`s like `remote.origin.url`. |
| pub fn strings_by_key<'a>(&self, key: impl Into<&'a BStr>) -> Option<Vec<Cow<'_, BStr>>> { |
| let key = crate::parse::key(key.into())?; |
| self.strings(key.section_name, key.subsection_name, key.value_name) |
| } |
| |
| /// Similar to [`strings(…)`][File::strings()], but all values are in sections that passed `filter`. |
| pub fn strings_filter( |
| &self, |
| section_name: impl AsRef<str>, |
| subsection_name: Option<&BStr>, |
| key: impl AsRef<str>, |
| filter: &mut MetadataFilter, |
| ) -> Option<Vec<Cow<'_, BStr>>> { |
| self.raw_values_filter(section_name.as_ref(), subsection_name, key.as_ref(), filter) |
| .ok() |
| } |
| |
| /// Like [`strings_filter()`][File::strings_filter()], but suitable for statically known `key`s like `remote.origin.url`. |
| pub fn strings_filter_by_key<'a>( |
| &self, |
| key: impl Into<&'a BStr>, |
| filter: &mut MetadataFilter, |
| ) -> Option<Vec<Cow<'_, BStr>>> { |
| let key = crate::parse::key(key.into())?; |
| self.strings_filter(key.section_name, key.subsection_name, key.value_name, filter) |
| } |
| |
| /// Similar to [`values(…)`][File::values()] but returning integers if at least one of them was found |
| /// and if none of them overflows. |
| pub fn integers( |
| &self, |
| section_name: impl AsRef<str>, |
| subsection_name: Option<&BStr>, |
| key: impl AsRef<str>, |
| ) -> Option<Result<Vec<i64>, value::Error>> { |
| self.integers_filter(section_name, subsection_name, key, &mut |_| true) |
| } |
| |
| /// Like [`integers()`][File::integers()], but suitable for statically known `key`s like `remote.origin.url`. |
| pub fn integers_by_key<'a>(&self, key: impl Into<&'a BStr>) -> Option<Result<Vec<i64>, value::Error>> { |
| self.integers_filter_by_key(key, &mut |_| true) |
| } |
| |
| /// Similar to [`integers(…)`][File::integers()] but all integers are in sections that passed `filter` |
| /// and that are not overflowing. |
| pub fn integers_filter( |
| &self, |
| section_name: impl AsRef<str>, |
| subsection_name: Option<&BStr>, |
| key: impl AsRef<str>, |
| filter: &mut MetadataFilter, |
| ) -> Option<Result<Vec<i64>, value::Error>> { |
| self.raw_values_filter(section_name.as_ref(), subsection_name, key.as_ref(), filter) |
| .ok() |
| .map(|values| { |
| values |
| .into_iter() |
| .map(|v| { |
| crate::Integer::try_from(v.as_ref()).and_then(|int| { |
| int.to_decimal() |
| .ok_or_else(|| value::Error::new("Integer overflow", v.into_owned())) |
| }) |
| }) |
| .collect() |
| }) |
| } |
| |
| /// Like [`integers_filter()`][File::integers_filter()], but suitable for statically known `key`s like `remote.origin.url`. |
| pub fn integers_filter_by_key<'a>( |
| &self, |
| key: impl Into<&'a BStr>, |
| filter: &mut MetadataFilter, |
| ) -> Option<Result<Vec<i64>, value::Error>> { |
| let key = crate::parse::key(key.into())?; |
| self.integers_filter(key.section_name, key.subsection_name, key.value_name, filter) |
| } |
| } |