Coverage Report

Created: 2026-11-11 06:34

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