diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:41:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:41:41 +0000 |
commit | 10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87 (patch) | |
tree | bdffd5d80c26cf4a7a518281a204be1ace85b4c1 /vendor/gix-config/src/parse/section/mod.rs | |
parent | Releasing progress-linux version 1.70.0+dfsg1-9~progress7.99u1. (diff) | |
download | rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.tar.xz rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.zip |
Merging upstream version 1.70.0+dfsg2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/gix-config/src/parse/section/mod.rs')
-rw-r--r-- | vendor/gix-config/src/parse/section/mod.rs | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/vendor/gix-config/src/parse/section/mod.rs b/vendor/gix-config/src/parse/section/mod.rs new file mode 100644 index 000000000..7ba08b87d --- /dev/null +++ b/vendor/gix-config/src/parse/section/mod.rs @@ -0,0 +1,187 @@ +use std::{borrow::Cow, fmt::Display}; + +use bstr::BStr; +use smallvec::SmallVec; + +use crate::parse::{Event, Section}; + +/// +pub mod header; + +pub(crate) mod unvalidated; + +/// A container for events, avoiding heap allocations in typical files. +pub type Events<'a> = SmallVec<[Event<'a>; 64]>; + +/// A parsed section header, containing a name and optionally a subsection name. +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] +pub struct Header<'a> { + /// The name of the header. + pub(crate) name: Name<'a>, + /// The separator used to determine if the section contains a subsection. + /// This is either a period `.` or a string of whitespace. Note that + /// reconstruction of subsection format is dependent on this value. If this + /// is all whitespace, then the subsection name needs to be surrounded by + /// quotes to have perfect reconstruction. + pub(crate) separator: Option<Cow<'a, BStr>>, + pub(crate) subsection_name: Option<Cow<'a, BStr>>, +} + +impl Section<'_> { + /// Turn this instance into a fully owned one with `'static` lifetime. + #[must_use] + pub fn to_owned(&self) -> Section<'static> { + Section { + header: self.header.to_owned(), + events: self.events.iter().map(Event::to_owned).collect(), + } + } +} + +impl Display for Section<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.header)?; + for event in &self.events { + event.fmt(f)?; + } + Ok(()) + } +} + +mod types { + macro_rules! generate_case_insensitive { + ($name:ident, $module:ident, $err_doc:literal, $validate:ident, $cow_inner_type:ty, $comment:literal) => { + /// + pub mod $module { + /// The error returned when `TryFrom` is invoked to create an instance. + #[derive(Debug, thiserror::Error, Copy, Clone)] + #[error($err_doc)] + pub struct Error; + } + + #[doc = $comment] + #[derive(Clone, Eq, Debug, Default)] + pub struct $name<'a>(pub(crate) std::borrow::Cow<'a, $cow_inner_type>); + + impl<'a> $name<'a> { + pub(crate) fn from_str_unchecked(s: &'a str) -> Self { + $name(std::borrow::Cow::Borrowed(s.into())) + } + /// Turn this instance into a fully owned one with `'static` lifetime. + #[must_use] + pub fn to_owned(&self) -> $name<'static> { + $name(std::borrow::Cow::Owned(self.0.clone().into_owned())) + } + } + + impl PartialEq for $name<'_> { + fn eq(&self, other: &Self) -> bool { + self.0.eq_ignore_ascii_case(&other.0) + } + } + + impl std::fmt::Display for $name<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } + } + + impl PartialOrd for $name<'_> { + fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { + self.cmp(other).into() + } + } + + impl Ord for $name<'_> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let a = self.0.iter().map(|c| c.to_ascii_lowercase()); + let b = other.0.iter().map(|c| c.to_ascii_lowercase()); + a.cmp(b) + } + } + + impl std::hash::Hash for $name<'_> { + fn hash<H: std::hash::Hasher>(&self, state: &mut H) { + for b in self.0.iter() { + b.to_ascii_lowercase().hash(state); + } + } + } + + impl<'a> std::convert::TryFrom<&'a str> for $name<'a> { + type Error = $module::Error; + + fn try_from(s: &'a str) -> Result<Self, Self::Error> { + Self::try_from(std::borrow::Cow::Borrowed(bstr::ByteSlice::as_bstr(s.as_bytes()))) + } + } + + impl<'a> std::convert::TryFrom<String> for $name<'a> { + type Error = $module::Error; + + fn try_from(s: String) -> Result<Self, Self::Error> { + Self::try_from(std::borrow::Cow::Owned(bstr::BString::from(s))) + } + } + + impl<'a> std::convert::TryFrom<std::borrow::Cow<'a, bstr::BStr>> for $name<'a> { + type Error = $module::Error; + + fn try_from(s: std::borrow::Cow<'a, bstr::BStr>) -> Result<Self, Self::Error> { + if $validate(s.as_ref()) { + Ok(Self(s)) + } else { + Err($module::Error) + } + } + } + + impl<'a> std::ops::Deref for $name<'a> { + type Target = $cow_inner_type; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl<'a> std::convert::AsRef<str> for $name<'a> { + fn as_ref(&self) -> &str { + std::str::from_utf8(self.0.as_ref()).expect("only valid UTF8 makes it through our validation") + } + } + }; + } + + fn is_valid_name(n: &bstr::BStr) -> bool { + !n.is_empty() && n.iter().all(|b| b.is_ascii_alphanumeric() || *b == b'-') + } + fn is_valid_key(n: &bstr::BStr) -> bool { + is_valid_name(n) && n[0].is_ascii_alphabetic() + } + + generate_case_insensitive!( + Name, + name, + "Valid names consist of alphanumeric characters or dashes.", + is_valid_name, + bstr::BStr, + "Wrapper struct for section header names, like `remote`, since these are case-insensitive." + ); + + generate_case_insensitive!( + Key, + key, + "Valid keys consist alphanumeric characters or dashes, starting with an alphabetic character.", + is_valid_key, + bstr::BStr, + "Wrapper struct for key names, like `path` in `include.path`, since keys are case-insensitive." + ); +} +pub use types::{key, name, Key, Name}; + +pub(crate) fn into_cow_bstr(c: Cow<'_, str>) -> Cow<'_, BStr> { + match c { + Cow::Borrowed(s) => Cow::Borrowed(s.into()), + Cow::Owned(s) => Cow::Owned(s.into()), + } +} |