Move the full lines iterator to its own file.
This commit is contained in:
parent
e42edb3f49
commit
f87c453459
125
src/intermediate/full_lines_iterator.rs
Normal file
125
src/intermediate/full_lines_iterator.rs
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
pub(crate) struct FullLinesIterator<'i> {
|
||||||
|
inner: Option<&'i str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'i> Iterator for FullLinesIterator<'i> {
|
||||||
|
type Item = &'i str;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if let Some(inner) = self.inner {
|
||||||
|
for (i, c) in inner.char_indices() {
|
||||||
|
if c == '\n' {
|
||||||
|
let (current_line, remainder) = inner.split_at(i + 1);
|
||||||
|
self.inner = Some(remainder);
|
||||||
|
return Some(current_line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if inner.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let final_unterminated_line = Some(inner);
|
||||||
|
self.inner = None;
|
||||||
|
final_unterminated_line
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
if let Some(inner) = self.inner {
|
||||||
|
let line_count = {
|
||||||
|
inner.bytes().filter(|b| *b == b'\n').count()
|
||||||
|
+ (if inner.ends_with('\n') { 0 } else { 1 })
|
||||||
|
};
|
||||||
|
(line_count, Some(line_count))
|
||||||
|
} else {
|
||||||
|
(0, Some(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExactSizeIterator for FullLinesIterator<'_> {}
|
||||||
|
|
||||||
|
pub(crate) trait GetFullLines {
|
||||||
|
fn full_lines(&self) -> FullLinesIterator<'_>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'s, S: AsRef<str>> GetFullLines for S {
|
||||||
|
fn full_lines(&self) -> FullLinesIterator<'_> {
|
||||||
|
let inner = self.as_ref();
|
||||||
|
FullLinesIterator {
|
||||||
|
inner: if inner.is_empty() { None } else { Some(inner) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_full_lines_iterator() {
|
||||||
|
{
|
||||||
|
let input = "foo\nbar\nbaz";
|
||||||
|
assert_eq!(input.lines().count(), input.full_lines().count());
|
||||||
|
assert_eq!(input.lines().count(), input.full_lines().len());
|
||||||
|
assert_eq!(input.lines().collect::<Vec<_>>(), vec!["foo", "bar", "baz"]);
|
||||||
|
assert_eq!(
|
||||||
|
input.full_lines().collect::<Vec<_>>(),
|
||||||
|
vec!["foo\n", "bar\n", "baz"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Trailing newline
|
||||||
|
let input = "foo\nbar\nbaz\n";
|
||||||
|
assert_eq!(input.lines().count(), input.full_lines().count());
|
||||||
|
assert_eq!(input.lines().count(), input.full_lines().len());
|
||||||
|
assert_eq!(input.lines().collect::<Vec<_>>(), vec!["foo", "bar", "baz"]);
|
||||||
|
assert_eq!(
|
||||||
|
input.full_lines().collect::<Vec<_>>(),
|
||||||
|
vec!["foo\n", "bar\n", "baz\n"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Leading newline
|
||||||
|
let input = "\nfoo\nbar\nbaz";
|
||||||
|
assert_eq!(input.lines().count(), input.full_lines().count());
|
||||||
|
assert_eq!(input.lines().count(), input.full_lines().len());
|
||||||
|
assert_eq!(
|
||||||
|
input.lines().collect::<Vec<_>>(),
|
||||||
|
vec!["", "foo", "bar", "baz"]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
input.full_lines().collect::<Vec<_>>(),
|
||||||
|
vec!["\n", "foo\n", "bar\n", "baz"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Double newline
|
||||||
|
let input = "foo\nbar\n\nbaz";
|
||||||
|
assert_eq!(input.lines().count(), input.full_lines().count());
|
||||||
|
assert_eq!(input.lines().count(), input.full_lines().len());
|
||||||
|
assert_eq!(
|
||||||
|
input.lines().collect::<Vec<_>>(),
|
||||||
|
vec!["foo", "bar", "", "baz"]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
input.full_lines().collect::<Vec<_>>(),
|
||||||
|
vec!["foo\n", "bar\n", "\n", "baz"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Empty
|
||||||
|
let input = "";
|
||||||
|
assert_eq!(input.lines().count(), input.full_lines().count());
|
||||||
|
assert_eq!(input.lines().count(), input.full_lines().len());
|
||||||
|
assert_eq!(input.lines().collect::<Vec<_>>(), Vec::<&str>::new());
|
||||||
|
assert_eq!(input.full_lines().collect::<Vec<_>>(), Vec::<&str>::new());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,7 @@ mod export_snippet;
|
|||||||
mod fixed_width_area;
|
mod fixed_width_area;
|
||||||
mod footnote_definition;
|
mod footnote_definition;
|
||||||
mod footnote_reference;
|
mod footnote_reference;
|
||||||
|
mod full_lines_iterator;
|
||||||
mod heading;
|
mod heading;
|
||||||
mod horizontal_rule;
|
mod horizontal_rule;
|
||||||
mod inline_babel_call;
|
mod inline_babel_call;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
|
|
||||||
|
use super::full_lines_iterator::GetFullLines;
|
||||||
use super::registry::Registry;
|
use super::registry::Registry;
|
||||||
use super::util::GetFullLines;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct ISrcBlock {
|
pub(crate) struct ISrcBlock {
|
||||||
|
@ -46,129 +46,3 @@ enum CoalesceWhitespace {
|
|||||||
Normal,
|
Normal,
|
||||||
HasWhitespace { in_whitespace: bool, ret: String },
|
HasWhitespace { in_whitespace: bool, ret: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct FullLinesIterator<'i> {
|
|
||||||
inner: Option<&'i str>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'i> Iterator for FullLinesIterator<'i> {
|
|
||||||
type Item = &'i str;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
if let Some(inner) = self.inner {
|
|
||||||
for (i, c) in inner.char_indices() {
|
|
||||||
if c == '\n' {
|
|
||||||
let (current_line, remainder) = inner.split_at(i + 1);
|
|
||||||
self.inner = Some(remainder);
|
|
||||||
return Some(current_line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if inner.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
let final_unterminated_line = Some(inner);
|
|
||||||
self.inner = None;
|
|
||||||
final_unterminated_line
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
||||||
if let Some(inner) = self.inner {
|
|
||||||
let line_count = {
|
|
||||||
inner.bytes().filter(|b| *b == b'\n').count()
|
|
||||||
+ (if inner.ends_with('\n') { 0 } else { 1 })
|
|
||||||
};
|
|
||||||
(line_count, Some(line_count))
|
|
||||||
} else {
|
|
||||||
(0, Some(0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ExactSizeIterator for FullLinesIterator<'_> {}
|
|
||||||
|
|
||||||
pub(crate) trait GetFullLines {
|
|
||||||
fn full_lines(&self) -> FullLinesIterator<'_>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'s, S: AsRef<str>> GetFullLines for S {
|
|
||||||
fn full_lines(&self) -> FullLinesIterator<'_> {
|
|
||||||
let inner = self.as_ref();
|
|
||||||
FullLinesIterator {
|
|
||||||
inner: if inner.is_empty() { None } else { Some(inner) },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_full_lines_iterator() {
|
|
||||||
{
|
|
||||||
let input = "foo\nbar\nbaz";
|
|
||||||
assert_eq!(input.lines().count(), input.full_lines().count());
|
|
||||||
assert_eq!(input.lines().count(), input.full_lines().len());
|
|
||||||
assert_eq!(input.lines().collect::<Vec<_>>(), vec!["foo", "bar", "baz"]);
|
|
||||||
assert_eq!(
|
|
||||||
input.full_lines().collect::<Vec<_>>(),
|
|
||||||
vec!["foo\n", "bar\n", "baz"]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
// Trailing newline
|
|
||||||
let input = "foo\nbar\nbaz\n";
|
|
||||||
assert_eq!(input.lines().count(), input.full_lines().count());
|
|
||||||
assert_eq!(input.lines().count(), input.full_lines().len());
|
|
||||||
assert_eq!(input.lines().collect::<Vec<_>>(), vec!["foo", "bar", "baz"]);
|
|
||||||
assert_eq!(
|
|
||||||
input.full_lines().collect::<Vec<_>>(),
|
|
||||||
vec!["foo\n", "bar\n", "baz\n"]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
// Leading newline
|
|
||||||
let input = "\nfoo\nbar\nbaz";
|
|
||||||
assert_eq!(input.lines().count(), input.full_lines().count());
|
|
||||||
assert_eq!(input.lines().count(), input.full_lines().len());
|
|
||||||
assert_eq!(
|
|
||||||
input.lines().collect::<Vec<_>>(),
|
|
||||||
vec!["", "foo", "bar", "baz"]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
input.full_lines().collect::<Vec<_>>(),
|
|
||||||
vec!["\n", "foo\n", "bar\n", "baz"]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
// Double newline
|
|
||||||
let input = "foo\nbar\n\nbaz";
|
|
||||||
assert_eq!(input.lines().count(), input.full_lines().count());
|
|
||||||
assert_eq!(input.lines().count(), input.full_lines().len());
|
|
||||||
assert_eq!(
|
|
||||||
input.lines().collect::<Vec<_>>(),
|
|
||||||
vec!["foo", "bar", "", "baz"]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
input.full_lines().collect::<Vec<_>>(),
|
|
||||||
vec!["foo\n", "bar\n", "\n", "baz"]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
// Empty
|
|
||||||
let input = "";
|
|
||||||
assert_eq!(input.lines().count(), input.full_lines().count());
|
|
||||||
assert_eq!(input.lines().count(), input.full_lines().len());
|
|
||||||
assert_eq!(input.lines().collect::<Vec<_>>(), Vec::<&str>::new());
|
|
||||||
assert_eq!(input.full_lines().collect::<Vec<_>>(), Vec::<&str>::new());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user