1use 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 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}
74pub 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}