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 141 142 143 144 145 146 147 148 149
/*! This crate provides a convenient way of reading and writing bytes to a buffer that implements the standard [`Read`] or [`Write`] traits. Supported std types include [`u8`], [`u16`], [`u32`], [`u64`], [`i8`], [`i16`], [`i32`], [`i64`], [`String`], [`Vec<T>`] and [`HashMap<T, V>`]. Reading and writing of these types is done using the [`byteorder`] crate. # Installation Add the following to your `Cargo.toml` file: ```toml [dependencies] bytestream = "0.*" ``` # Examples ```rust use std::io::{Cursor, Read, Result, Write}; use bytestream::*; #[derive(Debug, PartialEq)] pub struct Foo { bar: String, baz: u32, } impl Streamable for Foo { fn read_from<R: Read>(buffer: &mut R, order: ByteOrder) -> Result<Self> { Ok(Self { bar: String::read_from(buffer, order)?, baz: u32::read_from(buffer, order)?, }) } fn write_to<W: Write>(&self, buffer: &mut W, order: ByteOrder) -> Result<()> { self.bar.write_to(buffer, order)?; self.baz.write_to(buffer, order)?; Ok(()) } } // Create a buffer that implements the `Write` trait let mut buffer = Vec::<u8>::new(); // Write some data to the buffer let foo = Foo { bar: "corgi".to_owned(), baz: 37 }; foo.write_to(&mut buffer, ByteOrder::BigEndian).unwrap(); // Read the data back from the buffer // We wrap the buffer in a Cursor::<T> that implements the `Read` trait let mut cursor = Cursor::new(buffer); let other = Foo::read_from(&mut cursor, ByteOrder::BigEndian).unwrap(); assert_eq!(foo, other); ``` # Exclude `Streamable` support for std types If you do not wish to include out-of-the-box support for std types, you can exclude the default `batteries-included` feature in your `Cargo.toml` file: ```toml [dependencies] bytestream = { Version = "0.*", default-features = false } ``` Exluding the `batteries-included` feature will also remove the `byteorder` crate dependency. # Credits The inspiration from this crate came from the [`Stevenarella`] Minecraft client. [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html [`byteorder`]: https://github.com/BurntSushi/byteorder [`u8`]: https://doc.rust-lang.org/std/primitive.u8.html [`u16`]: https://doc.rust-lang.org/std/primitive.u16.html [`u32`]: https://doc.rust-lang.org/std/primitive.u32.html [`u64`]: https://doc.rust-lang.org/std/primitive.u64.html [`i8`]: https://doc.rust-lang.org/std/primitive.i8.html [`i16`]: https://doc.rust-lang.org/std/primitive.i16.html [`i32`]: https://doc.rust-lang.org/std/primitive.i32.html [`i64`]: https://doc.rust-lang.org/std/primitive.i64.html [`String`]: https://doc.rust-lang.org/std/string/struct.String.html [`Vec<T>`]: https://doc.rust-lang.org/std/vec/struct.Vec.html [`HashMap<T, V>`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html [`Stevenarella`]: https://github.com/iceiix/stevenarella */ #![deny(missing_docs)] use std::io::{Read, Result, Write}; #[cfg(feature = "batteries-included")] mod optional; #[cfg(feature = "batteries-included")] pub use optional::*; /// `ByteOrder` describes what order to write bytes to the buffer. #[derive(Copy, Clone)] pub enum ByteOrder { /// Represents big endian byte order (also called network endian). /// This is the default order if none is specified. BigEndian, /// Represents little endian byte order. LittleEndian, } /// The streamable trait allows for reading and writing /// bytes to and from a buffer. /// /// # Example /// /// ``` /// use std::io::{Read, Result, Write}; /// use bytestream::*; /// /// pub struct Foo { /// bar: String, /// baz: u32, /// } /// /// impl Streamable for Foo { /// fn read_from<R: Read>(buffer: &mut R, order: ByteOrder) -> Result<Self> { /// Ok(Self { /// bar: String::read_from(buffer, order)?, /// baz: u32::read_from(buffer, order)?, /// }) /// } /// fn write_to<W: Write>(&self, buffer: &mut W, order: ByteOrder) -> Result<()> { /// self.bar.write_to(buffer, order)?; /// self.baz.write_to(buffer, order)?; /// Ok(()) /// } /// } /// ``` pub trait Streamable: Sized { /// Reads something from the specified buffer using the specified byte order. fn read_from<R: Read>(buffer: &mut R, order: ByteOrder) -> Result<Self>; /// Writes something to the specified buffer using the specified byte order. fn write_to<W: Write>(&self, buffer: &mut W, order: ByteOrder) -> Result<()>; }