1 use core::ops::{Index, IndexMut, RangeFrom};
2 
3 use crate::ctx::{FromCtx, IntoCtx};
4 
5 /// Core-read - core, no_std friendly trait for reading basic traits from byte buffers. Cannot fail
6 /// unless the buffer is too small, in which case an assert fires and the program panics.
7 ///
8 /// If your type implements [FromCtx](ctx/trait.FromCtx.html) then you can `cread::<YourType>(offset)`.
9 ///
10 /// # Example
11 ///
12 /// ```rust
13 /// use scroll::{ctx, Cread, LE};
14 ///
15 /// #[repr(packed)]
16 /// struct Bar {
17 ///     foo: i32,
18 ///     bar: u32,
19 /// }
20 ///
21 /// impl ctx::FromCtx<scroll::Endian> for Bar {
22 ///     fn from_ctx(bytes: &[u8], ctx: scroll::Endian) -> Self {
23 ///         use scroll::Cread;
24 ///         Bar { foo: bytes.cread_with(0, ctx), bar: bytes.cread_with(4, ctx) }
25 ///     }
26 /// }
27 ///
28 /// let bytes = [0xff, 0xff, 0xff, 0xff, 0xef,0xbe,0xad,0xde,];
29 /// let bar = bytes.cread_with::<Bar>(0, LE);
30 /// // Remember that you need to copy out fields from packed structs
31 /// // with a `{}` block instead of borrowing them directly
32 /// // ref: https://github.com/rust-lang/rust/issues/46043
33 /// assert_eq!({bar.foo}, -1);
34 /// assert_eq!({bar.bar}, 0xdeadbeef);
35 /// ```
36 pub trait Cread<Ctx, I = usize> : Index<I> + Index<RangeFrom<I>>
37  where
38     Ctx: Copy,
39 {
40     /// Reads a value from `Self` at `offset` with `ctx`. Cannot fail.
41     /// If the buffer is too small for the value requested, this will panic.
42     ///
43     /// # Example
44     ///
45     /// ```rust
46     /// use scroll::{Cread, BE, LE};
47     /// use std::i64::MAX;
48     ///
49     /// let bytes = [0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xef,0xbe,0xad,0xde,];
50     /// let foo = bytes.cread_with::<i64>(0, BE);
51     /// let bar = bytes.cread_with::<u32>(8, LE);
52     /// assert_eq!(foo, MAX);
53     /// assert_eq!(bar, 0xdeadbeef);
54     /// ```
55     #[inline]
cread_with<N: FromCtx<Ctx, <Self as Index<RangeFrom<I>>>::Output>>(&self, offset: I, ctx: Ctx) -> N56     fn cread_with<N: FromCtx<Ctx, <Self as Index<RangeFrom<I>>>::Output>>(&self, offset: I, ctx: Ctx) -> N {
57         N::from_ctx(&self[offset..], ctx)
58     }
59     /// Reads a value implementing `FromCtx` from `Self` at `offset`,
60     /// with the **target machine**'s endianness.
61     /// For the primitive types, this will be the **target machine**'s endianness.
62     ///
63     /// # Example
64     ///
65     /// ```rust
66     /// use scroll::Cread;
67     ///
68     /// let bytes = [0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xef,0xbe,0x00,0x00,];
69     /// let foo = bytes.cread::<i64>(0);
70     /// let bar = bytes.cread::<u32>(8);
71     /// #[cfg(target_endian = "little")]
72     /// assert_eq!(foo, 1);
73     /// #[cfg(target_endian = "big")]
74     /// assert_eq!(foo, 0x100_0000_0000_0000);
75     ///
76     /// #[cfg(target_endian = "little")]
77     /// assert_eq!(bar, 0xbeef);
78     /// #[cfg(target_endian = "big")]
79     /// assert_eq!(bar, 0xefbe0000);
80     /// ```
81     #[inline]
cread<N: FromCtx<Ctx, <Self as Index<RangeFrom<I>>>::Output>>(&self, offset: I) -> N where Ctx: Default82     fn cread<N: FromCtx<Ctx, <Self as Index<RangeFrom<I>>>::Output>>(&self, offset: I) -> N where Ctx: Default {
83         let ctx = Ctx::default();
84         N::from_ctx(&self[offset..], ctx)
85     }
86 }
87 
88 impl<Ctx: Copy, I, R: ?Sized + Index<I> + Index<RangeFrom<I>>> Cread<Ctx, I> for R {}
89 
90 /// Core-write - core, no_std friendly trait for writing basic types into byte buffers. Cannot fail
91 /// unless the buffer is too small, in which case an assert fires and the program panics.
92 /// Similar to [Cread](trait.Cread.html), if your type implements [IntoCtx](ctx/trait.IntoCtx.html)
93 /// then you can `cwrite(your_type, offset)`.
94 ///
95 /// # Example
96 ///
97 /// ```rust
98 /// use scroll::{ctx, Cwrite};
99 ///
100 /// #[repr(packed)]
101 /// struct Bar {
102 ///     foo: i32,
103 ///     bar: u32,
104 /// }
105 ///
106 /// impl ctx::IntoCtx<scroll::Endian> for Bar {
107 ///     fn into_ctx(self, bytes: &mut [u8], ctx: scroll::Endian) {
108 ///         use scroll::Cwrite;
109 ///         bytes.cwrite_with(self.foo, 0, ctx);
110 ///         bytes.cwrite_with(self.bar, 4, ctx);
111 ///     }
112 /// }
113 ///
114 /// let bar = Bar { foo: -1, bar: 0xdeadbeef };
115 /// let mut bytes = [0x0; 16];
116 /// bytes.cwrite::<Bar>(bar, 0);
117 /// ```
118 pub trait Cwrite<Ctx: Copy, I = usize>: Index<I> + IndexMut<RangeFrom<I>> {
119     /// Writes `n` into `Self` at `offset`; uses default context.
120     /// For the primitive types, this will be the **target machine**'s endianness.
121     ///
122     /// # Example
123     ///
124     /// ```
125     /// use scroll::{Cwrite, Cread};
126     /// let mut bytes = [0x0; 16];
127     /// bytes.cwrite::<i64>(42, 0);
128     /// bytes.cwrite::<u32>(0xdeadbeef, 8);
129     ///
130     /// assert_eq!(bytes.cread::<i64>(0), 42);
131     /// assert_eq!(bytes.cread::<u32>(8), 0xdeadbeef);
132     #[inline]
cwrite<N: IntoCtx<Ctx, <Self as Index<RangeFrom<I>>>::Output>>(&mut self, n: N, offset: I) where Ctx: Default133     fn cwrite<N: IntoCtx<Ctx, <Self as Index<RangeFrom<I>>>::Output>>(&mut self, n: N, offset: I) where Ctx: Default {
134         let ctx = Ctx::default();
135         n.into_ctx(self.index_mut(offset..), ctx)
136     }
137     /// Writes `n` into `Self` at `offset` with `ctx`
138     ///
139     /// # Example
140     ///
141     /// ```
142     /// use scroll::{Cwrite, Cread, LE, BE};
143     /// let mut bytes = [0x0; 0x10];
144     /// bytes.cwrite_with::<i64>(42, 0, LE);
145     /// bytes.cwrite_with::<u32>(0xdeadbeef, 8, BE);
146     /// assert_eq!(bytes.cread_with::<i64>(0, LE), 42);
147     /// assert_eq!(bytes.cread_with::<u32>(8, LE), 0xefbeadde);
148     #[inline]
cwrite_with<N: IntoCtx<Ctx, <Self as Index<RangeFrom<I>>>::Output>>(&mut self, n: N, offset: I, ctx: Ctx)149     fn cwrite_with<N: IntoCtx<Ctx, <Self as Index<RangeFrom<I>>>::Output>>(&mut self, n: N, offset: I, ctx: Ctx) {
150         n.into_ctx(self.index_mut(offset..), ctx)
151     }
152 }
153 
154 impl<Ctx: Copy, I, W: ?Sized + Index<I> + IndexMut<RangeFrom<I>>> Cwrite<Ctx, I> for W {}
155