fix get_raw_value, fix returning refs to cows
This commit is contained in:
parent
5720ccd003
commit
c01b61cb11
2 changed files with 211 additions and 60 deletions
102
src/file.rs
102
src/file.rs
|
@ -1,6 +1,6 @@
|
||||||
use crate::parser::{parse_from_bytes, Error, Event, ParsedSectionHeader, Parser};
|
use crate::parser::{parse_from_bytes, Error, Event, ParsedSectionHeader, Parser};
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
use std::convert::TryFrom;
|
use std::{borrow::Borrow, convert::TryFrom};
|
||||||
use std::{borrow::Cow, fmt::Display};
|
use std::{borrow::Cow, fmt::Display};
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Hash, Copy, Clone, PartialOrd, Ord, Debug)]
|
#[derive(PartialEq, Eq, Hash, Copy, Clone, PartialOrd, Ord, Debug)]
|
||||||
|
@ -86,7 +86,7 @@ enum LookupTreeNode<'a> {
|
||||||
/// # use std::borrow::Cow;
|
/// # use std::borrow::Cow;
|
||||||
/// # use std::convert::TryFrom;
|
/// # use std::convert::TryFrom;
|
||||||
/// # let git_config = GitConfig::try_from("[core]a=b\n[core]\na=c\na=d").unwrap();
|
/// # let git_config = GitConfig::try_from("[core]a=b\n[core]\na=c\na=d").unwrap();
|
||||||
/// assert_eq!(git_config.get_raw_value("core", None, "a"), Ok(&Cow::Borrowed("d".as_bytes())));
|
/// assert_eq!(git_config.get_raw_value("core", None, "a"), Ok(Cow::Borrowed("d".as_bytes())));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Consider the `multi` variants of the methods instead, if you want to work
|
/// Consider the `multi` variants of the methods instead, if you want to work
|
||||||
|
@ -198,8 +198,8 @@ impl<'a> GitConfig<'a> {
|
||||||
///
|
///
|
||||||
/// [`values`]: crate::values
|
/// [`values`]: crate::values
|
||||||
/// [`TryFrom`]: std::convert::TryFrom
|
/// [`TryFrom`]: std::convert::TryFrom
|
||||||
pub fn get_value<'b, 'c, T: TryFrom<&'c [u8]>>(
|
pub fn get_value<'b, T: TryFrom<Cow<'a, [u8]>>>(
|
||||||
&'c self,
|
&'a self,
|
||||||
section_name: &'b str,
|
section_name: &'b str,
|
||||||
subsection_name: Option<&'b str>,
|
subsection_name: Option<&'b str>,
|
||||||
key: &'b str,
|
key: &'b str,
|
||||||
|
@ -232,34 +232,46 @@ impl<'a> GitConfig<'a> {
|
||||||
/// This function will return an error if the key is not in the requested
|
/// This function will return an error if the key is not in the requested
|
||||||
/// section and subsection, or if the section and subsection do not exist.
|
/// section and subsection, or if the section and subsection do not exist.
|
||||||
pub fn get_raw_value<'b>(
|
pub fn get_raw_value<'b>(
|
||||||
&self,
|
&'a self,
|
||||||
section_name: &'b str,
|
section_name: &'b str,
|
||||||
subsection_name: Option<&'b str>,
|
subsection_name: Option<&'b str>,
|
||||||
key: &'b str,
|
key: &'b str,
|
||||||
) -> Result<&Cow<'a, [u8]>, GitConfigError<'b>> {
|
) -> Result<Cow<'a, [u8]>, GitConfigError<'b>> {
|
||||||
let key = key;
|
let key = key;
|
||||||
// Note: cannot wrap around the raw_multi_value method because we need
|
// Note: cannot wrap around the raw_multi_value method because we need
|
||||||
// to guarantee that the highest section id is used (so that we follow
|
// to guarantee that the highest section id is used (so that we follow
|
||||||
// the "last one wins" resolution strategy by `git-config`).
|
// the "last one wins" resolution strategy by `git-config`).
|
||||||
let section_id = self.get_section_id_by_name_and_subname(section_name, subsection_name)?;
|
let section_id = self.get_section_id_by_name_and_subname(section_name, subsection_name)?;
|
||||||
|
|
||||||
// section_id is guaranteed to exist in self.sections, else we have a
|
|
||||||
// violated invariant.
|
|
||||||
let events = self.sections.get(§ion_id).unwrap();
|
|
||||||
let mut found_key = false;
|
let mut found_key = false;
|
||||||
let mut latest_value = None;
|
let mut latest_value = None;
|
||||||
for event in events {
|
let mut partial_value = None;
|
||||||
|
|
||||||
|
// section_id is guaranteed to exist in self.sections, else we have a
|
||||||
|
// violated invariant.
|
||||||
|
for event in self.sections.get(§ion_id).unwrap() {
|
||||||
match event {
|
match event {
|
||||||
Event::Key(event_key) if *event_key == key => found_key = true,
|
Event::Key(event_key) if *event_key == key => found_key = true,
|
||||||
Event::Value(v) if found_key => {
|
Event::Value(v) if found_key => {
|
||||||
found_key = false;
|
found_key = false;
|
||||||
latest_value = Some(v);
|
latest_value = Some(Cow::Borrowed(v.borrow()));
|
||||||
|
partial_value = None;
|
||||||
|
}
|
||||||
|
Event::ValueNotDone(v) if found_key => {
|
||||||
|
latest_value = None;
|
||||||
|
partial_value = Some((*v).to_vec());
|
||||||
|
}
|
||||||
|
Event::ValueDone(v) if found_key => {
|
||||||
|
found_key = false;
|
||||||
|
partial_value.as_mut().unwrap().extend(&**v);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
latest_value.ok_or(GitConfigError::KeyDoesNotExist(key))
|
latest_value
|
||||||
|
.or_else(|| partial_value.map(Cow::Owned))
|
||||||
|
.ok_or(GitConfigError::KeyDoesNotExist(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a mutable reference to an uninterpreted value given a section,
|
/// Returns a mutable reference to an uninterpreted value given a section,
|
||||||
|
@ -328,9 +340,9 @@ impl<'a> GitConfig<'a> {
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// git_config.get_raw_multi_value("core", None, "a"),
|
/// git_config.get_raw_multi_value("core", None, "a"),
|
||||||
/// Ok(vec![
|
/// Ok(vec![
|
||||||
/// &Cow::<[u8]>::Borrowed(b"b"),
|
/// Cow::<[u8]>::Borrowed(b"b"),
|
||||||
/// &Cow::<[u8]>::Borrowed(b"c"),
|
/// Cow::<[u8]>::Borrowed(b"c"),
|
||||||
/// &Cow::<[u8]>::Borrowed(b"d"),
|
/// Cow::<[u8]>::Borrowed(b"d"),
|
||||||
/// ]),
|
/// ]),
|
||||||
/// );
|
/// );
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -348,7 +360,7 @@ impl<'a> GitConfig<'a> {
|
||||||
section_name: &'b str,
|
section_name: &'b str,
|
||||||
subsection_name: Option<&'b str>,
|
subsection_name: Option<&'b str>,
|
||||||
key: &'b str,
|
key: &'b str,
|
||||||
) -> Result<Vec<&Cow<'_, [u8]>>, GitConfigError<'b>> {
|
) -> Result<Vec<Cow<'_, [u8]>>, GitConfigError<'b>> {
|
||||||
let key = key;
|
let key = key;
|
||||||
let mut values = vec![];
|
let mut values = vec![];
|
||||||
for section_id in self.get_section_ids_by_name_and_subname(section_name, subsection_name)? {
|
for section_id in self.get_section_ids_by_name_and_subname(section_name, subsection_name)? {
|
||||||
|
@ -359,7 +371,7 @@ impl<'a> GitConfig<'a> {
|
||||||
match event {
|
match event {
|
||||||
Event::Key(event_key) if *event_key == key => found_key = true,
|
Event::Key(event_key) if *event_key == key => found_key = true,
|
||||||
Event::Value(v) if found_key => {
|
Event::Value(v) if found_key => {
|
||||||
values.push(v);
|
values.push(Cow::Borrowed(v.borrow()));
|
||||||
found_key = false;
|
found_key = false;
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
|
@ -399,9 +411,9 @@ impl<'a> GitConfig<'a> {
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// git_config.get_raw_multi_value("core", None, "a")?,
|
/// git_config.get_raw_multi_value("core", None, "a")?,
|
||||||
/// vec![
|
/// vec![
|
||||||
/// &Cow::Borrowed(b"b"),
|
/// Cow::Borrowed(b"b"),
|
||||||
/// &Cow::Borrowed(b"c"),
|
/// Cow::Borrowed(b"c"),
|
||||||
/// &Cow::Borrowed(b"d")
|
/// Cow::Borrowed(b"d")
|
||||||
/// ]
|
/// ]
|
||||||
/// );
|
/// );
|
||||||
/// for value in git_config.get_raw_multi_value_mut("core", None, "a")? {
|
/// for value in git_config.get_raw_multi_value_mut("core", None, "a")? {
|
||||||
|
@ -410,9 +422,9 @@ impl<'a> GitConfig<'a> {
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// git_config.get_raw_multi_value("core", None, "a")?,
|
/// git_config.get_raw_multi_value("core", None, "a")?,
|
||||||
/// vec![
|
/// vec![
|
||||||
/// &Cow::Borrowed(b"g"),
|
/// Cow::Borrowed(b"g"),
|
||||||
/// &Cow::Borrowed(b"g"),
|
/// Cow::Borrowed(b"g"),
|
||||||
/// &Cow::Borrowed(b"g")
|
/// Cow::Borrowed(b"g")
|
||||||
/// ],
|
/// ],
|
||||||
/// );
|
/// );
|
||||||
/// # Ok::<(), GitConfigError>(())
|
/// # Ok::<(), GitConfigError>(())
|
||||||
|
@ -526,7 +538,7 @@ impl<'a> GitConfig<'a> {
|
||||||
/// # use std::convert::TryFrom;
|
/// # use std::convert::TryFrom;
|
||||||
/// # let mut git_config = GitConfig::try_from("[core]a=b\n[core]\na=c\na=d").unwrap();
|
/// # let mut git_config = GitConfig::try_from("[core]a=b\n[core]\na=c\na=d").unwrap();
|
||||||
/// git_config.set_raw_value("core", None, "a", "e".as_bytes())?;
|
/// git_config.set_raw_value("core", None, "a", "e".as_bytes())?;
|
||||||
/// assert_eq!(git_config.get_raw_value("core", None, "a")?, &Cow::Borrowed(b"e"));
|
/// assert_eq!(git_config.get_raw_value("core", None, "a")?, Cow::Borrowed(b"e"));
|
||||||
/// # Ok::<(), GitConfigError>(())
|
/// # Ok::<(), GitConfigError>(())
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
@ -585,9 +597,9 @@ impl<'a> GitConfig<'a> {
|
||||||
/// ];
|
/// ];
|
||||||
/// git_config.set_raw_multi_value("core", None, "a", new_values.into_iter())?;
|
/// git_config.set_raw_multi_value("core", None, "a", new_values.into_iter())?;
|
||||||
/// let fetched_config = git_config.get_raw_multi_value("core", None, "a")?;
|
/// let fetched_config = git_config.get_raw_multi_value("core", None, "a")?;
|
||||||
/// assert!(fetched_config.contains(&&Cow::Borrowed(b"x")));
|
/// assert!(fetched_config.contains(&Cow::Borrowed(b"x")));
|
||||||
/// assert!(fetched_config.contains(&&Cow::Borrowed(b"y")));
|
/// assert!(fetched_config.contains(&Cow::Borrowed(b"y")));
|
||||||
/// assert!(fetched_config.contains(&&Cow::Borrowed(b"z")));
|
/// assert!(fetched_config.contains(&Cow::Borrowed(b"z")));
|
||||||
/// # Ok::<(), GitConfigError>(())
|
/// # Ok::<(), GitConfigError>(())
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
@ -604,8 +616,8 @@ impl<'a> GitConfig<'a> {
|
||||||
/// ];
|
/// ];
|
||||||
/// git_config.set_raw_multi_value("core", None, "a", new_values.into_iter())?;
|
/// git_config.set_raw_multi_value("core", None, "a", new_values.into_iter())?;
|
||||||
/// let fetched_config = git_config.get_raw_multi_value("core", None, "a")?;
|
/// let fetched_config = git_config.get_raw_multi_value("core", None, "a")?;
|
||||||
/// assert!(fetched_config.contains(&&Cow::Borrowed(b"x")));
|
/// assert!(fetched_config.contains(&Cow::Borrowed(b"x")));
|
||||||
/// assert!(fetched_config.contains(&&Cow::Borrowed(b"y")));
|
/// assert!(fetched_config.contains(&Cow::Borrowed(b"y")));
|
||||||
/// # Ok::<(), GitConfigError>(())
|
/// # Ok::<(), GitConfigError>(())
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
@ -623,7 +635,7 @@ impl<'a> GitConfig<'a> {
|
||||||
/// Cow::Borrowed(b"discarded"),
|
/// Cow::Borrowed(b"discarded"),
|
||||||
/// ];
|
/// ];
|
||||||
/// git_config.set_raw_multi_value("core", None, "a", new_values.into_iter())?;
|
/// git_config.set_raw_multi_value("core", None, "a", new_values.into_iter())?;
|
||||||
/// assert!(!git_config.get_raw_multi_value("core", None, "a")?.contains(&&Cow::Borrowed(b"discarded")));
|
/// assert!(!git_config.get_raw_multi_value("core", None, "a")?.contains(&Cow::Borrowed(b"discarded")));
|
||||||
/// # Ok::<(), GitConfigError>(())
|
/// # Ok::<(), GitConfigError>(())
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
@ -968,11 +980,11 @@ mod get_raw_value {
|
||||||
let config = GitConfig::try_from("[core]\na=b\nc=d").unwrap();
|
let config = GitConfig::try_from("[core]\na=b\nc=d").unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config.get_raw_value("core", None, "a"),
|
config.get_raw_value("core", None, "a"),
|
||||||
Ok(&Cow::<[u8]>::Borrowed(b"b"))
|
Ok(Cow::<[u8]>::Borrowed(b"b"))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config.get_raw_value("core", None, "c"),
|
config.get_raw_value("core", None, "c"),
|
||||||
Ok(&Cow::<[u8]>::Borrowed(b"d"))
|
Ok(Cow::<[u8]>::Borrowed(b"d"))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -981,7 +993,7 @@ mod get_raw_value {
|
||||||
let config = GitConfig::try_from("[core]\na=b\na=d").unwrap();
|
let config = GitConfig::try_from("[core]\na=b\na=d").unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config.get_raw_value("core", None, "a"),
|
config.get_raw_value("core", None, "a"),
|
||||||
Ok(&Cow::<[u8]>::Borrowed(b"d"))
|
Ok(Cow::<[u8]>::Borrowed(b"d"))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -990,7 +1002,7 @@ mod get_raw_value {
|
||||||
let config = GitConfig::try_from("[core]\na=b\n[core]\na=d").unwrap();
|
let config = GitConfig::try_from("[core]\na=b\n[core]\na=d").unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config.get_raw_value("core", None, "a"),
|
config.get_raw_value("core", None, "a"),
|
||||||
Ok(&Cow::<[u8]>::Borrowed(b"d"))
|
Ok(Cow::<[u8]>::Borrowed(b"d"))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1026,11 +1038,11 @@ mod get_raw_value {
|
||||||
let config = GitConfig::try_from("[core]a=b\n[core.a]a=c").unwrap();
|
let config = GitConfig::try_from("[core]a=b\n[core.a]a=c").unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config.get_raw_value("core", None, "a"),
|
config.get_raw_value("core", None, "a"),
|
||||||
Ok(&Cow::<[u8]>::Borrowed(b"b"))
|
Ok(Cow::<[u8]>::Borrowed(b"b"))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config.get_raw_value("core", Some("a"), "a"),
|
config.get_raw_value("core", Some("a"), "a"),
|
||||||
Ok(&Cow::<[u8]>::Borrowed(b"c"))
|
Ok(Cow::<[u8]>::Borrowed(b"c"))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1072,7 +1084,7 @@ mod get_raw_multi_value {
|
||||||
let config = GitConfig::try_from("[core]\na=b\na=c").unwrap();
|
let config = GitConfig::try_from("[core]\na=b\na=c").unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config.get_raw_multi_value("core", None, "a").unwrap(),
|
config.get_raw_multi_value("core", None, "a").unwrap(),
|
||||||
vec![&Cow::Borrowed(b"b"), &Cow::Borrowed(b"c")]
|
vec![Cow::Borrowed(b"b"), Cow::Borrowed(b"c")]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1082,9 +1094,9 @@ mod get_raw_multi_value {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config.get_raw_multi_value("core", None, "a").unwrap(),
|
config.get_raw_multi_value("core", None, "a").unwrap(),
|
||||||
vec![
|
vec![
|
||||||
&Cow::Borrowed(b"b"),
|
Cow::Borrowed(b"b"),
|
||||||
&Cow::Borrowed(b"c"),
|
Cow::Borrowed(b"c"),
|
||||||
&Cow::Borrowed(b"d")
|
Cow::Borrowed(b"d")
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1121,11 +1133,11 @@ mod get_raw_multi_value {
|
||||||
let config = GitConfig::try_from("[core]a=b\n[core.a]a=c").unwrap();
|
let config = GitConfig::try_from("[core]a=b\n[core.a]a=c").unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config.get_raw_multi_value("core", None, "a").unwrap(),
|
config.get_raw_multi_value("core", None, "a").unwrap(),
|
||||||
vec![&Cow::Borrowed(b"b")]
|
vec![Cow::Borrowed(b"b")]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config.get_raw_multi_value("core", Some("a"), "a").unwrap(),
|
config.get_raw_multi_value("core", Some("a"), "a").unwrap(),
|
||||||
vec![&Cow::Borrowed(b"c")]
|
vec![Cow::Borrowed(b"c")]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1135,9 +1147,9 @@ mod get_raw_multi_value {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config.get_raw_multi_value("core", None, "a").unwrap(),
|
config.get_raw_multi_value("core", None, "a").unwrap(),
|
||||||
vec![
|
vec![
|
||||||
&Cow::Borrowed(b"b"),
|
Cow::Borrowed(b"b"),
|
||||||
&Cow::Borrowed(b"c"),
|
Cow::Borrowed(b"c"),
|
||||||
&Cow::Borrowed(b"d")
|
Cow::Borrowed(b"d")
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
169
src/values.rs
169
src/values.rs
|
@ -152,6 +152,35 @@ impl<'a> From<&'a [u8]> for Value<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<String> for Value<'_> {
|
||||||
|
fn from(s: String) -> Self {
|
||||||
|
Self::from(s.into_bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<u8>> for Value<'_> {
|
||||||
|
fn from(s: Vec<u8>) -> Self {
|
||||||
|
if let Ok(int) = Integer::try_from(s.as_ref()) {
|
||||||
|
return Self::Integer(int);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(color) = Color::try_from(s.as_ref()) {
|
||||||
|
return Self::Color(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
Boolean::try_from(s).map_or_else(|v| Self::Other(Cow::Owned(v)), Self::Boolean)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<Cow<'a, [u8]>> for Value<'a> {
|
||||||
|
fn from(c: Cow<'a, [u8]>) -> Self {
|
||||||
|
match c {
|
||||||
|
Cow::Borrowed(c) => Self::from(c),
|
||||||
|
Cow::Owned(c) => Self::from(c),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// todo display for value
|
// todo display for value
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
|
@ -175,11 +204,11 @@ impl Serialize for Value<'_> {
|
||||||
/// documentation has a strict subset of values that may be interpreted as a
|
/// documentation has a strict subset of values that may be interpreted as a
|
||||||
/// boolean value, all of which are ASCII and thus UTF-8 representable.
|
/// boolean value, all of which are ASCII and thus UTF-8 representable.
|
||||||
/// Consequently, variants hold [`str`]s rather than [`[u8]`]s.
|
/// Consequently, variants hold [`str`]s rather than [`[u8]`]s.
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
|
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub enum Boolean<'a> {
|
pub enum Boolean<'a> {
|
||||||
True(TrueVariant<'a>),
|
True(TrueVariant<'a>),
|
||||||
False(&'a str),
|
False(Cow<'a, str>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TryFrom<&'a str> for Boolean<'a> {
|
impl<'a> TryFrom<&'a str> for Boolean<'a> {
|
||||||
|
@ -204,13 +233,48 @@ impl<'a> TryFrom<&'a [u8]> for Boolean<'a> {
|
||||||
|| value.eq_ignore_ascii_case(b"zero")
|
|| value.eq_ignore_ascii_case(b"zero")
|
||||||
|| value == b"\"\""
|
|| value == b"\"\""
|
||||||
{
|
{
|
||||||
return Ok(Self::False(std::str::from_utf8(value).unwrap()));
|
return Ok(Self::False(std::str::from_utf8(value).unwrap().into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<String> for Boolean<'_> {
|
||||||
|
type Error = String;
|
||||||
|
|
||||||
|
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||||
|
Self::try_from(value.into_bytes()).map_err(|v| String::from_utf8(v).unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Vec<u8>> for Boolean<'_> {
|
||||||
|
type Error = Vec<u8>;
|
||||||
|
|
||||||
|
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
|
||||||
|
if value.eq_ignore_ascii_case(b"no")
|
||||||
|
|| value.eq_ignore_ascii_case(b"off")
|
||||||
|
|| value.eq_ignore_ascii_case(b"false")
|
||||||
|
|| value.eq_ignore_ascii_case(b"zero")
|
||||||
|
|| value == b"\"\""
|
||||||
|
{
|
||||||
|
return Ok(Self::False(Cow::Owned(String::from_utf8(value).unwrap())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TrueVariant::try_from(value).map(Self::True)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TryFrom<Cow<'a, [u8]>> for Boolean<'a> {
|
||||||
|
type Error = ();
|
||||||
|
fn try_from(c: Cow<'a, [u8]>) -> Result<Self, Self::Error> {
|
||||||
|
match c {
|
||||||
|
Cow::Borrowed(c) => Self::try_from(c),
|
||||||
|
Cow::Owned(c) => Self::try_from(c).map_err(|_| ()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for Boolean<'_> {
|
impl Display for Boolean<'_> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
@ -245,10 +309,10 @@ impl Serialize for Boolean<'_> {
|
||||||
/// Discriminating enum between implicit and explicit truthy values.
|
/// Discriminating enum between implicit and explicit truthy values.
|
||||||
///
|
///
|
||||||
/// This enum is part of the [`Boolean`] struct.
|
/// This enum is part of the [`Boolean`] struct.
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
|
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub enum TrueVariant<'a> {
|
pub enum TrueVariant<'a> {
|
||||||
Explicit(&'a str),
|
Explicit(Cow<'a, str>),
|
||||||
/// For values defined without a `= <value>`.
|
/// For values defined without a `= <value>`.
|
||||||
Implicit,
|
Implicit,
|
||||||
}
|
}
|
||||||
|
@ -270,7 +334,7 @@ impl<'a> TryFrom<&'a [u8]> for TrueVariant<'a> {
|
||||||
|| value.eq_ignore_ascii_case(b"true")
|
|| value.eq_ignore_ascii_case(b"true")
|
||||||
|| value.eq_ignore_ascii_case(b"one")
|
|| value.eq_ignore_ascii_case(b"one")
|
||||||
{
|
{
|
||||||
Ok(Self::Explicit(std::str::from_utf8(value).unwrap()))
|
Ok(Self::Explicit(std::str::from_utf8(value).unwrap().into()))
|
||||||
} else if value.is_empty() {
|
} else if value.is_empty() {
|
||||||
Ok(Self::Implicit)
|
Ok(Self::Implicit)
|
||||||
} else {
|
} else {
|
||||||
|
@ -279,6 +343,34 @@ impl<'a> TryFrom<&'a [u8]> for TrueVariant<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<String> for TrueVariant<'_> {
|
||||||
|
type Error = String;
|
||||||
|
|
||||||
|
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||||
|
Self::try_from(value.into_bytes()).map_err(|v| String::from_utf8(v).unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Vec<u8>> for TrueVariant<'_> {
|
||||||
|
type Error = Vec<u8>;
|
||||||
|
|
||||||
|
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
|
||||||
|
if value.eq_ignore_ascii_case(b"yes")
|
||||||
|
|| value.eq_ignore_ascii_case(b"on")
|
||||||
|
|| value.eq_ignore_ascii_case(b"true")
|
||||||
|
|| value.eq_ignore_ascii_case(b"one")
|
||||||
|
{
|
||||||
|
Ok(Self::Explicit(Cow::Owned(
|
||||||
|
String::from_utf8(value).unwrap(),
|
||||||
|
)))
|
||||||
|
} else if value.is_empty() {
|
||||||
|
Ok(Self::Implicit)
|
||||||
|
} else {
|
||||||
|
Err(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for TrueVariant<'_> {
|
impl Display for TrueVariant<'_> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
if let Self::Explicit(v) = self {
|
if let Self::Explicit(v) = self {
|
||||||
|
@ -378,6 +470,24 @@ impl TryFrom<&[u8]> for Integer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Vec<u8>> for Integer {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
|
||||||
|
Self::try_from(value.as_ref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Cow<'_, [u8]>> for Integer {
|
||||||
|
type Error = ();
|
||||||
|
fn try_from(c: Cow<'_, [u8]>) -> Result<Self, Self::Error> {
|
||||||
|
match c {
|
||||||
|
Cow::Borrowed(c) => Self::try_from(c),
|
||||||
|
Cow::Owned(c) => Self::try_from(c).map_err(|_| ()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 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.
|
||||||
|
@ -445,6 +555,14 @@ impl TryFrom<&[u8]> for IntegerSuffix {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Vec<u8>> for IntegerSuffix {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
|
||||||
|
Self::try_from(value.as_ref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Any value that may contain a foreground color, background color, a
|
/// Any value that may contain a foreground color, background color, a
|
||||||
/// collection of color (text) modifiers, or a combination of any of the
|
/// collection of color (text) modifiers, or a combination of any of the
|
||||||
/// aforementioned values.
|
/// aforementioned values.
|
||||||
|
@ -565,6 +683,24 @@ impl TryFrom<&[u8]> for Color {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Vec<u8>> for Color {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
|
||||||
|
Self::try_from(value.as_ref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Cow<'_, [u8]>> for Color {
|
||||||
|
type Error = ();
|
||||||
|
fn try_from(c: Cow<'_, [u8]>) -> Result<Self, Self::Error> {
|
||||||
|
match c {
|
||||||
|
Cow::Borrowed(c) => Self::try_from(c),
|
||||||
|
Cow::Owned(c) => Self::try_from(c).map_err(|_| ()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 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
|
||||||
|
@ -870,30 +1006,33 @@ mod boolean {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn from_str_false() {
|
fn from_str_false() {
|
||||||
assert_eq!(Boolean::try_from("no"), Ok(Boolean::False("no")));
|
assert_eq!(Boolean::try_from("no"), Ok(Boolean::False("no".into())));
|
||||||
assert_eq!(Boolean::try_from("off"), Ok(Boolean::False("off")));
|
assert_eq!(Boolean::try_from("off"), Ok(Boolean::False("off".into())));
|
||||||
assert_eq!(Boolean::try_from("false"), Ok(Boolean::False("false")));
|
assert_eq!(
|
||||||
assert_eq!(Boolean::try_from("zero"), Ok(Boolean::False("zero")));
|
Boolean::try_from("false"),
|
||||||
assert_eq!(Boolean::try_from("\"\""), Ok(Boolean::False("\"\"")));
|
Ok(Boolean::False("false".into()))
|
||||||
|
);
|
||||||
|
assert_eq!(Boolean::try_from("zero"), Ok(Boolean::False("zero".into())));
|
||||||
|
assert_eq!(Boolean::try_from("\"\""), Ok(Boolean::False("\"\"".into())));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn from_str_true() {
|
fn from_str_true() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Boolean::try_from("yes"),
|
Boolean::try_from("yes"),
|
||||||
Ok(Boolean::True(TrueVariant::Explicit("yes")))
|
Ok(Boolean::True(TrueVariant::Explicit("yes".into())))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Boolean::try_from("on"),
|
Boolean::try_from("on"),
|
||||||
Ok(Boolean::True(TrueVariant::Explicit("on")))
|
Ok(Boolean::True(TrueVariant::Explicit("on".into())))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Boolean::try_from("true"),
|
Boolean::try_from("true"),
|
||||||
Ok(Boolean::True(TrueVariant::Explicit("true")))
|
Ok(Boolean::True(TrueVariant::Explicit("true".into())))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Boolean::try_from("one"),
|
Boolean::try_from("one"),
|
||||||
Ok(Boolean::True(TrueVariant::Explicit("one")))
|
Ok(Boolean::True(TrueVariant::Explicit("one".into())))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in a new issue