use num_traits::WrappingSub;
#[derive(Debug, Default, Copy, Clone)]
pub struct DeltaEncoder<T> {
current: T,
}
impl<T: WrappingSub + Copy> DeltaEncoder<T> {
pub fn encode(&mut self, value: T) -> T {
let delta = value.wrapping_sub(&self.current);
self.current = value;
delta
}
}
#[derive(Clone, Debug)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct DeltaEncoderIter<I>
where
I: Iterator,
<I as Iterator>::Item: WrappingSub + Copy,
{
iter: I,
encoder: DeltaEncoder<I::Item>,
}
impl<I> Iterator for DeltaEncoderIter<I>
where
I: Iterator,
<I as Iterator>::Item: WrappingSub + Copy,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
Some(self.encoder.encode(self.iter.next()?))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<I> ExactSizeIterator for DeltaEncoderIter<I>
where
I: ExactSizeIterator,
<I as Iterator>::Item: WrappingSub + Copy,
{
}
pub trait DeltaEncoderExt: Iterator
where
<Self as Iterator>::Item: Default + Copy + WrappingSub,
{
fn deltas(self) -> DeltaEncoderIter<Self>
where
Self: Sized,
{
DeltaEncoderIter {
iter: self,
encoder: DeltaEncoder::default(),
}
}
}
impl<I> DeltaEncoderExt for I
where
I: Iterator,
<I as Iterator>::Item: Default + Copy + WrappingSub,
{
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tests::TEST_DATA;
fn run(original: &[i64], encoded: &[i64]) {
let mut enc = DeltaEncoder::default();
let result: Vec<i64> = original.iter().map(|&v| enc.encode(v)).collect();
assert_eq!(result, encoded, "encoded from: {original:?}");
let result: Vec<i64> = original.iter().copied().deltas().collect();
assert_eq!(result, encoded, "iter().copied() original: {original:?}");
}
#[test]
fn test() {
for &(original, encoded) in TEST_DATA {
run(original, encoded);
}
}
}