I needed a way to feed a Digest a stream of bytes while checking the CRC
for possible matches after each byte. Using CRC::crc directly would make
this O(n^2), so I looked to Digest. Because Digest::finalize consumes
self, it must be thrown out after each finalize operation. This is
probably what you want in the general case, but not in my slightly weird
case.
This problem can be solved by allowing Digest to be duplicated, thereby
letting the user "fork" the CRC state as desired. (This also enables
certain niche CRC-search algorithms.)
I went with Clone rather than Copy because making Digest Copy seemed
potentially error-prone; Clone has the advantage of requiring explicit
intent.
Here's an example (not included in the commit message for brevity) of a method enabled by this change.
/// Recognizer for sequences of bytes ending in a valid 16-bit CRC.
struct TrailingCrcSpotter {
digest: crc::Digest<'static, u16>,
tail: Tail,
}
/// Recognizer state; buffers 0-2 bytes as data arrives.
#[derive(Copy, Clone)]
enum Tail {
Empty,
One(u8),
Two(u8, u8),
}
impl TrailingCrcSpotter {
/// Append `byte` to the sequence being processed. If this causes
/// the sequence so far to end in a valid big-endian CRC16 over the
/// earlier data, return `true`. Otherwise, return `false`.
pub fn recognize(&mut self, byte: u8) -> bool {
match self.tail {
Tail::Empty => {
self.tail = Tail::One(byte);
false
}
Tail::One(x) => {
self.tail = Tail::Two(x, byte);
false
}
Tail::Two(x, y) => {
// main stage
self.tail = Tail::Two(y, byte);
self.digest.update(&[x]);
let crc = self.digest.clone().finalize();
crc == u16::from_be_bytes([y, byte])
}
}
}
}
I needed a way to feed a Digest a stream of bytes while checking the CRC for possible matches after each byte. Using CRC::crc directly would make this O(n^2), so I looked to Digest. Because Digest::finalize consumes self, it must be thrown out after each finalize operation. This is probably what you want in the general case, but not in my slightly weird case.
This problem can be solved by allowing Digest to be duplicated, thereby letting the user "fork" the CRC state as desired. (This also enables certain niche CRC-search algorithms.)
I went with Clone rather than Copy because making Digest Copy seemed potentially error-prone; Clone has the advantage of requiring explicit intent.
Here's an example (not included in the commit message for brevity) of a method enabled by this change.