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