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