//! This module handles parsing a `git-config` file. Generally speaking, you//! want to use a higher abstraction such as [`GitConfig`] unless you have some//! explicit reason to work with events instead.//!//! The general workflow for interacting with this is to use one of the//! `parse_from_*` function variants. These will return a [`Parser`] on success,//! which can be converted into an [`Event`] iterator. The [`Parser`] also has//! additional methods for accessing leading comments or events by section.//!//! [`GitConfig`]: crate::file::GitConfig use std::{borrow::Cow, convert::TryFrom, fmt::Display, hash::Hash, io::Read, iter::FusedIterator, path::Path}; use nom::{ branch::alt, bytes::complete::{escaped, tag, take_till, take_while}, character::{ complete::{char, none_of, one_of}, is_space, }, combinator::{map, opt}, error::{Error as NomError, ErrorKind}, multi::{many0, many1}, sequence::delimited, IResult,}; /// Syntactic events that occurs in the config. Despite all these variants/// holding a [`Cow`] instead over a simple reference, the parser will only emit/// borrowed `Cow` variants.////// The `Cow` smart pointer is used here for ease of inserting events in a/// middle of an Event iterator. This is used, for example, in the [`GitConfig`]/// struct when adding values.////// [`Cow`]: std::borrow::Cow/// [`GitConfig`]: crate::file::GitConfig#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]pub enum Event<'a> { /// A comment with a comment tag and the comment itself. Note that the /// comment itself may contain additional whitespace and comment markers /// at the beginning. Comment(ParsedComment<'a>), /// A section header containing the section name and a subsection, if it /// exists. SectionHeader(ParsedSectionHeader<'a>), /// A name to a value in a section. Key(Key<'a>), /// A completed value. This may be any string, including the empty string, /// if an implicit boolean value is used. Note that these values may contain /// spaces and any special character. This value is also unprocessed, so it /// it may contain double quotes that should be replaced. Value(Cow<'a, [u8]>), /// Represents any token used to signify a new line character. On Unix /// platforms, this is typically just `\n`, but can be any valid newline /// sequence. Multiple newlines (such as `\n\n`) will be merged as a single /// newline event. Newline(Cow<'a, str>), /// Any value that isn't completed. This occurs when the value is continued /// onto the next line. A Newline event is guaranteed after, followed by /// either a ValueDone, a Whitespace, or another ValueNotDone. ValueNotDone(Cow<'a, [u8]>), /// The last line of a value which was continued onto another line. ValueDone(Cow<'a, [u8]>), /// A continuous section of insignificant whitespace. Values with internal /// spaces will not be separated by this event. Whitespace(Cow<'a, str>), /// This event is emitted when the parser counters a valid `=` character /// separating the key and value. This event is necessary as it eliminates /// the ambiguity for whitespace events between a key and value event. KeyValueSeparator,} impl Event<'_> { /// Generates a byte representation of the value. This should be used when /// non-UTF-8 sequences are present or a UTF-8 representation can't be /// guaranteed. #[inline] #[must_use] pub fn to_vec(&self) -> Vec<u8> { self.into() } /// Coerces into an owned instance. This differs from the standard [`clone`] /// implementation as calling clone will _not_ copy the borrowed variant, /// while this method will. In other words: /// /// | Borrow type | `.clone()` | `to_owned()` | /// | ----------- | ---------- | ------------ | /// | Borrowed | Borrowed | Owned | /// | Owned | Owned | Owned | /// /// This can be most effectively seen by the differing lifetimes between the /// two. This method guarantees a `'static` lifetime, while `clone` does /// not. /// /// [`clone`]: Self::clone #[inline] #[must_use] pub fn to_owned(&self) -> Event<'static> { match self { Event::Comment(e) => Event::Comment(e.to_owned()), Event::SectionHeader(e) => Event::SectionHeader(e.to_owned()), Event::Key(e) => Event::Key(e.to_owned()), Event::Value(e) => Event::Value(Cow::Owned(e.clone().into_owned())), Event::ValueNotDone(e) => Event::ValueNotDone(Cow::Owned(e.clone().into_owned())), Event::ValueDone(e) => Event::ValueDone(Cow::Owned(e.clone().into_owned())), Event::Newline(e) => Event::Newline(Cow::Owned(e.clone().into_owned())), Event::Whitespace(e) => Event::Whitespace(Cow::Owned(e.clone().into_owned())), Event::KeyValueSeparator => Event::KeyValueSeparator, } }} impl Display for Event<'_> { /// Note that this is a best-effort attempt at printing an `Event`. If /// there are non UTF-8 values in your config, this will _NOT_ render /// as read. #[inline] fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Value(e) | Self::ValueNotDone(e) | Self::ValueDone(e) => match std::str::from_utf8(e) { Ok(e) => e.fmt(f), Err(_) => write!(f, "{:02x?}", e), }, Self::Comment(e) => e.fmt(f), Self::SectionHeader(e) => e.fmt(f), Self::Key(e) => e.fmt(f), Self::Newline(e) | Self::Whitespace(e) => e.fmt(f), Self::KeyValueSeparator => write!(f, "="), } }} impl From<Event<'_>> for Vec<u8> { #[inline] fn from(event: Event) -> Self { event.into() }} impl From<&Event<'_>> for Vec<u8> { #[inline] fn from(event: &Event) -> Self { match event { Event::Value(e) | Event::ValueNotDone(e) | Event::ValueDone(e) => e.to_vec(), Event::Comment(e) => e.into(), Event::SectionHeader(e) => e.into(), Event::Key(e) => e.0.as_bytes().to_vec(), Event::Newline(e) | Event::Whitespace(e) => e.as_bytes().to_vec(), Event::KeyValueSeparator => vec![b'='], } }} /// A parsed section containing the header and the section events.#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]pub struct ParsedSection<'a> { /// The section name and subsection name, if any. pub section_header: ParsedSectionHeader<'a>, /// The syntactic events found in this section. pub events: Vec<Event<'a>>,} impl ParsedSection<'_> { /// Coerces into an owned instance. This differs from the standard [`clone`] /// implementation as calling clone will _not_ copy the borrowed variant, /// while this method will. In other words: /// /// | Borrow type | `.clone()` | `to_owned()` | /// | ----------- | ---------- | ------------ | /// | Borrowed | Borrowed | Owned | /// | Owned | Owned | Owned | /// /// This can be most effectively seen by the differing lifetimes between the /// two. This method guarantees a `'static` lifetime, while `clone` does /// not. /// /// [`clone`]: Self::clone #[inline] #[must_use] pub fn to_owned(&self) -> ParsedSection<'static> { ParsedSection { section_header: self.section_header.to_owned(), events: self.events.iter().map(Event::to_owned).collect(), } }} impl Display for ParsedSection<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.section_header)?; for event in &self.events { event.fmt(f)?; } Ok(()) }} macro_rules! generate_case_insensitive { ($name:ident, $cow_inner_type:ty, $comment:literal) => { #[doc = $comment] #[derive(Clone, Eq, Ord, Debug, Default)] pub struct $name<'a>(pub Cow<'a, $cow_inner_type>); impl $name<'_> { /// Coerces into an owned instance. This differs from the standard /// [`clone`] implementation as calling clone will _not_ copy the /// borrowed variant, while this method will. In other words: /// /// | Borrow type | `.clone()` | `to_owned()` | /// | ----------- | ---------- | ------------ | /// | Borrowed | Borrowed | Owned | /// | Owned | Owned | Owned | /// /// This can be most effectively seen by the differing lifetimes /// between the two. This method guarantees a `'static` lifetime, /// while `clone` does not. /// /// [`clone`]: Self::clone #[inline] #[must_use] pub fn to_owned(&self) -> $name<'static> { $name(Cow::Owned(self.0.clone().into_owned())) } } impl PartialEq for $name<'_> { #[inline] fn eq(&self, other: &Self) -> bool { self.0.eq_ignore_ascii_case(&other.0) } } impl Display for $name<'_> { #[inline] fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.0.fmt(f) } } impl PartialOrd for $name<'_> { #[inline] fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { self.0 .to_ascii_lowercase() .partial_cmp(&other.0.to_ascii_lowercase()) } } impl std::hash::Hash for $name<'_> { #[inline] fn hash<H: std::hash::Hasher>(&self, state: &mut H) { self.0.to_ascii_lowercase().hash(state) } } impl<'a> From<&'a str> for $name<'a> { #[inline] fn from(s: &'a str) -> Self { Self(Cow::Borrowed(s)) } } impl<'a> From<Cow<'a, str>> for $name<'a> { #[inline] fn from(s: Cow<'a, str>) -> Self { Self(s) } } impl<'a> std::ops::Deref for $name<'a> { type Target = $cow_inner_type; #[inline] fn deref(&self) -> &Self::Target { &self.0 } } };} generate_case_insensitive!( SectionHeaderName, str, "Wrapper struct for section header names, since section headers are case-insensitive."); generate_case_insensitive!( Key, str, "Wrapper struct for key names, since keys are case-insensitive."); /// A parsed section header, containing a name and optionally a subsection name.////// Note that section headers must be parsed as valid ASCII, and thus all valid/// instances must also necessarily be valid UTF-8, which is why we use a/// [`str`] instead of [`[u8]`].#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]pub struct ParsedSectionHeader<'a> { /// The name of the header. pub name: SectionHeaderName<'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 separator: Option<Cow<'a, str>>, /// The subsection name without quotes if any exist. pub subsection_name: Option<Cow<'a, str>>,} impl ParsedSectionHeader<'_> { /// Generates a byte representation of the value. This should be used when /// non-UTF-8 sequences are present or a UTF-8 representation can't be /// guaranteed. #[must_use] #[inline] pub fn to_vec(&self) -> Vec<u8> { self.into() } /// Coerces into an owned instance. This differs from the standard [`clone`] /// implementation as calling clone will _not_ copy the borrowed variant, /// while this method will. In other words: /// /// | Borrow type | `.clone()` | `to_owned()` | /// | ----------- | ---------- | ------------ | /// | Borrowed | Borrowed | Owned | /// | Owned | Owned | Owned | /// /// This can be most effectively seen by the differing lifetimes between the /// two. This method guarantees a `'static` lifetime, while `clone` does /// not. /// /// [`clone`]: Self::clone #[inline] #[must_use] pub fn to_owned(&self) -> ParsedSectionHeader<'static> { ParsedSectionHeader { name: self.name.to_owned(), separator: self.separator.clone().map(|v| Cow::Owned(v.into_owned())), subsection_name: self.subsection_name.clone().map(|v| Cow::Owned(v.into_owned())), } }} impl Display for ParsedSectionHeader<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "[{}", self.name)?; if let Some(v) = &self.separator { // Separator must be utf-8 v.fmt(f)?; let subsection_name = self.subsection_name.as_ref().unwrap(); if v == "." { subsection_name.fmt(f)?; } else { write!(f, "\"{}\"", subsection_name)?; } } write!(f, "]") }} impl From<ParsedSectionHeader<'_>> for Vec<u8> { #[inline] fn from(header: ParsedSectionHeader) -> Self { header.into() }} impl From<&ParsedSectionHeader<'_>> for Vec<u8> { #[inline] fn from(header: &ParsedSectionHeader) -> Self { header.to_string().into_bytes() }} impl<'a> From<ParsedSectionHeader<'a>> for Event<'a> { #[inline] fn from(header: ParsedSectionHeader) -> Event { Event::SectionHeader(header) }} /// A parsed comment event containing the comment marker and comment.#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]pub struct ParsedComment<'a> { /// The comment marker used. This is either a semicolon or octothorpe. pub comment_tag: char, /// The parsed comment. pub comment: Cow<'a, [u8]>,} impl ParsedComment<'_> { /// Coerces into an owned instance. This differs from the standard [`clone`] /// implementation as calling clone will _not_ copy the borrowed variant, /// while this method will. In other words: /// /// | Borrow type | `.clone()` | `to_owned()` | /// | ----------- | ---------- | ------------ | /// | Borrowed | Borrowed | Owned | /// | Owned | Owned | Owned | /// /// This can be most effectively seen by the differing lifetimes between the /// two. This method guarantees a `'static` lifetime, while `clone` does /// not. /// /// [`clone`]: Self::clone #[inline] #[must_use] pub fn to_owned(&self) -> ParsedComment<'static> { ParsedComment { comment_tag: self.comment_tag, comment: Cow::Owned(self.comment.to_vec()), } }} impl Display for ParsedComment<'_> { /// Note that this is a best-effort attempt at printing an comment. If /// there are non UTF-8 values in your config, this will _NOT_ render /// as read. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.comment_tag.fmt(f)?; if let Ok(s) = std::str::from_utf8(&self.comment) { s.fmt(f) } else { write!(f, "{:02x?}", self.comment) } }} impl From<ParsedComment<'_>> for Vec<u8> { #[inline] fn from(c: ParsedComment) -> Self { c.into() }} impl From<&ParsedComment<'_>> for Vec<u8> { #[inline] fn from(c: &ParsedComment) -> Self { let mut values = vec![c.comment_tag as u8]; values.extend(c.comment.iter()); values }} /// A parser error reports the one-indexed line number where the parsing error/// occurred, as well as the last parser node and the remaining data to be/// parsed.#[derive(PartialEq, Debug)]pub struct Error<'a> { line_number: usize, last_attempted_parser: ParserNode, parsed_until: Cow<'a, [u8]>,} impl Error<'_> { /// The one-indexed line number where the error occurred. This is determined /// by the number of newlines that were successfully parsed. #[inline] #[must_use] pub const fn line_number(&self) -> usize { self.line_number + 1 } /// The remaining data that was left unparsed. #[inline] #[must_use] pub fn remaining_data(&self) -> &[u8] { &self.parsed_until } /// Coerces into an owned instance. This differs from the standard [`clone`] /// implementation as calling clone will _not_ copy the borrowed variant, /// while this method will. In other words: /// /// | Borrow type | `.clone()` | `to_owned()` | /// | ----------- | ---------- | ------------ | /// | Borrowed | Borrowed | Owned | /// | Owned | Owned | Owned | /// /// This can be most effectively seen by the differing lifetimes between the /// two. This method guarantees a `'static` lifetime, while `clone` does /// not. /// /// [`clone`]: std::clone::Clone::clone #[inline] #[must_use] pub fn to_owned(&self) -> Error<'static> { Error { line_number: self.line_number, last_attempted_parser: self.last_attempted_parser, parsed_until: self.parsed_until.clone().into_owned().into(), }Lines 1–500 of 1932. Load more
//! This module handles parsing a `git-config` file. Generally speaking, you //! want to use a higher abstraction such as [`GitConfig`] unless you have some //! explicit reason to work with events instead. //! //! The general workflow for interacting with this is to use one of the //! `parse_from_*` function variants. These will return a [`Parser`] on success, //! which can be converted into an [`Event`] iterator. The [`Parser`] also has //! additional methods for accessing leading comments or events by section. //! //! [`GitConfig`]: crate::file::GitConfig use std::{borrow::Cow, convert::TryFrom, fmt::Display, hash::Hash, io::Read, iter::FusedIterator, path::Path}; use nom::{ branch::alt, bytes::complete::{escaped, tag, take_till, take_while}, character::{ complete::{char, none_of, one_of}, is_space, }, combinator::{map, opt}, error::{Error as NomError, ErrorKind}, multi::{many0, many1}, sequence::delimited, IResult, }; /// Syntactic events that occurs in the config. Despite all these variants /// holding a [`Cow`] instead over a simple reference, the parser will only emit /// borrowed `Cow` variants. /// /// The `Cow` smart pointer is used here for ease of inserting events in a /// middle of an Event iterator. This is used, for example, in the [`GitConfig`] /// struct when adding values. /// /// [`Cow`]: std::borrow::Cow /// [`GitConfig`]: crate::file::GitConfig #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] pub enum Event<'a> { /// A comment with a comment tag and the comment itself. Note that the /// comment itself may contain additional whitespace and comment markers /// at the beginning. Comment(ParsedComment<'a>), /// A section header containing the section name and a subsection, if it /// exists. SectionHeader(ParsedSectionHeader<'a>), /// A name to a value in a section. Key(Key<'a>), /// A completed value. This may be any string, including the empty string, /// if an implicit boolean value is used. Note that these values may contain /// spaces and any special character. This value is also unprocessed, so it /// it may contain double quotes that should be replaced. Value(Cow<'a, [u8]>), /// Represents any token used to signify a new line character. On Unix /// platforms, this is typically just `\n`, but can be any valid newline /// sequence. Multiple newlines (such as `\n\n`) will be merged as a single /// newline event. Newline(Cow<'a, str>), /// Any value that isn't completed. This occurs when the value is continued /// onto the next line. A Newline event is guaranteed after, followed by /// either a ValueDone, a Whitespace, or another ValueNotDone. ValueNotDone(Cow<'a, [u8]>), /// The last line of a value which was continued onto another line. ValueDone(Cow<'a, [u8]>), /// A continuous section of insignificant whitespace. Values with internal /// spaces will not be separated by this event. Whitespace(Cow<'a, str>), /// This event is emitted when the parser counters a valid `=` character /// separating the key and value. This event is necessary as it eliminates /// the ambiguity for whitespace events between a key and value event. KeyValueSeparator, } impl Event<'_> { /// Generates a byte representation of the value. This should be used when /// non-UTF-8 sequences are present or a UTF-8 representation can't be /// guaranteed. #[inline] #[must_use] pub fn to_vec(&self) -> Vec<u8> { self.into() } /// Coerces into an owned instance. This differs from the standard [`clone`] /// implementation as calling clone will _not_ copy the borrowed variant, /// while this method will. In other words: /// /// | Borrow type | `.clone()` | `to_owned()` | /// | ----------- | ---------- | ------------ | /// | Borrowed | Borrowed | Owned | /// | Owned | Owned | Owned | /// /// This can be most effectively seen by the differing lifetimes between the /// two. This method guarantees a `'static` lifetime, while `clone` does /// not. /// /// [`clone`]: Self::clone #[inline] #[must_use] pub fn to_owned(&self) -> Event<'static> { match self { Event::Comment(e) => Event::Comment(e.to_owned()), Event::SectionHeader(e) => Event::SectionHeader(e.to_owned()), Event::Key(e) => Event::Key(e.to_owned()), Event::Value(e) => Event::Value(Cow::Owned(e.clone().into_owned())), Event::ValueNotDone(e) => Event::ValueNotDone(Cow::Owned(e.clone().into_owned())), Event::ValueDone(e) => Event::ValueDone(Cow::Owned(e.clone().into_owned())), Event::Newline(e) => Event::Newline(Cow::Owned(e.clone().into_owned())), Event::Whitespace(e) => Event::Whitespace(Cow::Owned(e.clone().into_owned())), Event::KeyValueSeparator => Event::KeyValueSeparator, } } } impl Display for Event<'_> { /// Note that this is a best-effort attempt at printing an `Event`. If /// there are non UTF-8 values in your config, this will _NOT_ render /// as read. #[inline] fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Value(e) | Self::ValueNotDone(e) | Self::ValueDone(e) => match std::str::from_utf8(e) { Ok(e) => e.fmt(f), Err(_) => write!(f, "{:02x?}", e), }, Self::Comment(e) => e.fmt(f), Self::SectionHeader(e) => e.fmt(f), Self::Key(e) => e.fmt(f), Self::Newline(e) | Self::Whitespace(e) => e.fmt(f), Self::KeyValueSeparator => write!(f, "="), } } } impl From<Event<'_>> for Vec<u8> { #[inline] fn from(event: Event) -> Self { event.into() } } impl From<&Event<'_>> for Vec<u8> { #[inline] fn from(event: &Event) -> Self { match event { Event::Value(e) | Event::ValueNotDone(e) | Event::ValueDone(e) => e.to_vec(), Event::Comment(e) => e.into(), Event::SectionHeader(e) => e.into(), Event::Key(e) => e.0.as_bytes().to_vec(), Event::Newline(e) | Event::Whitespace(e) => e.as_bytes().to_vec(), Event::KeyValueSeparator => vec![b'='], } } } /// A parsed section containing the header and the section events. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)] pub struct ParsedSection<'a> { /// The section name and subsection name, if any. pub section_header: ParsedSectionHeader<'a>, /// The syntactic events found in this section. pub events: Vec<Event<'a>>, } impl ParsedSection<'_> { /// Coerces into an owned instance. This differs from the standard [`clone`] /// implementation as calling clone will _not_ copy the borrowed variant, /// while this method will. In other words: /// /// | Borrow type | `.clone()` | `to_owned()` | /// | ----------- | ---------- | ------------ | /// | Borrowed | Borrowed | Owned | /// | Owned | Owned | Owned | /// /// This can be most effectively seen by the differing lifetimes between the /// two. This method guarantees a `'static` lifetime, while `clone` does /// not. /// /// [`clone`]: Self::clone #[inline] #[must_use] pub fn to_owned(&self) -> ParsedSection<'static> { ParsedSection { section_header: self.section_header.to_owned(), events: self.events.iter().map(Event::to_owned).collect(), } } } impl Display for ParsedSection<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.section_header)?; for event in &self.events { event.fmt(f)?; } Ok(()) } } macro_rules! generate_case_insensitive { ($name:ident, $cow_inner_type:ty, $comment:literal) => { #[doc = $comment] #[derive(Clone, Eq, Ord, Debug, Default)] pub struct $name<'a>(pub Cow<'a, $cow_inner_type>); impl $name<'_> { /// Coerces into an owned instance. This differs from the standard /// [`clone`] implementation as calling clone will _not_ copy the /// borrowed variant, while this method will. In other words: /// /// | Borrow type | `.clone()` | `to_owned()` | /// | ----------- | ---------- | ------------ | /// | Borrowed | Borrowed | Owned | /// | Owned | Owned | Owned | /// /// This can be most effectively seen by the differing lifetimes /// between the two. This method guarantees a `'static` lifetime, /// while `clone` does not. /// /// [`clone`]: Self::clone #[inline] #[must_use] pub fn to_owned(&self) -> $name<'static> { $name(Cow::Owned(self.0.clone().into_owned())) } } impl PartialEq for $name<'_> { #[inline] fn eq(&self, other: &Self) -> bool { self.0.eq_ignore_ascii_case(&other.0) } } impl Display for $name<'_> { #[inline] fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.0.fmt(f) } } impl PartialOrd for $name<'_> { #[inline] fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { self.0 .to_ascii_lowercase() .partial_cmp(&other.0.to_ascii_lowercase()) } } impl std::hash::Hash for $name<'_> { #[inline] fn hash<H: std::hash::Hasher>(&self, state: &mut H) { self.0.to_ascii_lowercase().hash(state) } } impl<'a> From<&'a str> for $name<'a> { #[inline] fn from(s: &'a str) -> Self { Self(Cow::Borrowed(s)) } } impl<'a> From<Cow<'a, str>> for $name<'a> { #[inline] fn from(s: Cow<'a, str>) -> Self { Self(s) } } impl<'a> std::ops::Deref for $name<'a> { type Target = $cow_inner_type; #[inline] fn deref(&self) -> &Self::Target { &self.0 } } }; } generate_case_insensitive!( SectionHeaderName, str, "Wrapper struct for section header names, since section headers are case-insensitive." ); generate_case_insensitive!( Key, str, "Wrapper struct for key names, since keys are case-insensitive." ); /// A parsed section header, containing a name and optionally a subsection name. /// /// Note that section headers must be parsed as valid ASCII, and thus all valid /// instances must also necessarily be valid UTF-8, which is why we use a /// [`str`] instead of [`[u8]`]. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)] pub struct ParsedSectionHeader<'a> { /// The name of the header. pub name: SectionHeaderName<'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 separator: Option<Cow<'a, str>>, /// The subsection name without quotes if any exist. pub subsection_name: Option<Cow<'a, str>>, } impl ParsedSectionHeader<'_> { /// Generates a byte representation of the value. This should be used when /// non-UTF-8 sequences are present or a UTF-8 representation can't be /// guaranteed. #[must_use] #[inline] pub fn to_vec(&self) -> Vec<u8> { self.into() } /// Coerces into an owned instance. This differs from the standard [`clone`] /// implementation as calling clone will _not_ copy the borrowed variant, /// while this method will. In other words: /// /// | Borrow type | `.clone()` | `to_owned()` | /// | ----------- | ---------- | ------------ | /// | Borrowed | Borrowed | Owned | /// | Owned | Owned | Owned | /// /// This can be most effectively seen by the differing lifetimes between the /// two. This method guarantees a `'static` lifetime, while `clone` does /// not. /// /// [`clone`]: Self::clone #[inline] #[must_use] pub fn to_owned(&self) -> ParsedSectionHeader<'static> { ParsedSectionHeader { name: self.name.to_owned(), separator: self.separator.clone().map(|v| Cow::Owned(v.into_owned())), subsection_name: self.subsection_name.clone().map(|v| Cow::Owned(v.into_owned())), } } } impl Display for ParsedSectionHeader<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "[{}", self.name)?; if let Some(v) = &self.separator { // Separator must be utf-8 v.fmt(f)?; let subsection_name = self.subsection_name.as_ref().unwrap(); if v == "." { subsection_name.fmt(f)?; } else { write!(f, "\"{}\"", subsection_name)?; } } write!(f, "]") } } impl From<ParsedSectionHeader<'_>> for Vec<u8> { #[inline] fn from(header: ParsedSectionHeader) -> Self { header.into() } } impl From<&ParsedSectionHeader<'_>> for Vec<u8> { #[inline] fn from(header: &ParsedSectionHeader) -> Self { header.to_string().into_bytes() } } impl<'a> From<ParsedSectionHeader<'a>> for Event<'a> { #[inline] fn from(header: ParsedSectionHeader) -> Event { Event::SectionHeader(header) } } /// A parsed comment event containing the comment marker and comment. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)] pub struct ParsedComment<'a> { /// The comment marker used. This is either a semicolon or octothorpe. pub comment_tag: char, /// The parsed comment. pub comment: Cow<'a, [u8]>, } impl ParsedComment<'_> { /// Coerces into an owned instance. This differs from the standard [`clone`] /// implementation as calling clone will _not_ copy the borrowed variant, /// while this method will. In other words: /// /// | Borrow type | `.clone()` | `to_owned()` | /// | ----------- | ---------- | ------------ | /// | Borrowed | Borrowed | Owned | /// | Owned | Owned | Owned | /// /// This can be most effectively seen by the differing lifetimes between the /// two. This method guarantees a `'static` lifetime, while `clone` does /// not. /// /// [`clone`]: Self::clone #[inline] #[must_use] pub fn to_owned(&self) -> ParsedComment<'static> { ParsedComment { comment_tag: self.comment_tag, comment: Cow::Owned(self.comment.to_vec()), } } } impl Display for ParsedComment<'_> { /// Note that this is a best-effort attempt at printing an comment. If /// there are non UTF-8 values in your config, this will _NOT_ render /// as read. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.comment_tag.fmt(f)?; if let Ok(s) = std::str::from_utf8(&self.comment) { s.fmt(f) } else { write!(f, "{:02x?}", self.comment) } } } impl From<ParsedComment<'_>> for Vec<u8> { #[inline] fn from(c: ParsedComment) -> Self { c.into() } } impl From<&ParsedComment<'_>> for Vec<u8> { #[inline] fn from(c: &ParsedComment) -> Self { let mut values = vec![c.comment_tag as u8]; values.extend(c.comment.iter()); values } } /// A parser error reports the one-indexed line number where the parsing error /// occurred, as well as the last parser node and the remaining data to be /// parsed. #[derive(PartialEq, Debug)] pub struct Error<'a> { line_number: usize, last_attempted_parser: ParserNode, parsed_until: Cow<'a, [u8]>, } impl Error<'_> { /// The one-indexed line number where the error occurred. This is determined /// by the number of newlines that were successfully parsed. #[inline] #[must_use] pub const fn line_number(&self) -> usize { self.line_number + 1 } /// The remaining data that was left unparsed. #[inline] #[must_use] pub fn remaining_data(&self) -> &[u8] { &self.parsed_until } /// Coerces into an owned instance. This differs from the standard [`clone`] /// implementation as calling clone will _not_ copy the borrowed variant, /// while this method will. In other words: /// /// | Borrow type | `.clone()` | `to_owned()` | /// | ----------- | ---------- | ------------ | /// | Borrowed | Borrowed | Owned | /// | Owned | Owned | Owned | /// /// This can be most effectively seen by the differing lifetimes between the /// two. This method guarantees a `'static` lifetime, while `clone` does /// not. /// /// [`clone`]: std::clone::Clone::clone #[inline] #[must_use] pub fn to_owned(&self) -> Error<'static> { Error { line_number: self.line_number, last_attempted_parser: self.last_attempted_parser, parsed_until: self.parsed_until.clone().into_owned().into(), }