1 use std::io::{Result, Read, Write};
2 use ctx::{FromCtx, IntoCtx, SizeWith};
3 
4 /// An extension trait to `std::io::Read` streams; this only deserializes simple types, like `u8`, `i32`, `f32`, `usize`, etc.
5 ///
6 /// If you implement [`FromCtx`](trait.FromCtx.html) and [`SizeWith`](ctx/trait.SizeWith.html) for your type, you can then `ioread::<YourType>()` on a `Read`.  Note: [`FromCtx`](trait.FromCtx.html) is only meant for very simple types, and should _never_ fail.
7 ///
8 /// **NB** You should probably add `repr(packed)` or `repr(C)` and be very careful how you implement [`SizeWith`](ctx/trait.SizeWith.html), otherwise you
9 /// will get IO errors failing to fill entire buffer (the size you specified in `SizeWith`), or out of bound errors (depending on your impl) in `from_ctx`
10 ///
11 /// # Example
12 /// ```rust
13 /// use std::io::Cursor;
14 /// use scroll::{self, ctx, LE, Pread, IOread};
15 ///
16 /// #[repr(packed)]
17 /// struct Foo {
18 ///     foo: i64,
19 ///     bar: u32,
20 /// }
21 ///
22 /// impl ctx::FromCtx<scroll::Endian> for Foo {
23 ///     fn from_ctx(bytes: &[u8], ctx: scroll::Endian) -> Self {
24 ///         Foo { foo: bytes.pread_with::<i64>(0, ctx).unwrap(), bar: bytes.pread_with::<u32>(8, ctx).unwrap() }
25 ///     }
26 /// }
27 ///
28 /// impl ctx::SizeWith<scroll::Endian> for Foo {
29 ///     type Units = usize;
30 ///     // our parsing context doesn't influence our size
31 ///     fn size_with(_: &scroll::Endian) -> Self::Units {
32 ///         ::std::mem::size_of::<Foo>()
33 ///     }
34 /// }
35 ///
36 /// let bytes_ = [0x0b,0x0b,0x00,0x00,0x00,0x00,0x00,0x00, 0xef,0xbe,0x00,0x00,];
37 /// let mut bytes = Cursor::new(bytes_);
38 /// let foo = bytes.ioread_with::<i64>(LE).unwrap();
39 /// let bar = bytes.ioread_with::<u32>(LE).unwrap();
40 /// assert_eq!(foo, 0xb0b);
41 /// assert_eq!(bar, 0xbeef);
42 /// let error = bytes.ioread_with::<f64>(LE);
43 /// assert!(error.is_err());
44 /// let mut bytes = Cursor::new(bytes_);
45 /// let foo_ = bytes.ioread_with::<Foo>(LE).unwrap();
46 /// // Remember that you need to copy out fields from packed structs
47 /// // with a `{}` block instead of borrowing them directly
48 /// // ref: https://github.com/rust-lang/rust/issues/46043
49 /// assert_eq!({foo_.foo}, foo);
50 /// assert_eq!({foo_.bar}, bar);
51 /// ```
52 ///
53 pub trait IOread<Ctx: Copy> : Read
54 {
55     /// Reads the type `N` from `Self`, with a default parsing context.
56     /// For the primitive numeric types, this will be at the host machine's endianness.
57     ///
58     /// # Example
59     /// ```rust
60     /// use scroll::IOread;
61     /// use std::io::Cursor;
62     /// let bytes = [0xef, 0xbe];
63     /// let mut bytes = Cursor::new(&bytes[..]);
64     /// let beef = bytes.ioread::<u16>().unwrap();
65     ///
66     /// #[cfg(target_endian = "little")]
67     /// assert_eq!(0xbeef, beef);
68     /// #[cfg(target_endian = "big")]
69     /// assert_eq!(0xefbe, beef);
70     /// ```
71     #[inline]
ioread<N: FromCtx<Ctx> + SizeWith<Ctx, Units = usize>>(&mut self) -> Result<N> where Ctx: Default72     fn ioread<N: FromCtx<Ctx> + SizeWith<Ctx, Units = usize>>(&mut self) -> Result<N> where Ctx: Default {
73         let ctx = Ctx::default();
74         self.ioread_with(ctx)
75     }
76 
77     /// Reads the type `N` from `Self`, with the parsing context `ctx`.
78     /// **NB**: this will panic if the type you're reading has a size greater than 256. Plans are to have this allocate in larger cases.
79     ///
80     /// For the primitive numeric types, this will be at the host machine's endianness.
81     ///
82     /// # Example
83     /// ```rust
84     /// use scroll::{IOread, LE, BE};
85     /// use std::io::Cursor;
86     /// let bytes = [0xef, 0xbe, 0xb0, 0xb0, 0xfe, 0xed, 0xde, 0xad];
87     /// let mut bytes = Cursor::new(&bytes[..]);
88     /// let beef = bytes.ioread_with::<u16>(LE).unwrap();
89     /// assert_eq!(0xbeef, beef);
90     /// let b0 = bytes.ioread::<u8>().unwrap();
91     /// assert_eq!(0xb0, b0);
92     /// let b0 = bytes.ioread::<u8>().unwrap();
93     /// assert_eq!(0xb0, b0);
94     /// let feeddead = bytes.ioread_with::<u32>(BE).unwrap();
95     /// assert_eq!(0xfeeddead, feeddead);
96     /// ```
97     #[inline]
ioread_with<N: FromCtx<Ctx> + SizeWith<Ctx, Units = usize>>(&mut self, ctx: Ctx) -> Result<N>98     fn ioread_with<N: FromCtx<Ctx> + SizeWith<Ctx, Units = usize>>(&mut self, ctx: Ctx) -> Result<N> {
99         let mut scratch = [0u8; 256];
100         let size = N::size_with(&ctx);
101         let mut buf = &mut scratch[0..size];
102         self.read_exact(&mut buf)?;
103         Ok(N::from_ctx(buf, ctx))
104     }
105 }
106 
107 /// Types that implement `Read` get methods defined in `IOread`
108 /// for free.
109 impl<Ctx: Copy, R: Read + ?Sized> IOread<Ctx> for R {}
110 
111 /// An extension trait to `std::io::Write` streams; this only serializes simple types, like `u8`, `i32`, `f32`, `usize`, etc.
112 ///
113 /// To write custom types with a single `iowrite::<YourType>` call, implement [`IntoCtx`](trait.IntoCtx.html) and [`SizeWith`](ctx/trait.SizeWith.html) for `YourType`.
114 pub trait IOwrite<Ctx: Copy>: Write
115 {
116     /// Writes the type `N` into `Self`, with the parsing context `ctx`.
117     /// **NB**: this will panic if the type you're writing has a size greater than 256. Plans are to have this allocate in larger cases.
118     ///
119     /// For the primitive numeric types, this will be at the host machine's endianness.
120     ///
121     /// # Example
122     /// ```rust
123     /// use scroll::IOwrite;
124     /// use std::io::Cursor;
125     ///
126     /// let mut bytes = [0x0u8; 4];
127     /// let mut bytes = Cursor::new(&mut bytes[..]);
128     /// bytes.iowrite(0xdeadbeef as u32).unwrap();
129     ///
130     /// #[cfg(target_endian = "little")]
131     /// assert_eq!(bytes.into_inner(), [0xef, 0xbe, 0xad, 0xde,]);
132     /// #[cfg(target_endian = "big")]
133     /// assert_eq!(bytes.into_inner(), [0xde, 0xad, 0xbe, 0xef,]);
134     /// ```
135     #[inline]
iowrite<N: SizeWith<Ctx, Units = usize> + IntoCtx<Ctx>>(&mut self, n: N) -> Result<()> where Ctx: Default136     fn iowrite<N: SizeWith<Ctx, Units = usize> + IntoCtx<Ctx>>(&mut self, n: N) -> Result<()> where Ctx: Default {
137         let ctx = Ctx::default();
138         self.iowrite_with(n, ctx)
139     }
140 
141     /// Writes the type `N` into `Self`, with the parsing context `ctx`.
142     /// **NB**: this will panic if the type you're writing has a size greater than 256. Plans are to have this allocate in larger cases.
143     ///
144     /// For the primitive numeric types, this will be at the host machine's endianness.
145     ///
146     /// # Example
147     /// ```rust
148     /// use scroll::{IOwrite, LE, BE};
149     /// use std::io::{Write, Cursor};
150     ///
151     /// let mut bytes = [0x0u8; 10];
152     /// let mut cursor = Cursor::new(&mut bytes[..]);
153     /// cursor.write_all(b"hello").unwrap();
154     /// cursor.iowrite_with(0xdeadbeef as u32, BE).unwrap();
155     /// assert_eq!(cursor.into_inner(), [0x68, 0x65, 0x6c, 0x6c, 0x6f, 0xde, 0xad, 0xbe, 0xef, 0x0]);
156     /// ```
157     #[inline]
iowrite_with<N: SizeWith<Ctx, Units = usize> + IntoCtx<Ctx>>(&mut self, n: N, ctx: Ctx) -> Result<()>158     fn iowrite_with<N: SizeWith<Ctx, Units = usize> + IntoCtx<Ctx>>(&mut self, n: N, ctx: Ctx) -> Result<()> {
159         let mut buf = [0u8; 256];
160         let size = N::size_with(&ctx);
161         let buf = &mut buf[0..size];
162         n.into_ctx(buf, ctx);
163         self.write_all(buf)?;
164         Ok(())
165     }
166 }
167 
168 /// Types that implement `Write` get methods defined in `IOwrite`
169 /// for free.
170 impl<Ctx: Copy, W: Write + ?Sized> IOwrite<Ctx> for W {}
171