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