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