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