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 {}