#![warn(missing_docs)] //! //! Normalize line endings //! //! This crate provides a `normalize` method that takes a char iterator and returns //! a new one with `\n` for all line endings /// This struct wraps a `std::io::Chars` to normalize line endings. /// /// Implements `Iterator` so can be used in place struct Normalized { iter: I, prev_was_cr: bool, } /// Take a Chars and return similar struct with normalized line endings /// /// # Example /// ``` /// use std::iter::FromIterator; /// use normalize_line_endings::normalized; /// /// let input = "This is a string \n with \r some \n\r\n random newlines\r\r\n\n"; /// assert_eq!( /// &String::from_iter(normalized(input.chars())), /// "This is a string \n with \n some \n\n random newlines\n\n\n" /// ); /// ``` #[inline] pub fn normalized(iter: impl Iterator) -> impl Iterator { Normalized { iter, prev_was_cr: false, } } impl Iterator for Normalized where I: Iterator, { type Item = char; fn next(&mut self) -> Option { match self.iter.next() { Some('\n') if self.prev_was_cr => { self.prev_was_cr = false; match self.iter.next() { Some('\r') => { self.prev_was_cr = true; Some('\n') } any => { self.prev_was_cr = false; any } } } Some('\r') => { self.prev_was_cr = true; Some('\n') } any => { self.prev_was_cr = false; any } } } } // tests #[cfg(test)] mod tests { use std::iter::FromIterator; #[test] fn normalized() { let input = "This is a string \n with \r some \n\r\n random newlines\r\r\n\n"; assert_eq!( &String::from_iter(super::normalized(input.chars())), "This is a string \n with \n some \n\n random newlines\n\n\n" ); } }