1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
//! # Welcome! //! `bin_io` is a crate inspired greatly by `nom` and //! other parser combinator libraries. //! But `bin_io` differs from those crates since //! it aims at providing both reading *and* writing //! facilities at the same time, with fewer code. //! //! ## Example //! ``` //! use std::io::Cursor; //! use bin_io::{ boilerplate, seq, read, write }; //! use bin_io::numbers::{ be_u8, be_u16 }; //! //! #[derive(Clone, Debug, PartialEq, Eq)] //! struct Thing { //! a: u8, //! b: u16 //! } //! //! boilerplate!( //! fn thing_parser() -> Thing { //! seq!( //! Thing { a, b }, //! a: be_u8() => //! b: be_u16() => //! ) //! } //! ); //! //! let mut vec = Vec::new(); //! let mut cursor = Cursor::new(vec); //! //! let my_thing = Thing { //! a: 0x10, b: 0x20 //! }; //! //! write(&mut cursor, &my_thing, thing_parser()) //! .unwrap(); //! //! cursor.set_position(0); //! //! let other_thing = read(&mut cursor, thing_parser()) //! .unwrap(); //! //! assert_eq!(other_thing, my_thing); //! ``` //! # Big change in 0.2 //! In 0.2 `bin_io` had a massive change, it now uses //! references while writing, and no longer needs an owned //! copy. This meant that some things needed to change //! from the last version, but everything should still //! work fine (with minor code changes, `seq!` in particular), //! so check out the documentation! //! //! # `nom` or `bin_io`? //! `bin_io` is at a very early stage of development, so //! you might want to prefer `nom` over `bin_io` for its //! well developed stage. But still `bin_io` offers some //! unique features, and if you fell that it's missing //! something, I'm open to contrubutions! //! //! # What's happening under the hood? //! Every function that return a parser (such as `be_u8`) //! returns a *tuple* of closure, one for reading and one //! for writing. Every time you apply some other function //! (for example `bind`) the tuple is split and //! a new tuple is created (with each part calling the //! old closure respectively). Once you call `read` or `write` //! not only is the correct closure called, but the other //! type is erased, this is why once you call `read` you //! can no longer call `write` and viceversa, and you //! *always* want to wrap you parser in a function. pub mod utils; pub mod error; #[doc(hidden)] pub mod macros; pub mod numbers; pub mod strings; pub use utils::*; pub use error::BinError; use std::io::{ self, Read, Write }; type ReadDummy = Box<dyn Read>; type WriteDummy = Box<dyn Write>; /// Trait representing a read closure. pub trait ReadFn<R: Read, I>: Fn(&mut R) -> io::Result<I> { } impl<R: Read, I, F: Fn(&mut R) -> io::Result<I>> ReadFn<R, I> for F { } /// Trait representing a write closure. pub trait WriteFn<W: Write, I>: Fn(&mut W, &I) -> io::Result<()> { } impl<W: Write, I, F: Fn(&mut W, &I) -> io::Result<()>> WriteFn<W, I> for F { } /// Reads from a read/write tuple. /// /// # Examples /// ``` /// use std::io::Cursor; /// use bin_io::numbers::{ be_u8 }; /// use bin_io::read; /// /// let vec = vec![ 0x80 ]; /// let mut cursor = Cursor::new(vec); /// /// let val = read(&mut cursor, be_u8()) /// .unwrap(); /// /// assert_eq!(val, 0x80); /// ``` pub fn read<R, Rf, Wf, I>(r: &mut R, f: (Rf, Wf)) -> io::Result<I> where R: Read, Rf: ReadFn<R, I>, Wf: WriteFn<WriteDummy, I> { f.0(r) } /// Writes to a read/write tuple. /// /// # Examples /// ``` /// use std::io::Cursor; /// use bin_io::numbers::{ be_u8 }; /// use bin_io::write; /// /// let vec = Vec::new(); /// let mut cursor = Cursor::new(vec); /// /// let val = write(&mut cursor, &0x80, be_u8()) /// .unwrap(); /// /// let vec = cursor.into_inner(); /// assert_eq!(vec[0], 0x80); /// ``` pub fn write<W, Rf, Wf, I>(w: &mut W, i: &I, f: (Rf, Wf)) -> io::Result<()> where W: Write, Rf: ReadFn<ReadDummy, I>, Wf: WriteFn<W, I> { f.1(w, i) }