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