diff --git a/.gitignore b/.gitignore index 96ef6c0..53715f4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target Cargo.lock +tarpaulin-report.html \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 4229891..2a66f00 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "serde-git-config" +name = "git-config" version = "0.1.0" authors = ["Edward Shen "] edition = "2018" @@ -7,9 +7,16 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -serde = "1.0" nom = "6" bstr = "0.2.15" +[dependencies.serde_crate] +package = "serde" +optional = true +version = " 1" + [dev-dependencies] -serde_derive = "1.0" \ No newline at end of file +serde_derive = "1.0" + +[features] +serde = ["serde_crate"] diff --git a/src/config.rs b/src/config.rs index cc07526..1f4b1b1 100644 --- a/src/config.rs +++ b/src/config.rs @@ -336,7 +336,7 @@ impl<'a> GitConfig<'a> { .map(|vec| { // get_section_ids_by_name_and_subname is guaranteed to return // a non-empty vec, so max can never return empty. - *vec.into_iter().max().unwrap() + *vec.iter().max().unwrap() }) } @@ -517,7 +517,7 @@ impl<'a> GitConfig<'a> { if let Some(subsect_name) = subsection_name { for node in section_ids { if let LookupTreeNode::NonTerminal(subsection_lookup) = node { - maybe_ids = subsection_lookup.get(subsect_name.into()); + maybe_ids = subsection_lookup.get(subsect_name); break; } } diff --git a/src/error.rs b/src/error.rs index 74f15b3..6ffd9b1 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,5 +1,6 @@ use std::fmt::{self, Display}; +#[cfg(feature = "serde")] use serde::{de, ser}; pub type Result = std::result::Result; @@ -16,12 +17,14 @@ pub enum Error { InvalidBoolean(String), } +#[cfg(feature = "serde")] impl ser::Error for Error { fn custom(msg: T) -> Self { Error::Message(msg.to_string()) } } +#[cfg(feature = "serde")] impl de::Error for Error { fn custom(msg: T) -> Self { Error::Message(msg.to_string()) diff --git a/src/lib.rs b/src/lib.rs index d2384bf..71b65d2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,8 @@ #![forbid(unsafe_code)] +#[cfg(feature = "serde")] +extern crate serde_crate as serde; + // mod de; pub mod config; mod error; diff --git a/src/parser.rs b/src/parser.rs index a26cc8a..4c4f409 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -472,7 +472,7 @@ impl<'a> Parser<'a> { /// data succeeding valid `git-config` data. pub fn parse_from_str(input: &str) -> Result, ParserError> { let (i, frontmatter) = many0(alt(( - map(comment, |comment| Event::Comment(comment)), + map(comment, Event::Comment), map(take_spaces, |whitespace| { Event::Whitespace(Cow::Borrowed(whitespace.into())) }), @@ -492,7 +492,7 @@ pub fn parse_from_str(input: &str) -> Result, ParserError> { }) } -fn comment<'a>(i: &'a [u8]) -> IResult<&'a [u8], ParsedComment<'a>> { +fn comment(i: &[u8]) -> IResult<&[u8], ParsedComment> { let (i, comment_tag) = one_of(";#")(i)?; let (i, comment) = take_till(|c| c == b'\n')(i)?; Ok(( @@ -504,7 +504,7 @@ fn comment<'a>(i: &'a [u8]) -> IResult<&'a [u8], ParsedComment<'a>> { )) } -fn section<'a>(i: &'a [u8]) -> IResult<&'a [u8], ParsedSection<'a>> { +fn section(i: &[u8]) -> IResult<&[u8], ParsedSection> { let (i, section_header) = section_header(i)?; let (i, items) = many0(alt(( map(take_spaces, |space| { @@ -529,7 +529,7 @@ fn section<'a>(i: &'a [u8]) -> IResult<&'a [u8], ParsedSection<'a>> { )) } -fn section_header<'a>(i: &'a [u8]) -> IResult<&'a [u8], ParsedSectionHeader<'a>> { +fn section_header(i: &[u8]) -> IResult<&[u8], ParsedSectionHeader> { let (i, _) = char('[')(i)?; // No spaces must be between section name and section start let (i, name) = take_while(|c: u8| c.is_ascii_alphanumeric() || c == b'-' || c == b'.')(i)?; @@ -581,7 +581,7 @@ fn section_header<'a>(i: &'a [u8]) -> IResult<&'a [u8], ParsedSectionHeader<'a>> )) } -fn section_body<'a>(i: &'a [u8]) -> IResult<&'a [u8], (&'a [u8], Vec>)> { +fn section_body(i: &[u8]) -> IResult<&[u8], (&[u8], Vec)> { // maybe need to check for [ here let (i, name) = config_name(i)?; let (i, whitespace) = opt(take_spaces)(i)?; @@ -597,7 +597,7 @@ fn section_body<'a>(i: &'a [u8]) -> IResult<&'a [u8], (&'a [u8], Vec>) /// Parses the config name of a config pair. Assumes the input has already been /// trimmed of any leading whitespace. -fn config_name<'a>(i: &'a [u8]) -> IResult<&'a [u8], &'a [u8]> { +fn config_name(i: &[u8]) -> IResult<&[u8], &[u8]> { if i.is_empty() { return Err(nom::Err::Error(NomError { input: i, @@ -615,7 +615,7 @@ fn config_name<'a>(i: &'a [u8]) -> IResult<&'a [u8], &'a [u8]> { take_while(|c: u8| (c as char).is_alphanumeric() || c == b'-')(i) } -fn config_value<'a>(i: &'a [u8]) -> IResult<&'a [u8], Vec>> { +fn config_value(i: &[u8]) -> IResult<&[u8], Vec> { if let (i, Some(_)) = opt(char('='))(i)? { let mut events = vec![]; events.push(Event::KeyValueSeparator); @@ -631,7 +631,7 @@ fn config_value<'a>(i: &'a [u8]) -> IResult<&'a [u8], Vec>> { } } -fn value_impl<'a>(i: &'a [u8]) -> IResult<&'a [u8], Vec>> { +fn value_impl(i: &[u8]) -> IResult<&[u8], Vec> { let mut events = vec![]; let mut parsed_index: usize = 0; let mut offset: usize = 0; @@ -722,11 +722,11 @@ fn value_impl<'a>(i: &'a [u8]) -> IResult<&'a [u8], Vec>> { Ok((i, events)) } -fn take_spaces<'a>(i: &'a [u8]) -> IResult<&'a [u8], &'a [u8]> { +fn take_spaces(i: &[u8]) -> IResult<&[u8], &[u8]> { take_common(i, |c| (c as char).is_ascii() && is_space(c)) } -fn take_newline<'a>(i: &'a [u8]) -> IResult<&'a [u8], &'a [u8]> { +fn take_newline(i: &[u8]) -> IResult<&[u8], &[u8]> { take_common(i, is_char_newline) } @@ -734,7 +734,7 @@ fn is_char_newline(c: u8) -> bool { (c as char).is_ascii() && is_newline(c) } -fn take_common<'a, F: Fn(u8) -> bool>(i: &'a [u8], f: F) -> IResult<&'a [u8], &'a [u8]> { +fn take_common bool>(i: &[u8], f: F) -> IResult<&[u8], &[u8]> { let (i, v) = take_while(f)(i)?; if v.is_empty() { Err(nom::Err::Error(NomError { diff --git a/src/test_util.rs b/src/test_util.rs index cdcf1ca..5100eb9 100644 --- a/src/test_util.rs +++ b/src/test_util.rs @@ -57,10 +57,6 @@ pub(crate) fn whitespace_event(value: &'static str) -> Event<'static> { Event::Whitespace(Cow::Borrowed(value.into())) } -pub(crate) fn separator_event() -> Event<'static> { - Event::KeyValueSeparator -} - pub(crate) fn comment_event(tag: char, msg: &'static str) -> Event<'static> { Event::Comment(comment(tag, msg)) } diff --git a/src/values.rs b/src/values.rs index b88f6c4..c677c8e 100644 --- a/src/values.rs +++ b/src/values.rs @@ -1,5 +1,6 @@ use std::{borrow::Cow, fmt::Display, str::FromStr}; +#[cfg(feature = "serde")] use serde::{Serialize, Serializer}; #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] @@ -20,9 +21,9 @@ impl<'a> Value<'a> { return Self::Integer(int); } - // if let Ok(color) = Color::from_str(s) { - // return Self::Color(color); - // } + if let Ok(color) = Color::from_str(s) { + return Self::Color(color); + } Self::Other(Cow::Borrowed(s)) } @@ -34,6 +35,7 @@ impl<'a> Value<'a> { // todo display for value +#[cfg(feature = "serde")] impl Serialize for Value<'_> { fn serialize(&self, serializer: S) -> Result where @@ -68,8 +70,16 @@ impl<'a> Boolean<'a> { } } -// todo: Display for boolean +impl Display for Boolean<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Boolean::True(v) => v.fmt(f), + Boolean::False(v) => v.fmt(f), + } + } +} +#[cfg(feature = "serde")] impl Serialize for Boolean<'_> { fn serialize(&self, serializer: S) -> Result where @@ -116,6 +126,7 @@ impl Display for TrueVariant<'_> { } } +#[cfg(feature = "serde")] impl Serialize for TrueVariant<'_> { fn serialize(&self, serializer: S) -> Result where @@ -149,6 +160,7 @@ impl Display for FalseVariant<'_> { } } +#[cfg(feature = "serde")] impl Serialize for FalseVariant<'_> { fn serialize(&self, serializer: S) -> Result where @@ -175,6 +187,7 @@ impl Display for Integer { } } +#[cfg(feature = "serde")] impl Serialize for Integer { fn serialize(&self, serializer: S) -> Result where @@ -191,7 +204,7 @@ impl Serialize for Integer { impl FromStr for Integer { type Err = String; - fn from_str<'a>(s: &'a str) -> Result { + fn from_str(s: &str) -> Result { if let Ok(value) = s.parse() { return Ok(Self { value, @@ -244,6 +257,7 @@ impl Display for IntegerSuffix { } } +#[cfg(feature = "serde")] impl Serialize for IntegerSuffix { fn serialize(&self, serializer: S) -> Result where @@ -291,16 +305,17 @@ impl Display for Color { self.attributes .iter() - .map(|attr| write!(f, " ").and_then(|_| attr.fmt(f))) - .collect::>() + .try_for_each(|attr| write!(f, " ").and_then(|_| attr.fmt(f))) } } +#[cfg(feature = "serde")] impl Serialize for Color { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { + // todo: maybe not? serializer.serialize_str(&self.to_string()) } } @@ -403,6 +418,7 @@ impl Display for ColorValue { } } +#[cfg(feature = "serde")] impl Serialize for ColorValue { fn serialize(&self, serializer: S) -> Result where @@ -450,8 +466,7 @@ impl FromStr for ColorValue { return Ok(Self::Ansi(v)); } - if s.starts_with("#") { - let s = &s[1..]; + if let Some(s) = s.strip_prefix('#') { if s.len() == 6 { let rgb = ( u8::from_str_radix(&s[..2], 16), @@ -508,6 +523,7 @@ impl Display for ColorAttribute { } } +#[cfg(feature = "serde")] impl Serialize for ColorAttribute { fn serialize(&self, serializer: S) -> Result where @@ -542,7 +558,7 @@ impl FromStr for ColorAttribute { if inverted { parsed = &parsed[2..]; - if parsed.starts_with("-") { + if parsed.starts_with('-') { parsed = &parsed[1..]; } } diff --git a/tests/parser_integration_tests.rs b/tests/parser_integration_tests.rs index c0aadb7..93ef1c7 100644 --- a/tests/parser_integration_tests.rs +++ b/tests/parser_integration_tests.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; -use serde_git_config::parser::{parse_from_str, Event, ParsedSectionHeader}; +use git_config::parser::{parse_from_str, Event, ParsedSectionHeader}; pub fn section_header_event( name: &str,