cmail_rpgp/
normalize_lines.rs1use std::iter::Peekable;
9
10use crate::line_writer::LineBreak;
11
12pub struct Normalized<I>
14where
15 I: Iterator<Item = u8>,
16{
17 line_break: LineBreak,
18 iter: Peekable<I>,
19 prev_was_cr: bool,
20}
21
22impl<I: Iterator<Item = u8>> Normalized<I> {
23 pub fn new(iter: I, line_break: LineBreak) -> Normalized<I> {
39 Normalized {
40 iter: iter.peekable(),
41 prev_was_cr: false,
42 line_break,
43 }
44 }
45}
46
47impl<I: Iterator<Item = u8>> Iterator for Normalized<I> {
48 type Item = u8;
49
50 fn next(&mut self) -> Option<u8> {
51 match self.iter.peek() {
52 Some(b'\n') => {
53 match self.line_break {
54 LineBreak::Lf => {
55 if self.prev_was_cr {
56 let _ = self.iter.next();
58 }
59
60 self.iter.next()
61 }
62 LineBreak::Cr => {
63 let _ = self.iter.next();
65
66 if self.prev_was_cr {
67 self.prev_was_cr = false;
68 self.next()
69 } else {
70 Some(b'\r')
71 }
72 }
73 LineBreak::Crlf => {
74 if self.prev_was_cr {
75 self.prev_was_cr = false;
76 self.iter.next()
77 } else {
78 self.prev_was_cr = true;
79 Some(b'\r')
80 }
81 }
82 }
83 }
84 Some(b'\r') => match self.line_break {
85 LineBreak::Lf => {
86 self.prev_was_cr = true;
87 let _ = self.iter.next();
88 Some(b'\n')
89 }
90 LineBreak::Cr => {
91 self.prev_was_cr = true;
92 self.iter.next()
93 }
94 LineBreak::Crlf => {
95 if self.prev_was_cr {
96 self.prev_was_cr = false;
97 Some(b'\n')
98 } else {
99 self.prev_was_cr = true;
100 self.iter.next()
101 }
102 }
103 },
104 _ => match self.line_break {
105 LineBreak::Lf | LineBreak::Cr => {
106 self.prev_was_cr = false;
107 self.iter.next()
108 }
109 LineBreak::Crlf => {
110 let res = if self.prev_was_cr {
111 Some(b'\n')
112 } else {
113 self.iter.next()
114 };
115 self.prev_was_cr = false;
116 res
117 }
118 },
119 }
120 }
121}
122
123#[cfg(test)]
125mod tests {
126 #![allow(clippy::unwrap_used)]
127 use super::*;
128
129 #[test]
130 fn normalized_lf() {
131 let input = "This is a string \n with \r some \n\r\n random newlines\r\r\n\n";
132 assert_eq!(
133 &String::from_utf8(Normalized::new(input.bytes(), LineBreak::Lf).collect()).unwrap(),
134 "This is a string \n with \n some \n\n random newlines\n\n\n"
135 );
136 }
137
138 #[test]
139 fn normalized_cr() {
140 let input = "This is a string \n with \r some \n\r\n random newlines\r\r\n\n";
141 assert_eq!(
142 &String::from_utf8(Normalized::new(input.bytes(), LineBreak::Cr).collect()).unwrap(),
143 "This is a string \r with \r some \r\r random newlines\r\r\r"
144 );
145 }
146
147 #[test]
148 fn normalized_crlf() {
149 let input = "This is a string \n with \r some \n\r\n random newlines\r\r\n\n";
150 assert_eq!(
151 &String::from_utf8(Normalized::new(input.bytes(), LineBreak::Crlf).collect()).unwrap(),
152 "This is a string \r\n with \r\n some \r\n\r\n random newlines\r\n\r\n\r\n"
153 );
154 }
155}