ferravex_net/
delta.rs

1//! Versioned byte snapshot differences. Callers acknowledge exact baselines before using a delta.
2use crate::{MAX_PACKET_BYTES, ProtocolError};
3#[derive(Clone, Debug, PartialEq, Eq)]
4pub struct Delta {
5    pub base_tick: u32,
6    pub tick: u32,
7    pub bytes: Vec<u8>,
8}
9impl Delta {
10    pub fn between(
11        base_tick: u32,
12        base: &[u8],
13        tick: u32,
14        next: &[u8],
15    ) -> Result<Self, ProtocolError> {
16        if base.len() != next.len() || next.len() > MAX_PACKET_BYTES - 11 {
17            return Err(ProtocolError::Invalid);
18        }
19        let mut changes = Vec::new();
20        for (i, (&a, &b)) in base.iter().zip(next).enumerate() {
21            if a != b {
22                changes.extend_from_slice(&(i as u16).to_le_bytes());
23                changes.push(b);
24            }
25        }
26        // Full snapshot fallback avoids larger packets for dense changes.
27        let mut bytes = Vec::new();
28        bytes.extend_from_slice(&(next.len() as u16).to_le_bytes());
29        if changes.len() < next.len() {
30            bytes.push(1);
31            bytes.extend(changes)
32        } else {
33            bytes.push(0);
34            bytes.extend(next)
35        }
36        Ok(Self {
37            base_tick,
38            tick,
39            bytes,
40        })
41    }
42    pub fn apply(&self, base_tick: u32, base: &[u8]) -> Result<Vec<u8>, ProtocolError> {
43        if self.base_tick != base_tick
44            || self.bytes.len() < 3
45            || base.len() > MAX_PACKET_BYTES - 11
46            || self.bytes.len() > MAX_PACKET_BYTES - 8
47        {
48            return Err(ProtocolError::Invalid);
49        }
50        let len = u16::from_le_bytes([self.bytes[0], self.bytes[1]]) as usize;
51        if len != base.len() {
52            return Err(ProtocolError::Invalid);
53        }
54        let body = &self.bytes[3..];
55        match self.bytes[2] {
56            0 if body.len() == len => Ok(body.to_vec()),
57            1 if body.len().is_multiple_of(3) => {
58                let mut result = base.to_vec();
59                let mut previous = None;
60                for entry in body.as_chunks::<3>().0 {
61                    let i = u16::from_le_bytes([entry[0], entry[1]]) as usize;
62                    if i >= len || previous.is_some_and(|p| i <= p) {
63                        return Err(ProtocolError::Invalid);
64                    }
65                    previous = Some(i);
66                    result[i] = entry[2];
67                }
68                Ok(result)
69            }
70            _ => Err(ProtocolError::Invalid),
71        }
72    }
73}
74/// Centimeter precision for a fixed world range; invalid or out-of-range values fail explicitly.
75pub fn quantize_position(value: f32) -> Option<i32> {
76    if !value.is_finite() || value.abs() > 32768.0 {
77        return None;
78    }
79    Some((value * 100.0).round() as i32)
80}
81pub fn dequantize_position(value: i32) -> Option<f32> {
82    (-3_276_800..=3_276_800)
83        .contains(&value)
84        .then_some(value as f32 / 100.0)
85}
86#[cfg(test)]
87mod tests {
88    use super::*;
89    #[test]
90    fn acknowledged_baseline_is_required_and_sparse_data_shrinks() {
91        let base = vec![0; 1000];
92        let mut next = base.clone();
93        next[20] = 4;
94        next[999] = 9;
95        let delta = Delta::between(1, &base, 2, &next).unwrap();
96        assert!(delta.bytes.len() < 20);
97        assert_eq!(delta.apply(1, &base).unwrap(), next);
98        assert!(delta.apply(0, &base).is_err());
99        let dense = Delta::between(1, &base, 2, &vec![4; 1000]).unwrap();
100        assert_eq!(dense.bytes.len(), 1003);
101        assert_eq!(dense.apply(1, &base).unwrap(), vec![4; 1000]);
102    }
103    #[test]
104    fn malformed_deltas_never_write_out_of_bounds() {
105        for bytes in [
106            vec![1, 0, 1, 2, 0, 9],
107            vec![1, 0, 1, 0, 0, 1, 0, 0, 2],
108            vec![1, 0, 2],
109            vec![],
110        ] {
111            assert!(
112                Delta {
113                    base_tick: 0,
114                    tick: 1,
115                    bytes
116                }
117                .apply(0, &[0])
118                .is_err()
119            );
120        }
121        assert!(quantize_position(f32::NAN).is_none());
122        assert!(
123            (dequantize_position(quantize_position(12.345).unwrap()).unwrap() - 12.345).abs()
124                <= 0.0051
125        );
126    }
127}