gaffe_xilinx/from_bytes.rs
1//! Traits and helpers for reading/writing binary formats to objects.
2
3use ::failure::Error;
4use ::failure::ResultExt;
5use ::std::io::prelude::*;
6use ::packed_struct::PackedStructSlice;
7
8/// `FromBytes` indicates that the type can be directly translated from a
9/// byte-oriented format. This is primarily used for types that represent
10/// structures used in a wire format.
11pub trait FromBytes: Sized {
12 /// Read an instance of this type from the reader.
13 ///
14 /// If successful, an instance of this type is returned and the reader now
15 /// points to the byte immediately following the returned object. If an
16 /// error occurs, the error is returned and reader is left in an
17 /// indeterminate state.
18 fn from_bytes(reader: &mut BufRead) -> Result<Self, Error>;
19}
20
21impl<T> FromBytes for T
22where
23 T: PackedStructSlice
24{
25 fn from_bytes(reader: &mut BufRead) -> Result<Self, Error> {
26 let mut packed_bytes = vec![0u8; Self::packed_bytes()];
27 reader.read_exact(&mut packed_bytes)?;
28 Ok(Self::unpack_from_slice(&packed_bytes).context("parse error")?)
29 }
30}
31
32/// `ToBytes` indicates that the type can be directly translated to a
33/// byte-oriented format. This is primarily used for types that represent
34/// structures used in a wire format.
35pub trait ToBytes: Sized {
36 /// Write an instance of this type to the writer.
37 ///
38 /// If an error occurs, the error is returned and writer is left in an
39 /// indeterminate state.
40 fn to_bytes(&self, writer: &mut Write) -> Result<(), Error>;
41}
42
43impl<T> ToBytes for T
44where
45 T: PackedStructSlice
46{
47 fn to_bytes(&self, writer: &mut Write) -> Result<(), Error>
48 {
49 let mut packed_bytes = vec![0u8; Self::packed_bytes()];
50 self.pack_to_slice(&mut packed_bytes).context("Error packing struct")?;
51 Ok(writer.write_all(&packed_bytes).context("I/O error while writing packed struct as bytes")?)
52 }
53}
54
55/// Extension to `std::io::BufRead` providing convenience methods for operations
56/// commonly used when reading binary formats.
57pub trait BufReadFromBytesExt: BufRead {
58 /// Consume bytes from this reader until `pattern` has been consumed.
59 ///
60 /// If `pattern` is found, true is returned and the reader has been
61 /// advanced to the byte immediately following the last byte of `pattern`.
62 /// Otherwise, returns false and the reader is at EOF.
63 ///
64 /// # Errors
65 ///
66 /// This function will ignore all instances of [`ErrorKind::Interrupted`] and
67 /// will otherwise return any errors returned by [`BufRead::fill_buf`].
68 ///
69 /// [`BufRead::fill_buf`]: trait.BufRead.html#method.fill_buf
70 /// [`ErrorKind::Interrupted`]: enum.ErrorKind.html#variant.Interrupted
71 ///
72 fn skip_until_match(&mut self, pattern: &[u8]) -> Result<bool, Error>
73 {
74 loop {
75 let (done, used) = {
76 let available = match self.fill_buf() {
77 Ok(n) => n,
78 Err(ref e) if e.kind() == ::std::io::ErrorKind::Interrupted => continue,
79 Err(e) => return Err(e.into())
80 };
81
82 match ::twoway::find_bytes(available, pattern) {
83 Some(index) => (true, index + pattern.len()),
84 None => (false, available.len() - pattern.len())
85 }
86 };
87 self.consume(used);
88 if done || used == 0 {
89 return Ok(done);
90 }
91 }
92 }
93}
94
95impl<T: BufRead> BufReadFromBytesExt for T {}