bradis/pack/
packable.rs

1use crate::{
2    buffer::{ArrayBuffer, Buffer},
3    bytes::parse_i64_exact,
4    PackRef, PackValue,
5};
6use bytes::{BufMut, Bytes};
7
8/// A trait for values that can be directly written to a [`Pack`][`crate::Pack`].
9pub trait Packable {
10    /// The size of the packed value, including the trailing length.
11    fn pack_size(&self) -> usize;
12
13    /// Write this packable value to a buffer.
14    fn pack_write(&self, buffer: impl BufMut);
15
16    /// Compare a packable value with a [`PackRef`] in an existing [`Pack`][`crate::Pack`].
17    fn pack_eq<'a>(&'a self, other: &PackRef<'a>) -> bool;
18}
19
20impl Packable for f64 {
21    fn pack_size(&self) -> usize {
22        10
23    }
24
25    fn pack_write(&self, mut buffer: impl BufMut) {
26        buffer.put_u8(0xf5);
27        buffer.put_f64_le(*self);
28        buffer.put_u8(9);
29    }
30
31    fn pack_eq<'a>(&'a self, other: &PackRef<'a>) -> bool {
32        let mut buffer = ArrayBuffer::default();
33
34        use PackRef::*;
35        match other {
36            Float(other) => self == other,
37            Integer(other) => {
38                if self.fract() == 0f64 {
39                    #[allow(clippy::cast_possible_truncation)]
40                    let i = *self as i64;
41                    i == *other
42                } else {
43                    false
44                }
45            }
46            Slice(other) => buffer.write_f64(*self) == &other[..],
47        }
48    }
49}
50
51impl Packable for i64 {
52    fn pack_size(&self) -> usize {
53        match self {
54            // u7
55            0..=0x7f => 2,
56            // i13
57            -0x1000..=0xfff => 3,
58            // i16
59            -0x8000..=0x7fff => 4,
60            // i24
61            -0x0080_0000..=0x007f_ffff => 5,
62            // i32
63            -0x8000_0000..=0x7fff_ffff => 6,
64            // i64
65            _ => 10,
66        }
67    }
68
69    fn pack_write(&self, mut buffer: impl BufMut) {
70        match self {
71            // u7
72            0..=0x7f => {
73                buffer.put_int_le(*self, 1);
74                buffer.put_u8(1);
75            }
76            // i13
77            -0x1000..=0xfff => {
78                let bytes = self.to_be_bytes();
79                buffer.put_u8(0xc0 | (0xdf & bytes[6]));
80                buffer.put_u8(bytes[7]);
81                buffer.put_u8(2);
82            }
83            // i16
84            -0x8000..=0x7fff => {
85                buffer.put_u8(0xf1);
86                buffer.put_int_le(*self, 2);
87                buffer.put_u8(3);
88            }
89            // i24
90            -0x0080_0000..=0x007f_ffff => {
91                buffer.put_u8(0xf2);
92                buffer.put_int_le(*self, 3);
93                buffer.put_u8(4);
94            }
95            // i32
96            -0x8000_0000..=0x7fff_ffff => {
97                buffer.put_u8(0xf3);
98                buffer.put_int_le(*self, 4);
99                buffer.put_u8(5);
100            }
101            // i64
102            _ => {
103                buffer.put_u8(0xf4);
104                buffer.put_i64_le(*self);
105                buffer.put_u8(9);
106            }
107        }
108    }
109
110    fn pack_eq<'a>(&'a self, other: &PackRef<'a>) -> bool {
111        use PackRef::*;
112        match other {
113            Float(f) => {
114                if f.fract() == 0f64 {
115                    #[allow(clippy::cast_possible_truncation)]
116                    let i = *f as i64;
117                    i == *self
118                } else {
119                    false
120                }
121            }
122            Integer(i) => self == i,
123            Slice(s) => match parse_i64_exact(&s[..]) {
124                Some(i) => *self == i,
125                None => false,
126            },
127        }
128    }
129}
130
131impl Packable for &[u8] {
132    fn pack_size(&self) -> usize {
133        if let Some(i) = parse_i64_exact(self) {
134            return i.pack_size();
135        }
136
137        match self.len() {
138            0..=0x3f => self.len() + 2,
139            0x40..=0xfff => self.len() + 2 + back_len_size(self.len() + 2),
140            0x1000..=0xffff_ffff => self.len() + 5 + back_len_size(self.len() + 5),
141            _ => todo!("xl string"),
142        }
143    }
144
145    fn pack_write(&self, mut buffer: impl BufMut) {
146        if let Some(i) = parse_i64_exact(self) {
147            return i.pack_write(buffer);
148        }
149
150        match self.len() {
151            0..=0x3f => {
152                buffer.put_u8(0x80 | u8::try_from(self.len()).unwrap());
153                buffer.put_slice(self);
154                write_back_len(self.len() + 1, buffer);
155            }
156            0x40..=0xfff => {
157                let len = u16::try_from(self.len()).unwrap();
158                buffer.put_u16(0xe000 | (0x0fff & len));
159                buffer.put_slice(self);
160                write_back_len(self.len() + 2, buffer);
161            }
162            0x1000..=0xffff_ffff => {
163                buffer.put_u8(0xf0);
164                buffer.put_u32_le(u32::try_from(self.len()).unwrap());
165                buffer.put_slice(self);
166                write_back_len(self.len() + 5, buffer);
167            }
168            _ => todo!("xl string"),
169        }
170    }
171
172    fn pack_eq<'a>(&'a self, other: &PackRef<'a>) -> bool {
173        let mut buffer = ArrayBuffer::default();
174
175        use PackRef::*;
176        match other {
177            Float(f) => &self[..] == buffer.write_f64(*f),
178            Integer(i) => match parse_i64_exact(&self[..]) {
179                Some(parsed) => *i == parsed,
180                None => false,
181            },
182            Slice(s) => self[..] == s[..],
183        }
184    }
185}
186
187impl Packable for Bytes {
188    fn pack_size(&self) -> usize {
189        (&self[..]).pack_size()
190    }
191
192    fn pack_write(&self, buffer: impl BufMut) {
193        (&self[..]).pack_write(buffer);
194    }
195
196    fn pack_eq<'a>(&'a self, other: &PackRef<'a>) -> bool {
197        (&self[..]).pack_eq(other)
198    }
199}
200
201impl Packable for &str {
202    fn pack_size(&self) -> usize {
203        self.as_bytes().pack_size()
204    }
205
206    fn pack_write(&self, buffer: impl BufMut) {
207        self.as_bytes().pack_write(buffer);
208    }
209
210    fn pack_eq<'a>(&'a self, other: &PackRef<'a>) -> bool {
211        self.as_bytes().pack_eq(other)
212    }
213}
214
215impl Packable for PackRef<'_> {
216    fn pack_size(&self) -> usize {
217        use PackRef::*;
218        match self {
219            Float(f) => f.pack_size(),
220            Integer(i) => i.pack_size(),
221            Slice(s) => (&s[..]).pack_size(),
222        }
223    }
224
225    fn pack_write(&self, buffer: impl BufMut) {
226        use PackRef::*;
227        match self {
228            Float(f) => f.pack_write(buffer),
229            Integer(i) => i.pack_write(buffer),
230            Slice(s) => (&s[..]).pack_write(buffer),
231        }
232    }
233
234    fn pack_eq<'a>(&'a self, other: &PackRef<'a>) -> bool {
235        use PackRef::*;
236        match self {
237            Float(f) => f.pack_eq(other),
238            Integer(i) => i.pack_eq(other),
239            Slice(s) => (&s[..]).pack_eq(other),
240        }
241    }
242}
243
244impl Packable for PackValue {
245    fn pack_size(&self) -> usize {
246        use PackValue::*;
247        match self {
248            Float(f) => f.pack_size(),
249            Integer(i) => i.pack_size(),
250            Raw(s) => (&s[..]).pack_size(),
251        }
252    }
253
254    fn pack_write(&self, buffer: impl BufMut) {
255        use PackValue::*;
256        match self {
257            Float(f) => f.pack_write(buffer),
258            Integer(i) => i.pack_write(buffer),
259            Raw(s) => (&s[..]).pack_write(buffer),
260        }
261    }
262
263    fn pack_eq<'a>(&'a self, other: &PackRef<'a>) -> bool {
264        use PackValue::*;
265        match self {
266            Float(f) => f.pack_eq(other),
267            Integer(i) => i.pack_eq(other),
268            Raw(s) => (&s[..]).pack_eq(other),
269        }
270    }
271}
272
273fn back_len_size(mut len: usize) -> usize {
274    let mut size = 0;
275    while len > 0 {
276        size += 1;
277        len >>= 7;
278    }
279    size
280}
281
282fn write_back_len(mut len: usize, mut buffer: impl BufMut) {
283    buffer.put_u8(u8::try_from(0x7f & len).unwrap());
284    len >>= 7;
285    while len > 0 {
286        buffer.put_u8(0x80 | u8::try_from(0x7f & len).unwrap());
287        len >>= 7;
288    }
289}
290
291#[cfg(test)]
292mod tests {
293    use super::*;
294    use crate::Pack;
295
296    macro_rules! assert_back_len {
297        ($len:expr, $expected:expr) => {{
298            let mut buffer: Vec<u8> = Vec::new();
299            write_back_len($len, &mut buffer);
300            assert_eq!(&buffer[..], &$expected[..]);
301        }};
302    }
303
304    #[test]
305    fn test_back_len_size() {
306        assert_eq!(back_len_size(0x01), 1);
307        assert_eq!(back_len_size(0x7f), 1);
308
309        assert_eq!(back_len_size(0x80), 2);
310        assert_eq!(back_len_size(0x81), 2);
311        assert_eq!(back_len_size(0x3fff), 2);
312
313        assert_eq!(back_len_size(0x4000), 3);
314        assert_eq!(back_len_size(0x4001), 3);
315        assert_eq!(back_len_size(0x1fffff), 3);
316
317        assert_eq!(back_len_size(0x200000), 4);
318        assert_eq!(back_len_size(0x200001), 4);
319        assert_eq!(back_len_size(0xfffffff), 4);
320
321        assert_eq!(back_len_size(0x10000000), 5);
322        assert_eq!(back_len_size(0x10000001), 5);
323    }
324
325    #[test]
326    fn test_write_back_len() {
327        // One byte
328        assert_back_len!(0x01, b"\x01");
329        assert_back_len!(0x02, b"\x02");
330        assert_back_len!(0x7f, b"\x7f");
331
332        // Two bytes
333        assert_back_len!(0x80, b"\x00\x81");
334        assert_back_len!(0x81, b"\x01\x81");
335        assert_back_len!(0x3fff, b"\x7f\xff");
336
337        // Three bytes
338        assert_back_len!(0x4000, b"\x00\x80\x81");
339        assert_back_len!(0x4001, b"\x01\x80\x81");
340        assert_back_len!(0x1fffff, b"\x7f\xff\xff");
341
342        // Four bytes
343        assert_back_len!(0x200000, b"\x00\x80\x80\x81");
344        assert_back_len!(0x200001, b"\x01\x80\x80\x81");
345        assert_back_len!(0xfffffff, b"\x7f\xff\xff\xff");
346
347        // Five bytes
348        assert_back_len!(0x10000000, b"\x00\x80\x80\x80\x81");
349        assert_back_len!(0x10000001, b"\x01\x80\x80\x80\x81");
350    }
351
352    #[test]
353    fn test_pack_eq() {
354        let mut pack = Pack::default();
355        pack.append(&1234);
356        pack.append(&12.34f64);
357        pack.append(&"12.34");
358        pack.append(&12f64);
359        pack.append(&"12");
360        let mut iter = pack.iter();
361
362        let i = iter.next().unwrap();
363        assert!("1234".pack_eq(&i));
364        assert!(1234f64.pack_eq(&i));
365        assert!(!1234.2f64.pack_eq(&i));
366
367        let f = iter.next().unwrap();
368        assert!("12.34".pack_eq(&f));
369
370        let s = iter.next().unwrap();
371        assert!(12.34f64.pack_eq(&s));
372
373        let f = iter.next().unwrap();
374        assert!(12i64.pack_eq(&f));
375        assert!(!13i64.pack_eq(&f));
376
377        let s = iter.next().unwrap();
378        assert!(12i64.pack_eq(&s));
379        assert!(!13i64.pack_eq(&s));
380    }
381}