Compare commits
2 commits
7cbdd46fde
...
6ce2c1d89d
Author | SHA1 | Date | |
---|---|---|---|
6ce2c1d89d | |||
ebfd15b6d3 |
3 changed files with 253 additions and 22 deletions
95
src/file.rs
95
src/file.rs
|
@ -4,6 +4,7 @@ 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.
|
||||||
|
@ -12,6 +13,8 @@ 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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,6 +54,8 @@ 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,
|
||||||
|
@ -117,6 +122,8 @@ 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,
|
||||||
|
@ -160,11 +167,14 @@ 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()
|
||||||
|
@ -258,7 +268,8 @@ 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.
|
/// performance of the typical usage behavior of many lookups and relatively
|
||||||
|
/// fewer insertions.
|
||||||
///
|
///
|
||||||
/// # Multivar behavior
|
/// # Multivar behavior
|
||||||
///
|
///
|
||||||
|
@ -302,7 +313,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.
|
||||||
front_matter_events: Vec<Event<'a>>,
|
frontmatter_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.
|
||||||
|
@ -354,12 +365,12 @@ impl<'event> GitConfig<'event> {
|
||||||
///
|
///
|
||||||
/// [`values`]: crate::values
|
/// [`values`]: crate::values
|
||||||
/// [`TryFrom`]: std::convert::TryFrom
|
/// [`TryFrom`]: std::convert::TryFrom
|
||||||
pub fn get_value<'b, T: TryFrom<Cow<'event, [u8]>>>(
|
pub fn get_value<'lookup, T: TryFrom<Cow<'event, [u8]>>>(
|
||||||
&'event self,
|
&'event self,
|
||||||
section_name: &'b str,
|
section_name: &'lookup str,
|
||||||
subsection_name: Option<&'b str>,
|
subsection_name: Option<&'lookup str>,
|
||||||
key: &'b str,
|
key: &'lookup str,
|
||||||
) -> Result<T, GitConfigError<'b>> {
|
) -> Result<T, GitConfigError<'lookup>> {
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -414,12 +425,12 @@ impl<'event> GitConfig<'event> {
|
||||||
///
|
///
|
||||||
/// [`values`]: crate::values
|
/// [`values`]: crate::values
|
||||||
/// [`TryFrom`]: std::convert::TryFrom
|
/// [`TryFrom`]: std::convert::TryFrom
|
||||||
pub fn get_multi_value<'b, T: TryFrom<Cow<'event, [u8]>>>(
|
pub fn get_multi_value<'lookup, T: TryFrom<Cow<'event, [u8]>>>(
|
||||||
&'event self,
|
&'event self,
|
||||||
section_name: &'b str,
|
section_name: &'lookup str,
|
||||||
subsection_name: Option<&'b str>,
|
subsection_name: Option<&'lookup str>,
|
||||||
key: &'b str,
|
key: &'lookup str,
|
||||||
) -> Result<Vec<T>, GitConfigError<'b>> {
|
) -> Result<Vec<T>, GitConfigError<'lookup>> {
|
||||||
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)
|
||||||
|
@ -860,6 +871,35 @@ 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(
|
||||||
|
§ion_name.into(),
|
||||||
|
subsection_name.into().as_deref(),
|
||||||
|
)
|
||||||
|
.ok()?;
|
||||||
|
|
||||||
|
self.sections.remove(§ion_ids.pop()?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Private helper functions
|
/// Private helper functions
|
||||||
|
@ -979,7 +1019,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 {
|
||||||
front_matter_events: vec![],
|
frontmatter_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(),
|
||||||
|
@ -1024,7 +1064,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.front_matter_events.push(e),
|
None => new_self.frontmatter_events.push(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1042,12 +1082,37 @@ 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.front_matter_events {
|
for front_matter in &self.frontmatter_events {
|
||||||
front_matter.fmt(f)?;
|
front_matter.fmt(f)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,12 @@ 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
|
||||||
|
@ -88,6 +94,30 @@ 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> {
|
||||||
|
@ -107,12 +137,6 @@ 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
|
||||||
|
@ -132,6 +156,12 @@ 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)?;
|
||||||
|
@ -151,6 +181,24 @@ 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> {
|
||||||
|
@ -174,6 +222,20 @@ 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.
|
||||||
|
@ -250,7 +312,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 a[u8]action to a `git-config`
|
/// around the parser to provide a higher-level abstraction 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
|
||||||
|
|
104
src/values.rs
104
src/values.rs
|
@ -149,6 +149,12 @@ 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) {
|
||||||
|
@ -207,6 +213,23 @@ 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")]
|
||||||
|
@ -237,6 +260,16 @@ 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 = ();
|
||||||
|
|
||||||
|
@ -319,6 +352,27 @@ 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>
|
||||||
|
@ -407,6 +461,15 @@ 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>
|
||||||
|
@ -430,10 +493,18 @@ 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)?;
|
||||||
|
@ -514,6 +585,18 @@ 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.
|
||||||
|
@ -598,11 +681,20 @@ 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 {
|
||||||
|
@ -710,6 +802,18 @@ 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
|
||||||
|
|
Reference in a new issue