use mut vec reference
This commit is contained in:
parent
6b8386d449
commit
17ba292934
1 changed files with 164 additions and 111 deletions
275
src/parser.rs
275
src/parser.rs
|
@ -631,34 +631,56 @@ fn section<'a, 'b>(
|
||||||
i: &'a [u8],
|
i: &'a [u8],
|
||||||
node: &'b mut ParserNode,
|
node: &'b mut ParserNode,
|
||||||
) -> IResult<&'a [u8], (ParsedSection<'a>, usize)> {
|
) -> IResult<&'a [u8], (ParsedSection<'a>, usize)> {
|
||||||
let (i, section_header) = section_header(i)?;
|
let (mut i, section_header) = section_header(i)?;
|
||||||
|
|
||||||
let mut newlines = 0;
|
let mut newlines = 0;
|
||||||
let (i, items) = many0(alt((
|
let mut items = vec![];
|
||||||
map(take_spaces, |space| {
|
|
||||||
vec![Event::Whitespace(Cow::Borrowed(space.into()))]
|
// This would usually be a many0(alt(...)), the manual loop allows us to
|
||||||
}),
|
// optimize vec insertions
|
||||||
map(take_newline, |(newline, counter)| {
|
loop {
|
||||||
newlines += counter;
|
let old_i = i;
|
||||||
vec![Event::Newline(Cow::Borrowed(newline.into()))]
|
|
||||||
}),
|
if let Ok((new_i, v)) = take_spaces(i) {
|
||||||
map(
|
if old_i != new_i {
|
||||||
|i| section_body(i, node),
|
i = new_i;
|
||||||
|(key, values)| {
|
items.push(Event::Whitespace(Cow::Borrowed(v.into())));
|
||||||
let mut vec = vec![Event::Key(Cow::Borrowed(key.into()))];
|
}
|
||||||
vec.extend(values);
|
}
|
||||||
vec
|
|
||||||
},
|
if let Ok((new_i, (v, new_newlines))) = take_newline(i) {
|
||||||
),
|
if old_i != new_i {
|
||||||
map(comment, |comment| vec![Event::Comment(comment)]),
|
i = new_i;
|
||||||
)))(i)?;
|
newlines += new_newlines;
|
||||||
|
items.push(Event::Newline(Cow::Borrowed(v.into())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok((new_i, _)) = section_body(i, node, &mut items) {
|
||||||
|
if old_i != new_i {
|
||||||
|
i = new_i;
|
||||||
|
// items.push(Event::Key(Cow::Borrowed(key.into())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok((new_i, comment)) = comment(i) {
|
||||||
|
if old_i != new_i {
|
||||||
|
i = new_i;
|
||||||
|
items.push(Event::Comment(comment));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if old_i == i {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
i,
|
i,
|
||||||
(
|
(
|
||||||
ParsedSection {
|
ParsedSection {
|
||||||
section_header,
|
section_header,
|
||||||
events: items.into_iter().flatten().collect(),
|
events: items,
|
||||||
},
|
},
|
||||||
newlines,
|
newlines,
|
||||||
),
|
),
|
||||||
|
@ -716,26 +738,26 @@ fn section_header(i: &[u8]) -> IResult<&[u8], ParsedSectionHeader> {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn section_body<'a, 'b>(
|
fn section_body<'a, 'b, 'c>(
|
||||||
i: &'a [u8],
|
i: &'a [u8],
|
||||||
node: &'b mut ParserNode,
|
node: &'b mut ParserNode,
|
||||||
) -> IResult<&'a [u8], (&'a [u8], Vec<Event<'a>>)> {
|
items: &'c mut Vec<Event<'a>>,
|
||||||
|
) -> IResult<&'a [u8], ()> {
|
||||||
// maybe need to check for [ here
|
// maybe need to check for [ here
|
||||||
*node = ParserNode::ConfigName;
|
*node = ParserNode::ConfigName;
|
||||||
let (i, name) = config_name(i)?;
|
let (i, name) = config_name(i)?;
|
||||||
|
|
||||||
|
items.push(Event::Key(Cow::Borrowed(name.into())));
|
||||||
|
|
||||||
let (i, whitespace) = opt(take_spaces)(i)?;
|
let (i, whitespace) = opt(take_spaces)(i)?;
|
||||||
|
|
||||||
*node = ParserNode::ConfigValue;
|
|
||||||
let (i, value) = config_value(i)?;
|
|
||||||
|
|
||||||
if let Some(whitespace) = whitespace {
|
if let Some(whitespace) = whitespace {
|
||||||
let mut events = vec![Event::Whitespace(Cow::Borrowed(whitespace.into()))];
|
items.push(Event::Whitespace(Cow::Borrowed(whitespace.into())));
|
||||||
events.extend(value);
|
|
||||||
Ok((i, (name, events)))
|
|
||||||
} else {
|
|
||||||
Ok((i, (name, value)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*node = ParserNode::ConfigValue;
|
||||||
|
let (i, _) = config_value(i, items)?;
|
||||||
|
Ok((i, ()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses the config name of a config pair. Assumes the input has already been
|
/// Parses the config name of a config pair. Assumes the input has already been
|
||||||
|
@ -757,24 +779,22 @@ fn config_name(i: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
take_while(|c: u8| (c as char).is_alphanumeric() || c == b'-')(i)
|
take_while(|c: u8| (c as char).is_alphanumeric() || c == b'-')(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn config_value(i: &[u8]) -> IResult<&[u8], Vec<Event>> {
|
fn config_value<'a, 'b>(i: &'a [u8], events: &'b mut Vec<Event<'a>>) -> IResult<&'a [u8], ()> {
|
||||||
if let (i, Some(_)) = opt(char('='))(i)? {
|
if let (i, Some(_)) = opt(char('='))(i)? {
|
||||||
let mut events = vec![];
|
|
||||||
events.push(Event::KeyValueSeparator);
|
events.push(Event::KeyValueSeparator);
|
||||||
let (i, whitespace) = opt(take_spaces)(i)?;
|
let (i, whitespace) = opt(take_spaces)(i)?;
|
||||||
let (i, values) = value_impl(i)?;
|
|
||||||
if let Some(whitespace) = whitespace {
|
if let Some(whitespace) = whitespace {
|
||||||
events.push(Event::Whitespace(Cow::Borrowed(whitespace.into())));
|
events.push(Event::Whitespace(Cow::Borrowed(whitespace.into())));
|
||||||
}
|
}
|
||||||
events.extend(values);
|
let (i, _) = value_impl(i, events)?;
|
||||||
Ok((i, events))
|
Ok((i, ()))
|
||||||
} else {
|
} else {
|
||||||
Ok((i, vec![Event::Value(Cow::Borrowed("".into()))]))
|
events.push(Event::Value(Cow::Borrowed("".into())));
|
||||||
|
Ok((i, ()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn value_impl(i: &[u8]) -> IResult<&[u8], Vec<Event>> {
|
fn value_impl<'a, 'b>(i: &'a [u8], events: &'b mut Vec<Event<'a>>) -> IResult<&'a [u8], ()> {
|
||||||
let mut events = vec![];
|
|
||||||
let mut parsed_index: usize = 0;
|
let mut parsed_index: usize = 0;
|
||||||
let mut offset: usize = 0;
|
let mut offset: usize = 0;
|
||||||
|
|
||||||
|
@ -861,7 +881,7 @@ fn value_impl(i: &[u8]) -> IResult<&[u8], Vec<Event>> {
|
||||||
events.push(Event::Value(Cow::Borrowed(remainder_value.into())));
|
events.push(Event::Value(Cow::Borrowed(remainder_value.into())));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((i, events))
|
Ok((i, ()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn take_spaces(i: &[u8]) -> IResult<&[u8], &[u8]> {
|
fn take_spaces(i: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
|
@ -1020,32 +1040,33 @@ mod config_name {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod section_body {
|
mod section_body {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::test_util::{value_event, whitespace_event};
|
use crate::test_util::{name_event, value_event, whitespace_event};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn whitespace_is_not_ambigious() {
|
fn whitespace_is_not_ambigious() {
|
||||||
let mut node = ParserNode::SectionHeader;
|
let mut node = ParserNode::SectionHeader;
|
||||||
|
let mut vec = vec![];
|
||||||
|
assert!(section_body(b"a =b", &mut node, &mut vec).is_ok());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
section_body(b"a =b", &mut node).unwrap().1,
|
vec,
|
||||||
(
|
vec![
|
||||||
"a".as_bytes(),
|
name_event("a"),
|
||||||
vec![
|
whitespace_event(" "),
|
||||||
whitespace_event(" "),
|
Event::KeyValueSeparator,
|
||||||
Event::KeyValueSeparator,
|
value_event("b")
|
||||||
value_event("b")
|
]
|
||||||
]
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let mut vec = vec![];
|
||||||
|
assert!(section_body(b"a= b", &mut node, &mut vec).is_ok());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
section_body(b"a= b", &mut node).unwrap().1,
|
vec,
|
||||||
(
|
vec![
|
||||||
"a".as_bytes(),
|
name_event("a"),
|
||||||
vec![
|
Event::KeyValueSeparator,
|
||||||
Event::KeyValueSeparator,
|
whitespace_event(" "),
|
||||||
whitespace_event(" "),
|
value_event("b")
|
||||||
value_event("b")
|
]
|
||||||
]
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1053,141 +1074,173 @@ mod section_body {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod value_no_continuation {
|
mod value_no_continuation {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::test_util::{fully_consumed, value_event};
|
use crate::test_util::value_event;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn no_comment() {
|
fn no_comment() {
|
||||||
assert_eq!(
|
let mut events = vec![];
|
||||||
value_impl(b"hello").unwrap(),
|
assert_eq!(value_impl(b"hello", &mut events).unwrap().0, b"");
|
||||||
fully_consumed(vec![value_event("hello")])
|
assert_eq!(events, vec![value_event("hello")]);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn no_comment_newline() {
|
fn no_comment_newline() {
|
||||||
assert_eq!(
|
let mut events = vec![];
|
||||||
value_impl(b"hello\na").unwrap(),
|
assert_eq!(value_impl(b"hello\na", &mut events).unwrap().0, b"\na");
|
||||||
("\na".as_bytes(), vec![value_event("hello")])
|
assert_eq!(events, vec![value_event("hello")]);
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn semicolon_comment_not_consumed() {
|
fn semicolon_comment_not_consumed() {
|
||||||
|
let mut events = vec![];
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
value_impl(b"hello;world").unwrap(),
|
value_impl(b"hello;world", &mut events).unwrap().0,
|
||||||
(";world".as_bytes(), vec![value_event("hello"),])
|
b";world"
|
||||||
);
|
);
|
||||||
|
assert_eq!(events, vec![value_event("hello")]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn octothorpe_comment_not_consumed() {
|
fn octothorpe_comment_not_consumed() {
|
||||||
|
let mut events = vec![];
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
value_impl(b"hello#world").unwrap(),
|
value_impl(b"hello#world", &mut events).unwrap().0,
|
||||||
("#world".as_bytes(), vec![value_event("hello"),])
|
b"#world"
|
||||||
);
|
);
|
||||||
|
assert_eq!(events, vec![value_event("hello")]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn values_with_extraneous_whitespace_without_comment() {
|
fn values_with_extraneous_whitespace_without_comment() {
|
||||||
|
let mut events = vec![];
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
value_impl(b"hello ").unwrap(),
|
value_impl(b"hello ", &mut events).unwrap().0,
|
||||||
(" ".as_bytes(), vec![value_event("hello")])
|
b" "
|
||||||
);
|
);
|
||||||
|
assert_eq!(events, vec![value_event("hello")]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn values_with_extraneous_whitespace_before_comment() {
|
fn values_with_extraneous_whitespace_before_comment() {
|
||||||
|
let mut events = vec![];
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
value_impl(b"hello #world").unwrap(),
|
value_impl(b"hello #world", &mut events)
|
||||||
(" #world".as_bytes(), vec![value_event("hello")])
|
.unwrap()
|
||||||
|
.0,
|
||||||
|
b" #world"
|
||||||
);
|
);
|
||||||
|
assert_eq!(events, vec![value_event("hello")]);
|
||||||
|
|
||||||
|
let mut events = vec![];
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
value_impl(b"hello ;world").unwrap(),
|
value_impl(b"hello ;world", &mut events)
|
||||||
(" ;world".as_bytes(), vec![value_event("hello")])
|
.unwrap()
|
||||||
|
.0,
|
||||||
|
b" ;world"
|
||||||
);
|
);
|
||||||
|
assert_eq!(events, vec![value_event("hello")]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn trans_escaped_comment_marker_not_consumed() {
|
fn trans_escaped_comment_marker_not_consumed() {
|
||||||
|
let mut events = vec![];
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
value_impl(br##"hello"#"world; a"##).unwrap(),
|
value_impl(br##"hello"#"world; a"##, &mut events).unwrap().0,
|
||||||
("; a".as_bytes(), vec![value_event(r##"hello"#"world"##)])
|
b"; a"
|
||||||
);
|
);
|
||||||
|
assert_eq!(events, vec![value_event(r##"hello"#"world"##)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn complex_test() {
|
fn complex_test() {
|
||||||
|
let mut events = vec![];
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
value_impl(br#"value";";ahhhh"#).unwrap(),
|
value_impl(br#"value";";ahhhh"#, &mut events).unwrap().0,
|
||||||
(";ahhhh".as_bytes(), vec![value_event(r#"value";""#)])
|
b";ahhhh"
|
||||||
);
|
);
|
||||||
|
assert_eq!(events, vec![value_event(r#"value";""#)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn garbage_after_continution_is_err() {
|
fn garbage_after_continution_is_err() {
|
||||||
assert!(value_impl(b"hello \\afwjdls").is_err());
|
assert!(value_impl(b"hello \\afwjdls", &mut vec![]).is_err());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod value_continuation {
|
mod value_continuation {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::test_util::{fully_consumed, newline_event, value_done_event, value_not_done_event};
|
use crate::test_util::{newline_event, value_done_event, value_not_done_event};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn simple_continuation() {
|
fn simple_continuation() {
|
||||||
|
let mut events = vec![];
|
||||||
|
assert_eq!(value_impl(b"hello\\\nworld", &mut events).unwrap().0, b"");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
value_impl(b"hello\\\nworld").unwrap(),
|
events,
|
||||||
fully_consumed(vec![
|
vec![
|
||||||
value_not_done_event("hello"),
|
value_not_done_event("hello"),
|
||||||
newline_event(),
|
newline_event(),
|
||||||
value_done_event("world")
|
value_done_event("world")
|
||||||
])
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn continuation_with_whitespace() {
|
fn continuation_with_whitespace() {
|
||||||
|
let mut events = vec![];
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
value_impl(b"hello\\\n world").unwrap(),
|
value_impl(b"hello\\\n world", &mut events)
|
||||||
fully_consumed(vec![
|
.unwrap()
|
||||||
|
.0,
|
||||||
|
b""
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
events,
|
||||||
|
vec![
|
||||||
value_not_done_event("hello"),
|
value_not_done_event("hello"),
|
||||||
newline_event(),
|
newline_event(),
|
||||||
value_done_event(" world")
|
value_done_event(" world")
|
||||||
])
|
]
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn complex_continuation_with_leftover_comment() {
|
fn complex_continuation_with_leftover_comment() {
|
||||||
|
let mut events = vec![];
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
value_impl(b"1 \"\\\"\\\na ; e \"\\\"\\\nd # \"b\t ; c").unwrap(),
|
value_impl(b"1 \"\\\"\\\na ; e \"\\\"\\\nd # \"b\t ; c", &mut events)
|
||||||
(
|
.unwrap()
|
||||||
" # \"b\t ; c".as_bytes(),
|
.0,
|
||||||
vec![
|
b" # \"b\t ; c"
|
||||||
value_not_done_event(r#"1 "\""#),
|
);
|
||||||
newline_event(),
|
assert_eq!(
|
||||||
value_not_done_event(r#"a ; e "\""#),
|
events,
|
||||||
newline_event(),
|
vec![
|
||||||
value_done_event("d")
|
value_not_done_event(r#"1 "\""#),
|
||||||
]
|
newline_event(),
|
||||||
)
|
value_not_done_event(r#"a ; e "\""#),
|
||||||
|
newline_event(),
|
||||||
|
value_done_event("d")
|
||||||
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn quote_split_over_two_lines_with_leftover_comment() {
|
fn quote_split_over_two_lines_with_leftover_comment() {
|
||||||
|
let mut events = vec![];
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
value_impl(b"\"\\\n;\";a").unwrap(),
|
value_impl(b"\"\\\n;\";a", &mut events).unwrap().0,
|
||||||
(
|
";a".as_bytes()
|
||||||
";a".as_bytes(),
|
);
|
||||||
vec![
|
assert_eq!(
|
||||||
value_not_done_event("\""),
|
events,
|
||||||
newline_event(),
|
vec![
|
||||||
value_done_event(";\"")
|
value_not_done_event("\""),
|
||||||
]
|
newline_event(),
|
||||||
)
|
value_done_event(";\"")
|
||||||
)
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in a new issue