normalize_line_endings/
lib.rs

1#![warn(missing_docs)]
2//!
3//! Normalize line endings
4//!
5//! This crate provides a `normalize` method that takes a char iterator and returns
6//! a new one with `\n` for all line endings
7
8/// This struct wraps a `std::io::Chars` to normalize line endings.
9///
10/// Implements `Iterator<Item=char>` so can be used in place
11struct Normalized<I> {
12    iter: I,
13    prev_was_cr: bool,
14}
15
16/// Take a Chars and return similar struct with normalized line endings
17///
18/// # Example
19/// ```
20/// use std::iter::FromIterator;
21/// use normalize_line_endings::normalized;
22///
23/// let input = "This is a string \n with \r some \n\r\n random newlines\r\r\n\n";
24/// assert_eq!(
25///     &String::from_iter(normalized(input.chars())),
26///     "This is a string \n with \n some \n\n random newlines\n\n\n"
27/// );
28/// ```
29#[inline]
30pub fn normalized(iter: impl Iterator<Item = char>) -> impl Iterator<Item = char> {
31    Normalized {
32        iter,
33        prev_was_cr: false,
34    }
35}
36
37impl<I> Iterator for Normalized<I>
38where
39    I: Iterator<Item = char>,
40{
41    type Item = char;
42    fn next(&mut self) -> Option<char> {
43        match self.iter.next() {
44            Some('\n') if self.prev_was_cr => {
45                self.prev_was_cr = false;
46                match self.iter.next() {
47                    Some('\r') => {
48                        self.prev_was_cr = true;
49                        Some('\n')
50                    }
51                    any => {
52                        self.prev_was_cr = false;
53                        any
54                    }
55                }
56            }
57            Some('\r') => {
58                self.prev_was_cr = true;
59                Some('\n')
60            }
61            any => {
62                self.prev_was_cr = false;
63                any
64            }
65        }
66    }
67}
68
69// tests
70#[cfg(test)]
71mod tests {
72    use std::iter::FromIterator;
73
74    #[test]
75    fn normalized() {
76        let input = "This is a string \n with \r some \n\r\n random newlines\r\r\n\n";
77        assert_eq!(
78            &String::from_iter(super::normalized(input.chars())),
79            "This is a string \n with \n some \n\n random newlines\n\n\n"
80        );
81    }
82}