1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
use std::io::{self, Read};
use std::str::{self, Utf8Error};
#[derive(Debug)]
struct ReaderBuf {
vec: Vec<u8>,
msg_start: usize,
write_loc: usize
}
impl ReaderBuf {
pub fn new(buffer_size: usize) -> ReaderBuf {
let mut vec = Vec::with_capacity(buffer_size);
unsafe { vec.set_len(buffer_size); }
ReaderBuf {
vec: vec,
msg_start: 0,
write_loc: 0
}
}
pub fn reset(&mut self) {
let mut write_index = 0;
for i in self.msg_start..self.write_loc {
self.vec[write_index] = self.vec[i];
write_index = write_index + 1;
}
self.write_loc = write_index;
self.msg_start = 0;
}
pub fn is_empty(&self) -> bool {
self.write_loc == 0
}
}
pub struct Iter<'a> {
buf: &'a mut ReaderBuf
}
impl<'a> Iterator for Iter<'a> {
type Item = Result<String, Utf8Error>;
fn next(&mut self) -> Option<Result<String, Utf8Error>> {
if self.buf.msg_start == self.buf.write_loc {
self.buf.reset();
return None;
}
let slice = &self.buf.vec[self.buf.msg_start..self.buf.write_loc];
match slice.iter().position(|&c| c == '\n' as u8) {
Some(index) => {
self.buf.msg_start = self.buf.msg_start + index + 1;
Some(str::from_utf8(&slice[0..index+1]).map(|s| s.to_string()))
},
None => None
}
}
}
#[derive(Debug)]
pub struct LineReader {
buf: ReaderBuf
}
impl LineReader {
pub fn new(buffer_size: usize) -> LineReader {
LineReader {
buf: ReaderBuf::new(buffer_size)
}
}
pub fn read<T: Read>(&mut self, reader: &mut T) -> io::Result<usize> {
let bytes_read = try!(reader.read(&mut self.buf.vec[self.buf.write_loc..]));
self.buf.write_loc += bytes_read;
Ok(bytes_read)
}
pub fn iter_mut(&mut self) -> Iter {
Iter {
buf: &mut self.buf
}
}
pub fn is_empty(&self) -> bool {
self.buf.is_empty()
}
}
#[cfg(test)]
mod tests {
use std::io::Cursor;
use super::LineReader;
const TEXT: &'static str = "hello\nworld\nhow's\nit\ngoing?\n";
#[test]
fn static_buffer_single_read() {
let mut data = Cursor::new(TEXT);
let mut line_reader = LineReader::new(1024);
let bytes_read = line_reader.read(&mut data).unwrap();
assert_eq!(false, line_reader.is_empty());
assert_eq!(TEXT.len(), bytes_read);
assert_eq!(5, line_reader.iter_mut().count());
assert_eq!(None, line_reader.iter_mut().next());
assert_eq!(true, line_reader.is_empty());
}
#[test]
fn static_buffer_partial_read_follow_by_complete_read() {
let mut string = TEXT.to_string();
string.push_str("ok");
let mut data = Cursor::new(&string);
let mut line_reader = LineReader::new(1024);
let bytes_read = line_reader.read(&mut data).unwrap();
assert_eq!(false, line_reader.is_empty());
assert_eq!(string.len(), bytes_read);
assert_eq!(5, line_reader.iter_mut().count());
assert_eq!(None, line_reader.iter_mut().next());
assert_eq!(false, line_reader.is_empty());
assert_eq!(1, line_reader.read(&mut Cursor::new("\n")).unwrap());
assert_eq!("ok\n".to_string(), line_reader.iter_mut().next().unwrap().unwrap());
assert_eq!(None, line_reader.iter_mut().next());
assert_eq!(true, line_reader.is_empty());
}
}