binprot/
lib.rs

1#[cfg(feature = "async")]
2pub mod async_read_write;
3#[cfg(feature = "async")]
4mod async_traits;
5
6extern crate binprot_derive;
7pub mod macros {
8    pub use binprot_derive::*;
9}
10
11// Re-export byteorder as it can be used by the macros.
12#[doc(hidden)]
13pub use ::byteorder;
14
15mod error;
16mod int;
17mod shape;
18mod traits;
19
20pub use crate::error::Error;
21pub use crate::shape::{Digestible, Shape};
22pub use crate::traits::{BinProtRead, BinProtShape, BinProtSize, BinProtWrite, ShapeContext};
23
24use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
25use std::convert::TryFrom;
26use std::hash::Hash;
27use std::io::{Read, Write};
28
29/// This uses the "size-prefixed binary protocol".
30/// https://ocaml.janestreet.com/ocaml-core/v0.13/doc/async_unix/Async_unix/Writer/index.html#val-write_bin_prot
31pub fn binprot_write_with_size<W: Write, B: BinProtWrite>(b: &B, w: &mut W) -> std::io::Result<()> {
32    let len = b.binprot_size();
33    w.write_i64::<byteorder::LittleEndian>(len as i64)?;
34    b.binprot_write(w)
35}
36
37/// This also uses the "size-prefixed binary protocol".
38pub fn binprot_read_with_size<R: Read, B: BinProtRead>(r: &mut R) -> Result<B, Error> {
39    // TODO: use the length value to avoid reading more that the specified number of bytes.
40    let _len = r.read_i64::<byteorder::LittleEndian>()?;
41    B::binprot_read(r)
42}
43
44#[derive(Debug, Clone, PartialEq, Eq, Copy)]
45pub struct Nat0(pub u64);
46
47#[derive(Debug, Clone, PartialEq, Eq)]
48pub struct Bytes(pub Vec<u8>);
49
50impl std::convert::From<String> for Bytes {
51    fn from(str: String) -> Self {
52        Bytes(str.into_bytes())
53    }
54}
55
56impl std::convert::From<&str> for Bytes {
57    fn from(str: &str) -> Self {
58        Bytes(str.as_bytes().to_vec())
59    }
60}
61
62impl std::convert::From<Vec<u8>> for Bytes {
63    fn from(v: Vec<u8>) -> Self {
64        Bytes(v)
65    }
66}
67
68impl BinProtWrite for Nat0 {
69    fn binprot_write<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
70        int::write_nat0(w, self.0)
71    }
72}
73
74impl BinProtWrite for i64 {
75    fn binprot_write<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
76        int::write_i64(w, *self as i64)
77    }
78}
79
80impl BinProtWrite for f64 {
81    fn binprot_write<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
82        w.write_all(&self.to_le_bytes())
83    }
84}
85
86impl BinProtWrite for () {
87    fn binprot_write<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
88        w.write_all(&[0u8])
89    }
90}
91
92impl BinProtWrite for bool {
93    fn binprot_write<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
94        let b = if *self { 1 } else { 0 };
95        w.write_all(&[b])
96    }
97}
98
99impl<T: BinProtWrite> BinProtWrite for Option<T> {
100    fn binprot_write<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
101        match &*self {
102            None => w.write_all(&[0u8]),
103            Some(v) => {
104                w.write_all(&[1u8])?;
105                v.binprot_write(w)
106            }
107        }
108    }
109}
110
111impl<T: BinProtWrite> BinProtWrite for Box<T> {
112    fn binprot_write<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
113        self.as_ref().binprot_write(w)
114    }
115}
116
117impl<T: BinProtWrite> BinProtWrite for Vec<T> {
118    fn binprot_write<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
119        int::write_nat0(w, self.len() as u64)?;
120        for v in self.iter() {
121            v.binprot_write(w)?
122        }
123        Ok(())
124    }
125}
126
127// Serialization using the same format as:
128// type vec32 = (float, Bigarray.float32_elt, Bigarray.fortran_layout) Bigarray.Array1.t
129// https://github.com/janestreet/bin_prot/blob/472b29dadede4d432a020be85bf34103aa26cd57/src/write.ml#L344
130impl BinProtWrite for Vec<f32> {
131    fn binprot_write<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
132        int::write_nat0(w, self.len() as u64)?;
133        for v in self.iter() {
134            w.write_f32::<byteorder::NativeEndian>(*v)?
135        }
136        Ok(())
137    }
138}
139
140impl<T: BinProtWrite> BinProtWrite for &[T] {
141    fn binprot_write<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
142        int::write_nat0(w, self.len() as u64)?;
143        for v in self.iter() {
144            v.binprot_write(w)?
145        }
146        Ok(())
147    }
148}
149
150impl BinProtWrite for String {
151    fn binprot_write<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
152        let bytes = self.as_bytes();
153        int::write_nat0(w, bytes.len() as u64)?;
154        w.write_all(bytes)
155    }
156}
157
158impl BinProtWrite for &str {
159    fn binprot_write<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
160        let bytes = self.as_bytes();
161        int::write_nat0(w, bytes.len() as u64)?;
162        w.write_all(bytes)
163    }
164}
165
166impl BinProtWrite for Bytes {
167    fn binprot_write<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
168        let bytes = &self.0;
169        int::write_nat0(w, bytes.len() as u64)?;
170        w.write_all(bytes)
171    }
172}
173
174impl<K: BinProtWrite, V: BinProtWrite> BinProtWrite for std::collections::BTreeMap<K, V> {
175    // The order is unspecified by the protocol
176    fn binprot_write<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
177        int::write_nat0(w, self.len() as u64)?;
178        for (k, v) in self.iter() {
179            k.binprot_write(w)?;
180            v.binprot_write(w)?;
181        }
182        Ok(())
183    }
184}
185
186impl<K: BinProtWrite, V: BinProtWrite> BinProtWrite for std::collections::HashMap<K, V> {
187    // The order is unspecified by the protocol
188    fn binprot_write<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
189        int::write_nat0(w, self.len() as u64)?;
190        for (k, v) in self.iter() {
191            k.binprot_write(w)?;
192            v.binprot_write(w)?;
193        }
194        Ok(())
195    }
196}
197
198macro_rules! tuple_impls {
199    ( $( $name:ident )+ ) => {
200        impl<$($name: BinProtWrite),+> BinProtWrite for ($($name,)+)
201        {
202            #[allow(non_snake_case)]
203            fn binprot_write<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
204                let ($($name,)+) = self;
205                $($name.binprot_write(w)?;)+
206                Ok(())
207            }
208        }
209
210        impl<$($name: BinProtRead),+> BinProtRead for ($($name,)+)
211        {
212            #[allow(non_snake_case)]
213            fn binprot_read<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error>
214            where
215                Self: Sized,
216            {
217                $(let $name = $name::binprot_read(r)?;)+
218                Ok(($($name,)+))
219            }
220        }
221
222        impl<$($name: BinProtShape),+> BinProtShape for ($($name,)+)
223        {
224            #[allow(non_snake_case)]
225            fn binprot_shape_impl(ctxt: &mut ShapeContext) -> Shape
226            {
227                $(let $name = <$name>::binprot_shape_loop(ctxt);)+
228                Shape::Tuple(vec![$($name,)+])
229            }
230        }
231    };
232}
233
234tuple_impls! { A }
235tuple_impls! { A B }
236tuple_impls! { A B C }
237tuple_impls! { A B C D }
238tuple_impls! { A B C D E }
239tuple_impls! { A B C D E F }
240tuple_impls! { A B C D E F G }
241tuple_impls! { A B C D E F G H }
242tuple_impls! { A B C D E F G H I }
243
244impl BinProtRead for Nat0 {
245    fn binprot_read<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error>
246    where
247        Self: Sized,
248    {
249        let u64 = int::read_nat0(r)?;
250        Ok(Nat0(u64))
251    }
252}
253
254impl BinProtRead for i64 {
255    fn binprot_read<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error>
256    where
257        Self: Sized,
258    {
259        let i64 = int::read_signed(r)?;
260        Ok(i64)
261    }
262}
263
264impl BinProtRead for f64 {
265    fn binprot_read<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error>
266    where
267        Self: Sized,
268    {
269        let f64 = r.read_f64::<LittleEndian>()?;
270        Ok(f64)
271    }
272}
273
274impl BinProtRead for () {
275    fn binprot_read<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error>
276    where
277        Self: Sized,
278    {
279        let c = r.read_u8()?;
280        if c == 0 {
281            Ok(())
282        } else {
283            Err(Error::UnexpectedValueForUnit(c))
284        }
285    }
286}
287
288impl BinProtRead for bool {
289    fn binprot_read<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error>
290    where
291        Self: Sized,
292    {
293        let c = r.read_u8()?;
294        if c == 0 {
295            Ok(false)
296        } else if c == 1 {
297            Ok(true)
298        } else {
299            Err(Error::UnexpectedValueForBool(c))
300        }
301    }
302}
303
304impl<T: BinProtRead> BinProtRead for Option<T> {
305    fn binprot_read<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error>
306    where
307        Self: Sized,
308    {
309        let c = r.read_u8()?;
310        if c == 0 {
311            Ok(None)
312        } else if c == 1 {
313            let v = T::binprot_read(r)?;
314            Ok(Some(v))
315        } else {
316            Err(Error::UnexpectedValueForOption(c))
317        }
318    }
319}
320
321impl<T: BinProtRead> BinProtRead for Box<T> {
322    fn binprot_read<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error>
323    where
324        Self: Sized,
325    {
326        let v = T::binprot_read(r)?;
327        Ok(Box::new(v))
328    }
329}
330
331impl<T: BinProtRead> BinProtRead for Vec<T> {
332    fn binprot_read<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error>
333    where
334        Self: Sized,
335    {
336        let len = int::read_nat0(r)?;
337        let mut v: Vec<T> = Vec::new();
338        for _i in 0..len {
339            let item = T::binprot_read(r)?;
340            v.push(item)
341        }
342        Ok(v)
343    }
344}
345
346// Serialization using the same format as:
347// type vec32 = (float, Bigarray.float32_elt, Bigarray.fortran_layout) Bigarray.Array1.t
348// https://github.com/janestreet/bin_prot/blob/472b29dadede4d432a020be85bf34103aa26cd57/src/write.ml#L344
349impl BinProtRead for Vec<f32> {
350    fn binprot_read<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error>
351    where
352        Self: Sized,
353    {
354        let len = int::read_nat0(r)?;
355        let mut v: Vec<f32> = Vec::new();
356        for _i in 0..len {
357            let item = r.read_f32::<byteorder::NativeEndian>()?;
358            v.push(item)
359        }
360        Ok(v)
361    }
362}
363
364impl<K: BinProtRead + Ord, V: BinProtRead> BinProtRead for std::collections::BTreeMap<K, V> {
365    fn binprot_read<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error>
366    where
367        Self: Sized,
368    {
369        let len = int::read_nat0(r)?;
370        let mut res = std::collections::BTreeMap::new();
371        for _i in 0..len {
372            let k = K::binprot_read(r)?;
373            let v = V::binprot_read(r)?;
374            if res.insert(k, v).is_some() {
375                return Err(Error::SameKeyAppearsTwiceInMap);
376            }
377        }
378        Ok(res)
379    }
380}
381
382impl<K: BinProtRead + Hash + Eq, V: BinProtRead> BinProtRead for std::collections::HashMap<K, V> {
383    fn binprot_read<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error>
384    where
385        Self: Sized,
386    {
387        let len = int::read_nat0(r)?;
388        let mut res = std::collections::HashMap::new();
389        for _i in 0..len {
390            let k = K::binprot_read(r)?;
391            let v = V::binprot_read(r)?;
392            if res.insert(k, v).is_some() {
393                return Err(Error::SameKeyAppearsTwiceInMap);
394            }
395        }
396        Ok(res)
397    }
398}
399
400impl BinProtRead for String {
401    fn binprot_read<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error>
402    where
403        Self: Sized,
404    {
405        let len = int::read_nat0(r)?;
406        let mut buf: Vec<u8> = vec![0u8; len as usize];
407        r.read_exact(&mut buf)?;
408        let str = std::str::from_utf8(&buf)?;
409        Ok(str.to_string())
410    }
411}
412
413impl BinProtRead for Bytes {
414    fn binprot_read<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error>
415    where
416        Self: Sized,
417    {
418        let len = int::read_nat0(r)?;
419        let mut buf: Vec<u8> = vec![0u8; len as usize];
420        r.read_exact(&mut buf)?;
421        Ok(Bytes(buf))
422    }
423}
424
425/// A value serialized by first having its size as a nat0, then the
426/// encoding of the value itself.
427#[derive(Debug, Clone, PartialEq, Eq)]
428pub struct WithLen<T>(pub T);
429
430impl<T: BinProtWrite + BinProtSize> BinProtWrite for WithLen<T> {
431    fn binprot_write<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
432        let len = self.0.binprot_size();
433        int::write_nat0(w, len as u64)?;
434        self.0.binprot_write(w)
435    }
436}
437
438impl<T: BinProtRead> BinProtRead for WithLen<T> {
439    fn binprot_read<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error>
440    where
441        Self: Sized,
442    {
443        // TODO: stop reading past this length
444        let _len = int::read_nat0(r)?;
445        let t = T::binprot_read(r)?;
446        Ok(WithLen(t))
447    }
448}
449
450/// A buffer serialized as its size first as a nat0, then the payload itself.
451#[derive(Debug, Clone, PartialEq)]
452pub struct BufferWithLen(pub Vec<u8>);
453
454impl BinProtRead for BufferWithLen {
455    fn binprot_read<R: std::io::Read + ?Sized>(r: &mut R) -> Result<Self, Error>
456    where
457        Self: Sized,
458    {
459        let len = Nat0::binprot_read(r)?;
460        let mut buf: Vec<u8> = vec![0u8; len.0 as usize];
461        r.read_exact(&mut buf)?;
462        Ok(BufferWithLen(buf))
463    }
464}
465
466impl BinProtWrite for BufferWithLen {
467    fn binprot_write<W: std::io::Write>(&self, w: &mut W) -> Result<(), std::io::Error> {
468        let nat0 = Nat0(self.0.len() as u64);
469        nat0.binprot_write(w)?;
470        w.write_all(&self.0)?;
471        Ok(())
472    }
473}
474
475// Maybe this could be done with some clever use of traits rather
476// than a macro but in doing so, I ended up with some potential
477// conflicts: "downstream crates may implement trait".
478macro_rules! int_impls {
479    ( $ty: ty) => {
480        impl BinProtWrite for $ty {
481            fn binprot_write<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
482                int::write_i64(w, (*self).into())
483            }
484        }
485
486        impl BinProtRead for $ty {
487            fn binprot_read<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error>
488            where
489                Self: Sized,
490            {
491                let i64 = int::read_signed(r)?;
492                Ok(<$ty>::try_from(i64)?)
493            }
494        }
495    };
496}
497
498int_impls!(i32);
499int_impls!(u32);
500int_impls!(i16);
501int_impls!(u16);
502int_impls!(i8);
503int_impls!(u8);