/rust/registry/src/index.crates.io-1949cf8c6b5b557f/scroll-0.10.2/src/pread.rs
Line | Count | Source |
1 | | use core::result; |
2 | | use core::ops::{Index, RangeFrom}; |
3 | | |
4 | | use crate::ctx::{TryFromCtx, MeasureWith}; |
5 | | use crate::error; |
6 | | |
7 | | /// A very generic, contextual pread interface in Rust. |
8 | | /// |
9 | | /// Like [Pwrite](trait.Pwrite.html) — but for reading! |
10 | | /// |
11 | | /// Implementing `Pread` on a data store allows you to then read almost arbitrarily complex types |
12 | | /// efficiently. |
13 | | /// |
14 | | /// To this end the Pread trait works in conjuction with the [TryFromCtx](ctx/trait.TryFromCtx.html); |
15 | | /// The `TryFromCtx` trait implemented on a type defines how to convert data to an object of that |
16 | | /// type, the Pread trait implemented on a data store defines how to extract said data from that |
17 | | /// store. |
18 | | /// |
19 | | /// It should be noted though that in this context, data does not necessarily mean `&[u8]` — |
20 | | /// `Pread` and `TryFromCtx` are generic over what 'data' means and could be implemented instead |
21 | | /// over chunks of memory or any other indexable type — but scroll does come with a set of powerful |
22 | | /// blanket implementations for data being a continous block of byte-addressable memory. |
23 | | /// |
24 | | /// Pread provides two main groups of functions: pread and gread. |
25 | | /// |
26 | | /// `pread` is the basic function that simply extracts a given type from a given data store - either |
27 | | /// using a provided Context in the case of [pread_with](trait.Pread.html#method.pread_with) or |
28 | | /// with the default context for the given type in the case of [pread](trait.Pread.html#method.pread) |
29 | | /// |
30 | | /// `gread` does in addition to that update the offset it's currently at, allowing for a cursored |
31 | | /// read — `gread_inout` expands on that and reads a number of continous types from the data store. |
32 | | /// gread again comes with `_with` variants to allow using a specific context. |
33 | | /// |
34 | | /// Since pread and friends are very generic functions their types are rather complex, but very |
35 | | /// much understandable; `TryFromCtx` is generic over `Ctx` ([described |
36 | | /// here](ctx/index.html#context)), `Output` and `Error`. The Error type is hopefully |
37 | | /// self-explanatory, however the `Output` type is rather important; it defines what Pread extracts |
38 | | /// from the data store and has to match up with what `TryFromCtx` expects as input to convert into |
39 | | /// the resulting type. scroll defaults to `&[u8]` here. |
40 | | /// |
41 | | /// Unless you need to implement your own data store — that is either can't convert to `&[u8]` or |
42 | | /// have a data that is not `&[u8]` — you will probably want to implement |
43 | | /// [TryFromCtx](ctx/trait.TryFromCtx.html) on your Rust types to be extracted. |
44 | | /// |
45 | | pub trait Pread<Ctx, E> : Index<usize> + Index<RangeFrom<usize>> + MeasureWith<Ctx> |
46 | | where |
47 | | Ctx: Copy, |
48 | | E: From<error::Error>, |
49 | | { |
50 | | #[inline] |
51 | | /// Reads a value from `self` at `offset` with a default `Ctx`. For the primitive numeric values, this will read at the machine's endianness. |
52 | | /// # Example |
53 | | /// ```rust |
54 | | /// use scroll::Pread; |
55 | | /// let bytes = [0x7fu8; 0x01]; |
56 | | /// let byte = bytes.pread::<u8>(0).unwrap(); |
57 | 0 | fn pread<'a, N: TryFromCtx<'a, Ctx, <Self as Index<RangeFrom<usize>>>::Output, Error = E>>(&'a self, offset: usize) -> result::Result<N, E> where <Self as Index<RangeFrom<usize>>>::Output: 'a, Ctx: Default { |
58 | 0 | self.pread_with(offset, Ctx::default()) |
59 | 0 | } |
60 | | #[inline] |
61 | | /// Reads a value from `self` at `offset` with the given `ctx` |
62 | | /// # Example |
63 | | /// ```rust |
64 | | /// use scroll::Pread; |
65 | | /// let bytes: [u8; 2] = [0xde, 0xad]; |
66 | | /// let dead: u16 = bytes.pread_with(0, scroll::BE).unwrap(); |
67 | | /// assert_eq!(dead, 0xdeadu16); |
68 | 0 | fn pread_with<'a, N: TryFromCtx<'a, Ctx, <Self as Index<RangeFrom<usize>>>::Output, Error = E>>(&'a self, offset: usize, ctx: Ctx) -> result::Result<N, E> where <Self as Index<RangeFrom<usize>>>::Output: 'a { |
69 | 0 | let len = self.measure_with(&ctx); |
70 | 0 | if offset >= len { |
71 | 0 | return Err(error::Error::BadOffset(offset).into()) |
72 | 0 | } |
73 | 0 | N::try_from_ctx(&self[offset..], ctx).and_then(|(n, _)| Ok(n)) |
74 | 0 | } |
75 | | #[inline] |
76 | | /// Reads a value from `self` at `offset` with a default `Ctx`. For the primitive numeric values, this will read at the machine's endianness. Updates the offset |
77 | | /// # Example |
78 | | /// ```rust |
79 | | /// use scroll::Pread; |
80 | | /// let offset = &mut 0; |
81 | | /// let bytes = [0x7fu8; 0x01]; |
82 | | /// let byte = bytes.gread::<u8>(offset).unwrap(); |
83 | | /// assert_eq!(*offset, 1); |
84 | 0 | fn gread<'a, N: TryFromCtx<'a, Ctx, <Self as Index<RangeFrom<usize>>>::Output, Error = E>>(&'a self, offset: &mut usize) -> result::Result<N, E> where Ctx: Default, <Self as Index<RangeFrom<usize>>>::Output: 'a { |
85 | 0 | let ctx = Ctx::default(); |
86 | 0 | self.gread_with(offset, ctx) |
87 | 0 | } |
88 | | /// Reads a value from `self` at `offset` with the given `ctx`, and updates the offset. |
89 | | /// # Example |
90 | | /// ```rust |
91 | | /// use scroll::Pread; |
92 | | /// let offset = &mut 0; |
93 | | /// let bytes: [u8; 2] = [0xde, 0xad]; |
94 | | /// let dead: u16 = bytes.gread_with(offset, scroll::BE).unwrap(); |
95 | | /// assert_eq!(dead, 0xdeadu16); |
96 | | /// assert_eq!(*offset, 2); |
97 | | #[inline] |
98 | 0 | fn gread_with<'a, N: TryFromCtx<'a, Ctx, <Self as Index<RangeFrom<usize>>>::Output, Error = E>> |
99 | 0 | (&'a self, offset: &mut usize, ctx: Ctx) -> |
100 | 0 | result::Result<N, E> |
101 | 0 | where <Self as Index<RangeFrom<usize>>>::Output: 'a |
102 | | { |
103 | 0 | let o = *offset; |
104 | | // self.pread_with(o, ctx).and_then(|(n, size)| { |
105 | | // *offset += size; |
106 | | // Ok(n) |
107 | | // }) |
108 | 0 | let len = self.measure_with(&ctx); |
109 | 0 | if o >= len { |
110 | 0 | return Err(error::Error::BadOffset(o).into()) |
111 | 0 | } |
112 | 0 | N::try_from_ctx(&self[o..], ctx).and_then(|(n, size)| { |
113 | 0 | *offset += size; |
114 | 0 | Ok(n) |
115 | 0 | }) |
116 | 0 | } |
117 | | |
118 | | /// Trys to write `inout.len()` `N`s into `inout` from `Self` starting at `offset`, using the default context for `N`, and updates the offset. |
119 | | /// # Example |
120 | | /// ```rust |
121 | | /// use scroll::Pread; |
122 | | /// let mut bytes: Vec<u8> = vec![0, 0]; |
123 | | /// let offset = &mut 0; |
124 | | /// let bytes_from: [u8; 2] = [0x48, 0x49]; |
125 | | /// bytes_from.gread_inout(offset, &mut bytes).unwrap(); |
126 | | /// assert_eq!(&bytes, &bytes_from); |
127 | | /// assert_eq!(*offset, 2); |
128 | | #[inline] |
129 | 0 | fn gread_inout<'a, N>(&'a self, offset: &mut usize, inout: &mut [N]) -> result::Result<(), E> |
130 | 0 | where |
131 | 0 | N: TryFromCtx<'a, Ctx, <Self as Index<RangeFrom<usize>>>::Output, Error = E>, |
132 | 0 | Ctx: Default, |
133 | 0 | <Self as Index<RangeFrom<usize>>>::Output: 'a |
134 | | { |
135 | 0 | for i in inout.iter_mut() { |
136 | 0 | *i = self.gread(offset)?; |
137 | | } |
138 | 0 | Ok(()) |
139 | 0 | } |
140 | | |
141 | | /// Trys to write `inout.len()` `N`s into `inout` from `Self` starting at `offset`, using the context `ctx` |
142 | | /// # Example |
143 | | /// ```rust |
144 | | /// use scroll::{ctx, LE, Pread}; |
145 | | /// let mut bytes: Vec<u8> = vec![0, 0]; |
146 | | /// let offset = &mut 0; |
147 | | /// let bytes_from: [u8; 2] = [0x48, 0x49]; |
148 | | /// bytes_from.gread_inout_with(offset, &mut bytes, LE).unwrap(); |
149 | | /// assert_eq!(&bytes, &bytes_from); |
150 | | /// assert_eq!(*offset, 2); |
151 | | #[inline] |
152 | 0 | fn gread_inout_with<'a, N>(&'a self, offset: &mut usize, inout: &mut [N], ctx: Ctx) -> result::Result<(), E> |
153 | 0 | where |
154 | 0 | N: TryFromCtx<'a, Ctx, <Self as Index<RangeFrom<usize>>>::Output, Error = E>, |
155 | 0 | <Self as Index<RangeFrom<usize>>>::Output: 'a |
156 | | { |
157 | 0 | for i in inout.iter_mut() { |
158 | 0 | *i = self.gread_with(offset, ctx)?; |
159 | | } |
160 | 0 | Ok(()) |
161 | 0 | } |
162 | | } |
163 | | |
164 | | impl<Ctx: Copy, |
165 | | E: From<error::Error>, |
166 | | R: ?Sized + Index<usize> + Index<RangeFrom<usize>> + MeasureWith<Ctx>> |
167 | | Pread<Ctx, E> for R {} |