Use traits instead of from_str
This commit is contained in:
parent
a50544b43a
commit
3e97f07b28
2 changed files with 146 additions and 147 deletions
245
src/config.rs
245
src/config.rs
|
@ -1,9 +1,10 @@
|
||||||
use crate::parser::{parse_from_str, Event, ParsedSectionHeader, Parser, ParserError};
|
use crate::parser::{parse_from_bytes, Event, ParsedSectionHeader, Parser, ParserError};
|
||||||
use bstr::BStr;
|
use bstr::BStr;
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
|
use std::convert::TryFrom;
|
||||||
use std::{borrow::Cow, fmt::Display};
|
use std::{borrow::Cow, fmt::Display};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[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.
|
||||||
SectionDoesNotExist(&'a BStr),
|
SectionDoesNotExist(&'a BStr),
|
||||||
|
@ -13,21 +14,6 @@ pub enum GitConfigError<'a> {
|
||||||
KeyDoesNotExist(&'a BStr),
|
KeyDoesNotExist(&'a BStr),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// High level `git-config` reader and writer.
|
|
||||||
pub struct GitConfig<'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
|
|
||||||
/// comment, newline, and whitespace events.
|
|
||||||
front_matter_events: Vec<Event<'a>>,
|
|
||||||
section_lookup_tree: HashMap<Cow<'a, BStr>, Vec<LookupTreeNode<'a>>>,
|
|
||||||
/// SectionId to section mapping. The value of this HashMap contains actual
|
|
||||||
/// events
|
|
||||||
sections: HashMap<SectionId, Vec<Event<'a>>>,
|
|
||||||
section_headers: HashMap<SectionId, ParsedSectionHeader<'a>>,
|
|
||||||
section_id_counter: usize,
|
|
||||||
section_order: VecDeque<SectionId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The section ID is a monotonically increasing ID used to refer to sections.
|
/// The section ID is a monotonically increasing ID used to refer to sections.
|
||||||
/// This value does not imply any ordering between sections, as new sections
|
/// This value does not imply any ordering between sections, as new sections
|
||||||
/// with higher section IDs may be in between lower ID sections.
|
/// with higher section IDs may be in between lower ID sections.
|
||||||
|
@ -42,85 +28,28 @@ pub struct GitConfig<'a> {
|
||||||
#[derive(PartialEq, Eq, Hash, Copy, Clone, PartialOrd, Ord, Debug)]
|
#[derive(PartialEq, Eq, Hash, Copy, Clone, PartialOrd, Ord, Debug)]
|
||||||
struct SectionId(usize);
|
struct SectionId(usize);
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||||
enum LookupTreeNode<'a> {
|
enum LookupTreeNode<'a> {
|
||||||
Terminal(Vec<SectionId>),
|
Terminal(Vec<SectionId>),
|
||||||
NonTerminal(HashMap<Cow<'a, BStr>, Vec<SectionId>>),
|
NonTerminal(HashMap<Cow<'a, BStr>, Vec<SectionId>>),
|
||||||
}
|
}
|
||||||
|
/// High level `git-config` reader and writer.
|
||||||
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||||
|
pub struct GitConfig<'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
|
||||||
|
/// comment, newline, and whitespace events.
|
||||||
|
front_matter_events: Vec<Event<'a>>,
|
||||||
|
section_lookup_tree: HashMap<Cow<'a, BStr>, Vec<LookupTreeNode<'a>>>,
|
||||||
|
/// SectionId to section mapping. The value of this HashMap contains actual
|
||||||
|
/// events
|
||||||
|
sections: HashMap<SectionId, Vec<Event<'a>>>,
|
||||||
|
section_headers: HashMap<SectionId, ParsedSectionHeader<'a>>,
|
||||||
|
section_id_counter: usize,
|
||||||
|
section_order: VecDeque<SectionId>,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> GitConfig<'a> {
|
impl<'a> GitConfig<'a> {
|
||||||
/// Convenience constructor. Attempts to parse the provided string into a
|
|
||||||
/// [`GitConfig`]. See [`parse_from_str`] for more information.
|
|
||||||
///
|
|
||||||
/// [`parse_from_str`]: crate::parser::parse_from_str
|
|
||||||
pub fn from_str(str: &'a str) -> Result<Self, ParserError> {
|
|
||||||
Ok(Self::from_parser(parse_from_str(str)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_parser(parser: Parser<'a>) -> Self {
|
|
||||||
let mut new_self = Self {
|
|
||||||
front_matter_events: vec![],
|
|
||||||
sections: HashMap::new(),
|
|
||||||
section_lookup_tree: HashMap::new(),
|
|
||||||
section_headers: HashMap::new(),
|
|
||||||
section_id_counter: 0,
|
|
||||||
section_order: VecDeque::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Current section that we're building
|
|
||||||
let mut current_section_name: Option<Cow<'a, BStr>> = None;
|
|
||||||
let mut current_subsection_name: Option<Cow<'a, BStr>> = None;
|
|
||||||
let mut maybe_section: Option<Vec<Event<'a>>> = None;
|
|
||||||
|
|
||||||
for event in parser.into_iter() {
|
|
||||||
match event {
|
|
||||||
Event::SectionHeader(header) => {
|
|
||||||
new_self.push_section(
|
|
||||||
current_section_name,
|
|
||||||
current_subsection_name,
|
|
||||||
&mut maybe_section,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Initialize new section
|
|
||||||
// We need to store the new, current id counter, so don't
|
|
||||||
// use new_section_id here and use the already incremented
|
|
||||||
// section id value.
|
|
||||||
new_self
|
|
||||||
.section_headers
|
|
||||||
.insert(SectionId(new_self.section_id_counter), header.clone());
|
|
||||||
let (name, subname) = (header.name, header.subsection_name);
|
|
||||||
maybe_section = Some(vec![]);
|
|
||||||
current_section_name = Some(name);
|
|
||||||
current_subsection_name = subname;
|
|
||||||
}
|
|
||||||
e @ Event::Key(_)
|
|
||||||
| e @ Event::Value(_)
|
|
||||||
| e @ Event::ValueNotDone(_)
|
|
||||||
| e @ Event::ValueDone(_)
|
|
||||||
| e @ Event::KeyValueSeparator => maybe_section
|
|
||||||
.as_mut()
|
|
||||||
.expect("Got a section-only event before a section")
|
|
||||||
.push(e),
|
|
||||||
e @ Event::Comment(_) | e @ Event::Newline(_) | e @ Event::Whitespace(_) => {
|
|
||||||
match maybe_section {
|
|
||||||
Some(ref mut section) => section.push(e),
|
|
||||||
None => new_self.front_matter_events.push(e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The last section doesn't get pushed since we only push if there's a
|
|
||||||
// new section header, so we need to call push one more time.
|
|
||||||
new_self.push_section(
|
|
||||||
current_section_name,
|
|
||||||
current_subsection_name,
|
|
||||||
&mut maybe_section,
|
|
||||||
);
|
|
||||||
|
|
||||||
new_self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_section(
|
fn push_section(
|
||||||
&mut self,
|
&mut self,
|
||||||
current_section_name: Option<Cow<'a, BStr>>,
|
current_section_name: Option<Cow<'a, BStr>>,
|
||||||
|
@ -574,9 +503,93 @@ impl<'a> GitConfig<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> TryFrom<&'a str> for GitConfig<'a> {
|
||||||
|
type Error = ParserError<'a>;
|
||||||
|
|
||||||
|
/// Convenience constructor. Attempts to parse the provided string into a
|
||||||
|
/// [`GitConfig`]. See [`parse_from_str`] for more information.
|
||||||
|
///
|
||||||
|
/// [`parse_from_str`]: crate::parser::parse_from_str
|
||||||
|
fn try_from(s: &'a str) -> Result<Self, Self::Error> {
|
||||||
|
parse_from_bytes(s.as_bytes()).map(Self::from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TryFrom<&'a BStr> for GitConfig<'a> {
|
||||||
|
type Error = ParserError<'a>;
|
||||||
|
|
||||||
|
/// Convenience constructor. Attempts to parse the provided byte string into
|
||||||
|
//// a [`GitConfig`]. See [`parse_from_bytes`] for more information.
|
||||||
|
///
|
||||||
|
/// [`parse_from_bytes`]: crate::parser::parse_from_bytes
|
||||||
|
fn try_from(value: &'a BStr) -> Result<Self, Self::Error> {
|
||||||
|
parse_from_bytes(value).map(Self::from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> From<Parser<'a>> for GitConfig<'a> {
|
impl<'a> From<Parser<'a>> for GitConfig<'a> {
|
||||||
fn from(p: Parser<'a>) -> Self {
|
fn from(parser: Parser<'a>) -> Self {
|
||||||
Self::from_parser(p)
|
let mut new_self = Self {
|
||||||
|
front_matter_events: vec![],
|
||||||
|
sections: HashMap::new(),
|
||||||
|
section_lookup_tree: HashMap::new(),
|
||||||
|
section_headers: HashMap::new(),
|
||||||
|
section_id_counter: 0,
|
||||||
|
section_order: VecDeque::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Current section that we're building
|
||||||
|
let mut current_section_name: Option<Cow<'a, BStr>> = None;
|
||||||
|
let mut current_subsection_name: Option<Cow<'a, BStr>> = None;
|
||||||
|
let mut maybe_section: Option<Vec<Event<'a>>> = None;
|
||||||
|
|
||||||
|
for event in parser.into_iter() {
|
||||||
|
match event {
|
||||||
|
Event::SectionHeader(header) => {
|
||||||
|
new_self.push_section(
|
||||||
|
current_section_name,
|
||||||
|
current_subsection_name,
|
||||||
|
&mut maybe_section,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Initialize new section
|
||||||
|
// We need to store the new, current id counter, so don't
|
||||||
|
// use new_section_id here and use the already incremented
|
||||||
|
// section id value.
|
||||||
|
new_self
|
||||||
|
.section_headers
|
||||||
|
.insert(SectionId(new_self.section_id_counter), header.clone());
|
||||||
|
let (name, subname) = (header.name, header.subsection_name);
|
||||||
|
maybe_section = Some(vec![]);
|
||||||
|
current_section_name = Some(name);
|
||||||
|
current_subsection_name = subname;
|
||||||
|
}
|
||||||
|
e @ Event::Key(_)
|
||||||
|
| e @ Event::Value(_)
|
||||||
|
| e @ Event::ValueNotDone(_)
|
||||||
|
| e @ Event::ValueDone(_)
|
||||||
|
| e @ Event::KeyValueSeparator => maybe_section
|
||||||
|
.as_mut()
|
||||||
|
.expect("Got a section-only event before a section")
|
||||||
|
.push(e),
|
||||||
|
e @ Event::Comment(_) | e @ Event::Newline(_) | e @ Event::Whitespace(_) => {
|
||||||
|
match maybe_section {
|
||||||
|
Some(ref mut section) => section.push(e),
|
||||||
|
None => new_self.front_matter_events.push(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The last section doesn't get pushed since we only push if there's a
|
||||||
|
// new section header, so we need to call push one more time.
|
||||||
|
new_self.push_section(
|
||||||
|
current_section_name,
|
||||||
|
current_subsection_name,
|
||||||
|
&mut maybe_section,
|
||||||
|
);
|
||||||
|
|
||||||
|
new_self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -606,7 +619,7 @@ mod from_parser {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_empty() {
|
fn parse_empty() {
|
||||||
let config = GitConfig::from_str("").unwrap();
|
let config = GitConfig::try_from("").unwrap();
|
||||||
assert!(config.section_headers.is_empty());
|
assert!(config.section_headers.is_empty());
|
||||||
assert_eq!(config.section_id_counter, 0);
|
assert_eq!(config.section_id_counter, 0);
|
||||||
assert!(config.section_lookup_tree.is_empty());
|
assert!(config.section_lookup_tree.is_empty());
|
||||||
|
@ -616,7 +629,7 @@ mod from_parser {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_single_section() {
|
fn parse_single_section() {
|
||||||
let mut config = GitConfig::from_str("[core]\na=b\nc=d").unwrap();
|
let mut config = GitConfig::try_from("[core]\na=b\nc=d").unwrap();
|
||||||
let expected_separators = {
|
let expected_separators = {
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
map.insert(SectionId(0), section_header("core", None));
|
map.insert(SectionId(0), section_header("core", None));
|
||||||
|
@ -656,7 +669,7 @@ mod from_parser {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_single_subsection() {
|
fn parse_single_subsection() {
|
||||||
let mut config = GitConfig::from_str("[core.subsec]\na=b\nc=d").unwrap();
|
let mut config = GitConfig::try_from("[core.subsec]\na=b\nc=d").unwrap();
|
||||||
let expected_separators = {
|
let expected_separators = {
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
map.insert(SectionId(0), section_header("core", (".", "subsec")));
|
map.insert(SectionId(0), section_header("core", (".", "subsec")));
|
||||||
|
@ -698,7 +711,7 @@ mod from_parser {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_multiple_sections() {
|
fn parse_multiple_sections() {
|
||||||
let mut config = GitConfig::from_str("[core]\na=b\nc=d\n[other]e=f").unwrap();
|
let mut config = GitConfig::try_from("[core]\na=b\nc=d\n[other]e=f").unwrap();
|
||||||
let expected_separators = {
|
let expected_separators = {
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
map.insert(SectionId(0), section_header("core", None));
|
map.insert(SectionId(0), section_header("core", None));
|
||||||
|
@ -751,7 +764,7 @@ mod from_parser {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_multiple_duplicate_sections() {
|
fn parse_multiple_duplicate_sections() {
|
||||||
let mut config = GitConfig::from_str("[core]\na=b\nc=d\n[core]e=f").unwrap();
|
let mut config = GitConfig::try_from("[core]\na=b\nc=d\n[core]e=f").unwrap();
|
||||||
let expected_separators = {
|
let expected_separators = {
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
map.insert(SectionId(0), section_header("core", None));
|
map.insert(SectionId(0), section_header("core", None));
|
||||||
|
@ -805,7 +818,7 @@ mod get_raw_value {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn single_section() {
|
fn single_section() {
|
||||||
let config = GitConfig::from_str("[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::Borrowed("b".into()))
|
Ok(&Cow::Borrowed("b".into()))
|
||||||
|
@ -818,7 +831,7 @@ mod get_raw_value {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn last_one_wins_respected_in_section() {
|
fn last_one_wins_respected_in_section() {
|
||||||
let config = GitConfig::from_str("[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::Borrowed("d".into()))
|
Ok(&Cow::Borrowed("d".into()))
|
||||||
|
@ -827,7 +840,7 @@ mod get_raw_value {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn last_one_wins_respected_across_section() {
|
fn last_one_wins_respected_across_section() {
|
||||||
let config = GitConfig::from_str("[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::Borrowed("d".into()))
|
Ok(&Cow::Borrowed("d".into()))
|
||||||
|
@ -836,7 +849,7 @@ mod get_raw_value {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn section_not_found() {
|
fn section_not_found() {
|
||||||
let config = GitConfig::from_str("[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("foo", None, "a"),
|
config.get_raw_value("foo", None, "a"),
|
||||||
Err(GitConfigError::SectionDoesNotExist("foo".into()))
|
Err(GitConfigError::SectionDoesNotExist("foo".into()))
|
||||||
|
@ -845,7 +858,7 @@ mod get_raw_value {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn subsection_not_found() {
|
fn subsection_not_found() {
|
||||||
let config = GitConfig::from_str("[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", Some("a"), "a"),
|
config.get_raw_value("core", Some("a"), "a"),
|
||||||
Err(GitConfigError::SubSectionDoesNotExist(Some("a".into())))
|
Err(GitConfigError::SubSectionDoesNotExist(Some("a".into())))
|
||||||
|
@ -854,7 +867,7 @@ mod get_raw_value {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn key_not_found() {
|
fn key_not_found() {
|
||||||
let config = GitConfig::from_str("[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, "aaaaaa"),
|
config.get_raw_value("core", None, "aaaaaa"),
|
||||||
Err(GitConfigError::KeyDoesNotExist("aaaaaa".into()))
|
Err(GitConfigError::KeyDoesNotExist("aaaaaa".into()))
|
||||||
|
@ -863,7 +876,7 @@ mod get_raw_value {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn subsection_must_be_respected() {
|
fn subsection_must_be_respected() {
|
||||||
let config = GitConfig::from_str("[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::Borrowed("b".into()))
|
Ok(&Cow::Borrowed("b".into()))
|
||||||
|
@ -881,7 +894,7 @@ mod get_raw_multi_value {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn single_value_is_identical_to_single_value_query() {
|
fn single_value_is_identical_to_single_value_query() {
|
||||||
let config = GitConfig::from_str("[core]\na=b\nc=d").unwrap();
|
let config = GitConfig::try_from("[core]\na=b\nc=d").unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
vec![config.get_raw_value("core", None, "a").unwrap()],
|
vec![config.get_raw_value("core", None, "a").unwrap()],
|
||||||
config.get_raw_multi_value("core", None, "a").unwrap()
|
config.get_raw_multi_value("core", None, "a").unwrap()
|
||||||
|
@ -890,7 +903,7 @@ mod get_raw_multi_value {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn multi_value_in_section() {
|
fn multi_value_in_section() {
|
||||||
let config = GitConfig::from_str("[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"), &Cow::Borrowed("c")]
|
vec![&Cow::Borrowed("b"), &Cow::Borrowed("c")]
|
||||||
|
@ -899,7 +912,7 @@ mod get_raw_multi_value {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn multi_value_across_sections() {
|
fn multi_value_across_sections() {
|
||||||
let config = GitConfig::from_str("[core]\na=b\na=c\n[core]a=d").unwrap();
|
let config = GitConfig::try_from("[core]\na=b\na=c\n[core]a=d").unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config.get_raw_multi_value("core", None, "a").unwrap(),
|
config.get_raw_multi_value("core", None, "a").unwrap(),
|
||||||
vec![
|
vec![
|
||||||
|
@ -912,7 +925,7 @@ mod get_raw_multi_value {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn section_not_found() {
|
fn section_not_found() {
|
||||||
let config = GitConfig::from_str("[core]\na=b\nc=d").unwrap();
|
let config = GitConfig::try_from("[core]\na=b\nc=d").unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config.get_raw_multi_value("foo", None, "a"),
|
config.get_raw_multi_value("foo", None, "a"),
|
||||||
Err(GitConfigError::SectionDoesNotExist("foo".into()))
|
Err(GitConfigError::SectionDoesNotExist("foo".into()))
|
||||||
|
@ -921,7 +934,7 @@ mod get_raw_multi_value {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn subsection_not_found() {
|
fn subsection_not_found() {
|
||||||
let config = GitConfig::from_str("[core]\na=b\nc=d").unwrap();
|
let config = GitConfig::try_from("[core]\na=b\nc=d").unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config.get_raw_multi_value("core", Some("a"), "a"),
|
config.get_raw_multi_value("core", Some("a"), "a"),
|
||||||
Err(GitConfigError::SubSectionDoesNotExist(Some("a".into())))
|
Err(GitConfigError::SubSectionDoesNotExist(Some("a".into())))
|
||||||
|
@ -930,7 +943,7 @@ mod get_raw_multi_value {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn key_not_found() {
|
fn key_not_found() {
|
||||||
let config = GitConfig::from_str("[core]\na=b\nc=d").unwrap();
|
let config = GitConfig::try_from("[core]\na=b\nc=d").unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config.get_raw_multi_value("core", None, "aaaaaa"),
|
config.get_raw_multi_value("core", None, "aaaaaa"),
|
||||||
Err(GitConfigError::KeyDoesNotExist("aaaaaa".into()))
|
Err(GitConfigError::KeyDoesNotExist("aaaaaa".into()))
|
||||||
|
@ -939,7 +952,7 @@ mod get_raw_multi_value {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn subsection_must_be_respected() {
|
fn subsection_must_be_respected() {
|
||||||
let config = GitConfig::from_str("[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")]
|
vec![&Cow::Borrowed("b")]
|
||||||
|
@ -952,7 +965,7 @@ mod get_raw_multi_value {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn non_relevant_subsection_is_ignored() {
|
fn non_relevant_subsection_is_ignored() {
|
||||||
let config = GitConfig::from_str("[core]\na=b\na=c\n[core]a=d\n[core]g=g").unwrap();
|
let config = GitConfig::try_from("[core]\na=b\na=c\n[core]a=d\n[core]g=g").unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config.get_raw_multi_value("core", None, "a").unwrap(),
|
config.get_raw_multi_value("core", None, "a").unwrap(),
|
||||||
vec![
|
vec![
|
||||||
|
@ -973,7 +986,7 @@ mod display {
|
||||||
let config = r#"
|
let config = r#"
|
||||||
|
|
||||||
"#;
|
"#;
|
||||||
assert_eq!(GitConfig::from_str(config).unwrap().to_string(), config);
|
assert_eq!(GitConfig::try_from(config).unwrap().to_string(), config);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -997,7 +1010,7 @@ mod display {
|
||||||
[init]
|
[init]
|
||||||
defaultBranch = master"#;
|
defaultBranch = master"#;
|
||||||
|
|
||||||
assert_eq!(GitConfig::from_str(config).unwrap().to_string(), config);
|
assert_eq!(GitConfig::try_from(config).unwrap().to_string(), config);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1012,7 +1025,7 @@ mod display {
|
||||||
[commit]
|
[commit]
|
||||||
gpgsign"#;
|
gpgsign"#;
|
||||||
|
|
||||||
assert_eq!(GitConfig::from_str(config).unwrap().to_string(), config);
|
assert_eq!(GitConfig::try_from(config).unwrap().to_string(), config);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1028,6 +1041,6 @@ mod display {
|
||||||
[init]
|
[init]
|
||||||
defaultBranch = master"#;
|
defaultBranch = master"#;
|
||||||
|
|
||||||
assert_eq!(GitConfig::from_str(config).unwrap().to_string(), config);
|
assert_eq!(GitConfig::try_from(config).unwrap().to_string(), config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,9 +19,9 @@ use nom::error::{Error as NomError, ErrorKind};
|
||||||
use nom::multi::{many0, many1};
|
use nom::multi::{many0, many1};
|
||||||
use nom::sequence::delimited;
|
use nom::sequence::delimited;
|
||||||
use nom::IResult;
|
use nom::IResult;
|
||||||
use std::fmt::Display;
|
|
||||||
use std::iter::FusedIterator;
|
use std::iter::FusedIterator;
|
||||||
use std::{borrow::Cow, error::Error};
|
use std::{borrow::Cow, error::Error};
|
||||||
|
use std::{convert::TryFrom, fmt::Display};
|
||||||
|
|
||||||
/// Syntactic events that occurs in the config. Despite all these variants
|
/// Syntactic events that occurs in the config. Despite all these variants
|
||||||
/// holding a [`Cow`] instead over a simple reference, the parser will only emit
|
/// holding a [`Cow`] instead over a simple reference, the parser will only emit
|
||||||
|
@ -446,36 +446,6 @@ pub struct Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Parser<'a> {
|
impl<'a> Parser<'a> {
|
||||||
/// Attempt to zero-copy parse the provided `&str`. On success, returns a
|
|
||||||
/// [`Parser`] that provides methods to accessing leading comments and
|
|
||||||
/// sections of a `git-config` file and can be converted into an iterator of
|
|
||||||
/// [`Event`] for higher level processing.
|
|
||||||
///
|
|
||||||
/// This function is identical to [`parse_from_str`].
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// Returns an error if the string provided is not a valid `git-config`.
|
|
||||||
/// This generally is due to either invalid names or if there's extraneous
|
|
||||||
/// data succeeding valid `git-config` data.
|
|
||||||
pub fn from_str(s: &'a str) -> Result<Self, ParserError> {
|
|
||||||
parse_from_str(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Attempt to zero-copy parse the provided bytes. On success, returns a
|
|
||||||
/// [`Parser`] that provides methods to accessing leading comments and
|
|
||||||
/// sections of a `git-config` file and can be converted into an iterator of
|
|
||||||
/// [`Event`] for higher level processing.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// Returns an error if the string provided is not a valid `git-config`.
|
|
||||||
/// This generally is due to either invalid names or if there's extraneous
|
|
||||||
/// data succeeding valid `git-config` data.
|
|
||||||
pub fn from_bytes(s: impl Into<&'a BStr>) -> Result<Self, ParserError<'a>> {
|
|
||||||
parse_from_bytes(s.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the leading events (any comments, whitespace, or newlines before
|
/// Returns the leading events (any comments, whitespace, or newlines before
|
||||||
/// a section) from the parser. Consider [`Parser::take_frontmatter`] if
|
/// a section) from the parser. Consider [`Parser::take_frontmatter`] if
|
||||||
/// you need an owned copy only once. If that function was called, then this
|
/// you need an owned copy only once. If that function was called, then this
|
||||||
|
@ -530,6 +500,22 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> TryFrom<&'a str> for Parser<'a> {
|
||||||
|
type Error = ParserError<'a>;
|
||||||
|
|
||||||
|
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
|
||||||
|
parse_from_str(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TryFrom<&'a [u8]> for Parser<'a> {
|
||||||
|
type Error = ParserError<'a>;
|
||||||
|
|
||||||
|
fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
|
||||||
|
parse_from_bytes(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Attempt to zero-copy parse the provided `&str`. On success, returns a
|
/// Attempt to zero-copy parse the provided `&str`. On success, returns a
|
||||||
/// [`Parser`] that provides methods to accessing leading comments and sections
|
/// [`Parser`] that provides methods to accessing leading comments and sections
|
||||||
/// of a `git-config` file and can be converted into an iterator of [`Event`]
|
/// of a `git-config` file and can be converted into an iterator of [`Event`]
|
||||||
|
|
Reference in a new issue