Use traits instead of shadowing from_str

This commit is contained in:
Edward Shen 2021-02-26 21:32:37 -05:00
parent 781040a88b
commit a50544b43a
Signed by: edward
GPG key ID: 19182661E818369F
4 changed files with 46 additions and 24 deletions

View file

@ -3,6 +3,7 @@
"Multivar", "Multivar",
"autocrlf", "autocrlf",
"bstr", "bstr",
"combinator",
"gitea", "gitea",
"gpgsign", "gpgsign",
"implicits", "implicits",

View file

@ -1,5 +1,14 @@
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
//! # git_config
//!
//! This crate is a high performance `git-config` file reader and writer. It
//! exposes a high level API to parse, read, and write [`git-config` files],
//! which are loosely based on the [INI file format].
//!
//! [`git-config` files]: https://git-scm.com/docs/git-config#_configuration_file
//! [INI file format]: https://en.wikipedia.org/wiki/INI_file
// Cargo.toml cannot have self-referential dependencies, so you can't just // Cargo.toml cannot have self-referential dependencies, so you can't just
// specify the actual serde crate when you define a feature called serde. We // specify the actual serde crate when you define a feature called serde. We
// instead call the serde crate as serde_crate and then rename the crate to // instead call the serde crate as serde_crate and then rename the crate to

View file

@ -790,6 +790,13 @@ fn config_value<'a, 'b>(i: &'a [u8], events: &'b mut Vec<Event<'a>>) -> IResult<
} }
} }
/// Handles parsing of known-to-be values. This function handles both single
/// line values as well as values that are continuations.
///
/// # Errors
///
/// Returns an error if an invalid escape was used, if there was an unfinished
/// quote, or there was an escape but there is nothing left to escape.
fn value_impl<'a, 'b>(i: &'a [u8], events: &'b mut Vec<Event<'a>>) -> IResult<&'a [u8], ()> { fn value_impl<'a, 'b>(i: &'a [u8], events: &'b mut Vec<Event<'a>>) -> IResult<&'a [u8], ()> {
let mut parsed_index: usize = 0; let mut parsed_index: usize = 0;
let mut offset: usize = 0; let mut offset: usize = 0;

View file

@ -1,6 +1,6 @@
//! Rust containers for valid `git-config` types. //! Rust containers for valid `git-config` types.
use std::{borrow::Cow, fmt::Display, str::FromStr}; use std::{borrow::Cow, convert::TryFrom, fmt::Display, str::FromStr};
use bstr::BStr; use bstr::BStr;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
@ -27,7 +27,7 @@ impl<'a> Value<'a> {
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::from_str(s) { if let Ok(bool) = Boolean::try_from(s) {
return Self::Boolean(bool); return Self::Boolean(bool);
} }
@ -66,9 +66,11 @@ pub enum Boolean<'a> {
False(&'a str), False(&'a str),
} }
impl<'a> Boolean<'a> { impl<'a> TryFrom<&'a str> for Boolean<'a> {
pub fn from_str(value: &'a str) -> Result<Self, ()> { type Error = ();
if let Ok(v) = TrueVariant::from_str(value) {
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
if let Ok(v) = TrueVariant::try_from(value) {
return Ok(Self::True(v)); return Ok(Self::True(v));
} }
@ -89,7 +91,7 @@ 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 {
Boolean::True(v) => v.fmt(f), Boolean::True(v) => v.fmt(f),
Boolean::False(v) => v.fmt(f), Boolean::False(v) => write!(f, "{}", v),
} }
} }
} }
@ -126,8 +128,10 @@ pub enum TrueVariant<'a> {
Implicit, Implicit,
} }
impl<'a> TrueVariant<'a> { impl<'a> TryFrom<&'a str> for TrueVariant<'a> {
pub fn from_str(value: &'a str) -> Result<TrueVariant<'a>, ()> { type Error = ();
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
if value.eq_ignore_ascii_case("yes") if value.eq_ignore_ascii_case("yes")
|| value.eq_ignore_ascii_case("on") || value.eq_ignore_ascii_case("on")
|| value.eq_ignore_ascii_case("true") || value.eq_ignore_ascii_case("true")
@ -221,14 +225,15 @@ impl FromStr for Integer {
} }
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
enum IntegerSuffix { pub enum IntegerSuffix {
Kilo, Kilo,
Mega, Mega,
Giga, Giga,
} }
impl IntegerSuffix { impl IntegerSuffix {
fn bitwise_offset(&self) -> usize { /// Returns the number of bits that the suffix shifts left by.
pub fn bitwise_offset(&self) -> usize {
match self { match self {
Self::Kilo => 10, Self::Kilo => 10,
Self::Mega => 20, Self::Mega => 20,
@ -579,29 +584,29 @@ mod boolean {
#[test] #[test]
fn from_str_false() { fn from_str_false() {
assert_eq!(Boolean::from_str("no"), Ok(Boolean::False("no"))); assert_eq!(Boolean::try_from("no"), Ok(Boolean::False("no")));
assert_eq!(Boolean::from_str("off"), Ok(Boolean::False("off"))); assert_eq!(Boolean::try_from("off"), Ok(Boolean::False("off")));
assert_eq!(Boolean::from_str("false"), Ok(Boolean::False("false"))); assert_eq!(Boolean::try_from("false"), Ok(Boolean::False("false")));
assert_eq!(Boolean::from_str("zero"), Ok(Boolean::False("zero"))); assert_eq!(Boolean::try_from("zero"), Ok(Boolean::False("zero")));
assert_eq!(Boolean::from_str("\"\""), Ok(Boolean::False("\"\""))); assert_eq!(Boolean::try_from("\"\""), Ok(Boolean::False("\"\"")));
} }
#[test] #[test]
fn from_str_true() { fn from_str_true() {
assert_eq!( assert_eq!(
Boolean::from_str("yes"), Boolean::try_from("yes"),
Ok(Boolean::True(TrueVariant::Explicit("yes"))) Ok(Boolean::True(TrueVariant::Explicit("yes")))
); );
assert_eq!( assert_eq!(
Boolean::from_str("on"), Boolean::try_from("on"),
Ok(Boolean::True(TrueVariant::Explicit("on"))) Ok(Boolean::True(TrueVariant::Explicit("on")))
); );
assert_eq!( assert_eq!(
Boolean::from_str("true"), Boolean::try_from("true"),
Ok(Boolean::True(TrueVariant::Explicit("true"))) Ok(Boolean::True(TrueVariant::Explicit("true")))
); );
assert_eq!( assert_eq!(
Boolean::from_str("one"), Boolean::try_from("one"),
Ok(Boolean::True(TrueVariant::Explicit("one"))) Ok(Boolean::True(TrueVariant::Explicit("one")))
); );
} }
@ -610,17 +615,17 @@ mod boolean {
fn ignores_case() { fn ignores_case() {
// Random subset // Random subset
for word in &["no", "yes", "off", "true", "zero"] { for word in &["no", "yes", "off", "true", "zero"] {
let first: bool = Boolean::from_str(word).unwrap().into(); let first: bool = Boolean::try_from(*word).unwrap().into();
let second: bool = Boolean::from_str(&word.to_uppercase()).unwrap().into(); let second: bool = Boolean::try_from(&*word.to_uppercase()).unwrap().into();
assert_eq!(first, second); assert_eq!(first, second);
} }
} }
#[test] #[test]
fn from_str_err() { fn from_str_err() {
assert!(Boolean::from_str("yesn't").is_err()); assert!(Boolean::try_from("yesn't").is_err());
assert!(Boolean::from_str("yesno").is_err()); assert!(Boolean::try_from("yesno").is_err());
assert!(Boolean::from_str("").is_err()); assert!(Boolean::try_from("").is_err());
} }
} }