Move the full lines iterator to its own file.

This commit is contained in:
Tom Alexander 2023-10-29 10:55:03 -04:00
parent e42edb3f49
commit f87c453459
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
4 changed files with 127 additions and 127 deletions

View 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());
}
}
}

View File

@ -22,6 +22,7 @@ mod export_snippet;
mod fixed_width_area;
mod footnote_definition;
mod footnote_reference;
mod full_lines_iterator;
mod heading;
mod horizontal_rule;
mod inline_babel_call;

View File

@ -1,7 +1,7 @@
use crate::error::CustomError;
use super::full_lines_iterator::GetFullLines;
use super::registry::Registry;
use super::util::GetFullLines;
#[derive(Debug)]
pub(crate) struct ISrcBlock {

View File

@ -46,129 +46,3 @@ enum CoalesceWhitespace {
Normal,
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());
}
}
}