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
use std::io::{BufRead, Read};
use std::io;
use std::fmt;
use crc32fast::Hasher;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct Crc {
checksum: u32,
amt: u32,
}
impl fmt::Display for Crc {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({:#x},{})", self.checksum, self.amt)
}
}
#[derive(Debug)]
pub struct CrcReader<R> {
inner: R,
crc: Crc,
}
impl Crc {
pub fn new() -> Crc {
Crc {
checksum: 0,
amt: 0,
}
}
pub fn with_initial(checksum: u32, amount: u32) -> Crc {
Crc {
checksum: checksum,
amt: amount,
}
}
pub fn sum(&self) -> u32 {
self.checksum
}
pub fn amt_as_u32(&self) -> u32 {
self.amt
}
pub fn update(&mut self, data: &[u8]) {
self.amt = self.amt.wrapping_add(data.len() as u32);
let mut h = Hasher::new_with_initial(self.checksum);
h.update(data);
self.checksum = h.finalize();
}
pub fn reset(&mut self) {
self.checksum = 0;
self.amt = 0;
}
}
impl<R: Read> CrcReader<R> {
pub fn new(r: R) -> CrcReader<R> {
CrcReader {
inner: r,
crc: Crc::new(),
}
}
pub fn crc(&self) -> &Crc {
&self.crc
}
pub fn into_inner(self) -> R {
self.inner
}
pub fn inner(&mut self) -> &mut R {
&mut self.inner
}
pub fn reset(&mut self) {
self.crc.reset();
}
}
impl<R: Read> Read for CrcReader<R> {
fn read(&mut self, into: &mut [u8]) -> io::Result<usize> {
let amt = try!(self.inner.read(into));
self.crc.update(&into[..amt]);
Ok(amt)
}
}
impl<R: BufRead> BufRead for CrcReader<R> {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
self.inner.fill_buf()
}
fn consume(&mut self, amt: usize) {
if let Ok(data) = self.inner.fill_buf() {
self.crc.update(&data[..amt]);
}
self.inner.consume(amt);
}
}
#[cfg(test)]
mod test {
use super::Crc;
#[test]
fn checksum_correct() {
let mut c = Crc::new();
c.update(b"abcdefg12345689\n");
assert_eq!(c.sum(), 0x141ddb83);
assert_eq!(c.amt_as_u32(), 16);
}
}