Compare commits

..

No commits in common. "6ce2c1d89de4066faa91c0e40df566bfa200af96" and "7cbdd46fdecc022f702ff5e56b7edf45be8c230f" have entirely different histories.

3 changed files with 22 additions and 253 deletions

View file

@ -4,7 +4,6 @@ use std::collections::{HashMap, VecDeque};
use std::{borrow::Borrow, convert::TryFrom}; use std::{borrow::Borrow, convert::TryFrom};
use std::{borrow::Cow, fmt::Display}; use std::{borrow::Cow, fmt::Display};
/// All possible error types that may occur from interacting with [`GitConfig`].
#[derive(PartialEq, Eq, Hash, Copy, Clone, PartialOrd, Ord, Debug)] #[derive(PartialEq, Eq, Hash, Copy, Clone, PartialOrd, Ord, Debug)]
pub enum GitConfigError<'a> { pub enum GitConfigError<'a> {
/// The requested section does not exist. /// The requested section does not exist.
@ -13,8 +12,6 @@ pub enum GitConfigError<'a> {
SubSectionDoesNotExist(Option<&'a str>), SubSectionDoesNotExist(Option<&'a str>),
/// The key does not exist in the requested section. /// The key does not exist in the requested section.
KeyDoesNotExist(&'a str), KeyDoesNotExist(&'a str),
/// The conversion into the provided type for methods such as
/// [`GitConfig::get_value`] failed.
FailedConversion, FailedConversion,
} }
@ -54,8 +51,6 @@ enum LookupTreeNode<'a> {
NonTerminal(HashMap<Cow<'a, str>, Vec<SectionId>>), NonTerminal(HashMap<Cow<'a, str>, Vec<SectionId>>),
} }
/// An intermediate representation of a mutable value obtained from
/// [`GitConfig`].
pub struct MutableValue<'borrow, 'lookup, 'event> { pub struct MutableValue<'borrow, 'lookup, 'event> {
section: &'borrow mut Vec<Event<'event>>, section: &'borrow mut Vec<Event<'event>>,
key: &'lookup str, key: &'lookup str,
@ -122,8 +117,6 @@ impl MutableValue<'_, '_, '_> {
} }
} }
/// An imtermediate representation of a mutable multivar obtained from
/// [`GitConfig`].
pub struct MutableMultiValue<'borrow, 'lookup, 'event> { pub struct MutableMultiValue<'borrow, 'lookup, 'event> {
section: &'borrow mut HashMap<SectionId, Vec<Event<'event>>>, section: &'borrow mut HashMap<SectionId, Vec<Event<'event>>>,
key: &'lookup str, key: &'lookup str,
@ -167,14 +160,11 @@ impl<'event> MutableMultiValue<'_, '_, 'event> {
Ok(values) Ok(values)
} }
/// Returns the size of values the multivar has.
#[inline] #[inline]
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.indices_and_sizes.len() self.indices_and_sizes.len()
} }
/// Returns if the multivar has any values. This might occur if the value
/// was deleted but not set with a new value.
#[inline] #[inline]
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.indices_and_sizes.is_empty() self.indices_and_sizes.is_empty()
@ -268,8 +258,7 @@ impl<'event> MutableMultiValue<'_, '_, 'event> {
/// High level `git-config` reader and writer. /// High level `git-config` reader and writer.
/// ///
/// Internally, this uses various acceleration data structures to improve /// Internally, this uses various acceleration data structures to improve
/// performance of the typical usage behavior of many lookups and relatively /// performance.
/// fewer insertions.
/// ///
/// # Multivar behavior /// # Multivar behavior
/// ///
@ -313,7 +302,7 @@ pub struct GitConfig<'a> {
/// The list of events that occur before an actual section. Since a /// The list of events that occur before an actual section. Since a
/// `git-config` file prohibits global values, this vec is limited to only /// `git-config` file prohibits global values, this vec is limited to only
/// comment, newline, and whitespace events. /// comment, newline, and whitespace events.
frontmatter_events: Vec<Event<'a>>, front_matter_events: Vec<Event<'a>>,
section_lookup_tree: HashMap<Cow<'a, str>, Vec<LookupTreeNode<'a>>>, section_lookup_tree: HashMap<Cow<'a, str>, Vec<LookupTreeNode<'a>>>,
/// SectionId to section mapping. The value of this HashMap contains actual /// SectionId to section mapping. The value of this HashMap contains actual
/// events. /// events.
@ -365,12 +354,12 @@ impl<'event> GitConfig<'event> {
/// ///
/// [`values`]: crate::values /// [`values`]: crate::values
/// [`TryFrom`]: std::convert::TryFrom /// [`TryFrom`]: std::convert::TryFrom
pub fn get_value<'lookup, T: TryFrom<Cow<'event, [u8]>>>( pub fn get_value<'b, T: TryFrom<Cow<'event, [u8]>>>(
&'event self, &'event self,
section_name: &'lookup str, section_name: &'b str,
subsection_name: Option<&'lookup str>, subsection_name: Option<&'b str>,
key: &'lookup str, key: &'b str,
) -> Result<T, GitConfigError<'lookup>> { ) -> Result<T, GitConfigError<'b>> {
T::try_from(self.get_raw_value(section_name, subsection_name, key)?) T::try_from(self.get_raw_value(section_name, subsection_name, key)?)
.map_err(|_| GitConfigError::FailedConversion) .map_err(|_| GitConfigError::FailedConversion)
} }
@ -425,12 +414,12 @@ impl<'event> GitConfig<'event> {
/// ///
/// [`values`]: crate::values /// [`values`]: crate::values
/// [`TryFrom`]: std::convert::TryFrom /// [`TryFrom`]: std::convert::TryFrom
pub fn get_multi_value<'lookup, T: TryFrom<Cow<'event, [u8]>>>( pub fn get_multi_value<'b, T: TryFrom<Cow<'event, [u8]>>>(
&'event self, &'event self,
section_name: &'lookup str, section_name: &'b str,
subsection_name: Option<&'lookup str>, subsection_name: Option<&'b str>,
key: &'lookup str, key: &'b str,
) -> Result<Vec<T>, GitConfigError<'lookup>> { ) -> Result<Vec<T>, GitConfigError<'b>> {
self.get_raw_multi_value(section_name, subsection_name, key)? self.get_raw_multi_value(section_name, subsection_name, key)?
.into_iter() .into_iter()
.map(T::try_from) .map(T::try_from)
@ -871,35 +860,6 @@ impl<'event> GitConfig<'event> {
self.get_raw_multi_value_mut(section_name, subsection_name, key) self.get_raw_multi_value_mut(section_name, subsection_name, key)
.map(|mut v| v.set_values(new_values)) .map(|mut v| v.set_values(new_values))
} }
/// Adds a new section to config. This cannot fail.
pub fn new_empty_section(
&mut self,
section_name: impl Into<Cow<'event, str>>,
subsection_name: impl Into<Option<Cow<'event, str>>>,
) {
self.push_section(
Some(section_name.into()),
subsection_name.into(),
&mut Some(vec![]),
)
}
/// Removes the section, returning the events it had, if any.
pub fn remove_section(
&mut self,
section_name: impl Into<Cow<'event, str>>,
subsection_name: impl Into<Option<Cow<'event, str>>>,
) -> Option<Vec<Event>> {
let mut section_ids = self
.get_section_ids_by_name_and_subname(
&section_name.into(),
subsection_name.into().as_deref(),
)
.ok()?;
self.sections.remove(&section_ids.pop()?)
}
} }
/// Private helper functions /// Private helper functions
@ -1019,7 +979,7 @@ impl<'a> TryFrom<&'a [u8]> for GitConfig<'a> {
impl<'a> From<Parser<'a>> for GitConfig<'a> { impl<'a> From<Parser<'a>> for GitConfig<'a> {
fn from(parser: Parser<'a>) -> Self { fn from(parser: Parser<'a>) -> Self {
let mut new_self = Self { let mut new_self = Self {
frontmatter_events: vec![], front_matter_events: vec![],
sections: HashMap::new(), sections: HashMap::new(),
section_lookup_tree: HashMap::new(), section_lookup_tree: HashMap::new(),
section_headers: HashMap::new(), section_headers: HashMap::new(),
@ -1064,7 +1024,7 @@ impl<'a> From<Parser<'a>> for GitConfig<'a> {
e @ Event::Comment(_) | e @ Event::Newline(_) | e @ Event::Whitespace(_) => { e @ Event::Comment(_) | e @ Event::Newline(_) | e @ Event::Whitespace(_) => {
match maybe_section { match maybe_section {
Some(ref mut section) => section.push(e), Some(ref mut section) => section.push(e),
None => new_self.frontmatter_events.push(e), None => new_self.front_matter_events.push(e),
} }
} }
} }
@ -1082,37 +1042,12 @@ impl<'a> From<Parser<'a>> for GitConfig<'a> {
} }
} }
impl<'a> Into<Vec<u8>> for GitConfig<'a> {
fn into(self) -> Vec<u8> {
(&self).into()
}
}
impl<'a> Into<Vec<u8>> for &GitConfig<'a> {
fn into(self) -> Vec<u8> {
let mut value = vec![];
for events in &self.frontmatter_events {
value.extend(events.to_vec());
}
for section_id in &self.section_order {
value.extend(self.section_headers.get(section_id).unwrap().to_vec());
for event in self.sections.get(section_id).unwrap() {
value.extend(event.to_vec());
}
}
value
}
}
impl Display for GitConfig<'_> { impl Display for GitConfig<'_> {
/// Note that this is a best-effort attempt at printing a `GitConfig`. If /// Note that this is a best-effort attempt at printing a `GitConfig`. If
/// there are non UTF-8 values in your config, this will _NOT_ render as /// there are non UTF-8 values in your config, this will _NOT_ render as
/// read. /// read.
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for front_matter in &self.frontmatter_events { for front_matter in &self.front_matter_events {
front_matter.fmt(f)?; front_matter.fmt(f)?;
} }

View file

@ -68,12 +68,6 @@ pub enum Event<'a> {
KeyValueSeparator, KeyValueSeparator,
} }
impl Event<'_> {
pub fn to_vec(&self) -> Vec<u8> {
self.into()
}
}
impl Display for Event<'_> { impl Display for Event<'_> {
/// Note that this is a best-effort attempt at printing an `Event`. If /// 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 /// there are non UTF-8 values in your config, this will _NOT_ render
@ -94,30 +88,6 @@ impl Display for Event<'_> {
} }
} }
impl Into<Vec<u8>> for Event<'_> {
fn into(self) -> Vec<u8> {
match self {
Self::Value(e) | Self::ValueNotDone(e) | Self::ValueDone(e) => e.to_vec(),
Self::Comment(e) => e.into(),
Self::SectionHeader(e) => e.into(),
Self::Key(e) | Self::Newline(e) | Self::Whitespace(e) => e.as_bytes().to_vec(),
Self::KeyValueSeparator => vec![b'='],
}
}
}
impl Into<Vec<u8>> for &Event<'_> {
fn into(self) -> Vec<u8> {
match self {
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) | 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. /// A parsed section containing the header and the section events.
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)] #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
pub struct ParsedSection<'a> { pub struct ParsedSection<'a> {
@ -137,6 +107,12 @@ impl Display for ParsedSection<'_> {
} }
} }
impl<'a> Into<Event<'a>> for ParsedSectionHeader<'a> {
fn into(self) -> Event<'a> {
Event::SectionHeader(self)
}
}
/// A parsed section header, containing a name and optionally a subsection name. /// 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 /// Note that section headers must be parsed as valid ASCII, and thus all valid
@ -156,12 +132,6 @@ pub struct ParsedSectionHeader<'a> {
pub subsection_name: Option<Cow<'a, str>>, pub subsection_name: Option<Cow<'a, str>>,
} }
impl ParsedSectionHeader<'_> {
pub fn to_vec(&self) -> Vec<u8> {
self.into()
}
}
impl Display for ParsedSectionHeader<'_> { impl Display for ParsedSectionHeader<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[{}", self.name)?; write!(f, "[{}", self.name)?;
@ -181,24 +151,6 @@ impl Display for ParsedSectionHeader<'_> {
} }
} }
impl Into<Vec<u8>> for ParsedSectionHeader<'_> {
fn into(self) -> Vec<u8> {
(&self).into()
}
}
impl Into<Vec<u8>> for &ParsedSectionHeader<'_> {
fn into(self) -> Vec<u8> {
self.to_string().into_bytes()
}
}
impl<'a> Into<Event<'a>> for ParsedSectionHeader<'a> {
fn into(self) -> Event<'a> {
Event::SectionHeader(self)
}
}
/// A parsed comment event containing the comment marker and comment. /// A parsed comment event containing the comment marker and comment.
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)] #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
pub struct ParsedComment<'a> { pub struct ParsedComment<'a> {
@ -222,20 +174,6 @@ impl Display for ParsedComment<'_> {
} }
} }
impl Into<Vec<u8>> for ParsedComment<'_> {
fn into(self) -> Vec<u8> {
(&self).into()
}
}
impl Into<Vec<u8>> for &ParsedComment<'_> {
fn into(self) -> Vec<u8> {
let mut values = vec![self.comment_tag as u8];
values.extend(self.comment.iter());
values
}
}
/// A parser error reports the one-indexed line number where the parsing error /// 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 /// occurred, as well as the last parser node and the remaining data to be
/// parsed. /// parsed.
@ -312,7 +250,7 @@ impl Display for ParserNode {
/// ///
/// This is parser exposes low-level syntactic events from a `git-config` file. /// This is parser exposes low-level syntactic events from a `git-config` file.
/// Generally speaking, you'll want to use [`GitConfig`] as it wraps /// Generally speaking, you'll want to use [`GitConfig`] as it wraps
/// around the parser to provide a higher-level abstraction to a `git-config` /// around the parser to provide a higher-level a[u8]action to a `git-config`
/// file, including querying, modifying, and updating values. /// file, including querying, modifying, and updating values.
/// ///
/// This parser guarantees that the events emitted are sufficient to /// This parser guarantees that the events emitted are sufficient to

View file

@ -149,12 +149,6 @@ pub enum Value<'a> {
Other(Cow<'a, [u8]>), Other(Cow<'a, [u8]>),
} }
impl Value<'_> {
pub fn to_vec(&self) -> Vec<u8> {
self.into()
}
}
impl<'a> From<&'a str> for Value<'a> { impl<'a> From<&'a str> for Value<'a> {
fn from(s: &'a str) -> Self { fn from(s: &'a str) -> Self {
if let Ok(bool) = Boolean::try_from(s) { if let Ok(bool) = Boolean::try_from(s) {
@ -213,23 +207,6 @@ impl<'a> From<Cow<'a, [u8]>> for Value<'a> {
} }
} }
impl Into<Vec<u8>> for Value<'_> {
fn into(self) -> Vec<u8> {
(&self).into()
}
}
impl Into<Vec<u8>> for &Value<'_> {
fn into(self) -> Vec<u8> {
match self {
Value::Boolean(b) => b.into(),
Value::Integer(i) => i.into(),
Value::Color(c) => c.into(),
Value::Other(o) => o.to_vec(),
}
}
}
// todo display for value // todo display for value
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
@ -260,16 +237,6 @@ pub enum Boolean<'a> {
False(Cow<'a, str>), False(Cow<'a, str>),
} }
impl Boolean<'_> {
pub fn to_vec(&self) -> Vec<u8> {
self.into()
}
pub fn as_bytes(&self) -> &[u8] {
self.into()
}
}
impl<'a> TryFrom<&'a str> for Boolean<'a> { impl<'a> TryFrom<&'a str> for Boolean<'a> {
type Error = (); type Error = ();
@ -352,27 +319,6 @@ impl Into<bool> for Boolean<'_> {
} }
} }
impl<'a, 'b: 'a> Into<&'a [u8]> for &'b Boolean<'a> {
fn into(self) -> &'a [u8] {
match self {
Boolean::True(t) => t.into(),
Boolean::False(f) => f.as_bytes(),
}
}
}
impl Into<Vec<u8>> for Boolean<'_> {
fn into(self) -> Vec<u8> {
(&self).into()
}
}
impl Into<Vec<u8>> for &Boolean<'_> {
fn into(self) -> Vec<u8> {
self.to_string().into_bytes()
}
}
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
impl Serialize for Boolean<'_> { impl Serialize for Boolean<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@ -461,15 +407,6 @@ impl Display for TrueVariant<'_> {
} }
} }
impl<'a, 'b: 'a> Into<&'a [u8]> for &'b TrueVariant<'a> {
fn into(self) -> &'a [u8] {
match self {
TrueVariant::Explicit(e) => e.as_bytes(),
TrueVariant::Implicit => &[],
}
}
}
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
impl Serialize for TrueVariant<'_> { impl Serialize for TrueVariant<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@ -493,18 +430,10 @@ impl Serialize for TrueVariant<'_> {
/// [`bitwise_offset`]: IntegerSuffix::bitwise_offset /// [`bitwise_offset`]: IntegerSuffix::bitwise_offset
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct Integer { pub struct Integer {
/// The value, without any suffix modification
pub value: i64, pub value: i64,
/// A provided suffix, if any.
pub suffix: Option<IntegerSuffix>, pub suffix: Option<IntegerSuffix>,
} }
impl Integer {
pub fn to_vec(&self) -> Vec<u8> {
self.into()
}
}
impl Display for Integer { impl Display for Integer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.value)?; write!(f, "{}", self.value)?;
@ -585,18 +514,6 @@ impl TryFrom<Cow<'_, [u8]>> for Integer {
} }
} }
impl Into<Vec<u8>> for Integer {
fn into(self) -> Vec<u8> {
(&self).into()
}
}
impl Into<Vec<u8>> for &Integer {
fn into(self) -> Vec<u8> {
self.to_string().into_bytes()
}
}
/// Integer prefixes that are supported by `git-config`. /// Integer prefixes that are supported by `git-config`.
/// ///
/// These values are base-2 unit of measurements, not the base-10 variants. /// These values are base-2 unit of measurements, not the base-10 variants.
@ -681,20 +598,11 @@ impl TryFrom<Vec<u8>> for IntegerSuffix {
/// foreground or background color. /// foreground or background color.
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)] #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
pub struct Color { pub struct Color {
/// A provided foreground color
pub foreground: Option<ColorValue>, pub foreground: Option<ColorValue>,
/// A provided background color
pub background: Option<ColorValue>, pub background: Option<ColorValue>,
/// A potentially empty list of text attributes
pub attributes: Vec<ColorAttribute>, pub attributes: Vec<ColorAttribute>,
} }
impl Color {
pub fn to_vec(&self) -> Vec<u8> {
self.into()
}
}
impl Display for Color { impl Display for Color {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(fg) = self.foreground { if let Some(fg) = self.foreground {
@ -802,18 +710,6 @@ impl TryFrom<Cow<'_, [u8]>> for Color {
} }
} }
impl Into<Vec<u8>> for Color {
fn into(self) -> Vec<u8> {
(&self).into()
}
}
impl Into<Vec<u8>> for &Color {
fn into(self) -> Vec<u8> {
self.to_string().into_bytes()
}
}
/// Discriminating enum for [`Color`] values. /// Discriminating enum for [`Color`] values.
/// ///
/// `git-config` supports the eight standard colors, their bright variants, an /// `git-config` supports the eight standard colors, their bright variants, an