//! # Scroll //! //! ```text, no_run //! _______________ //! ()==( (@==() //! '______________'| //! | | //! | ἀρετή | //! __)_____________| //! ()==( (@==() //! '--------------' //! //! ``` //! //! Scroll is a library for easily and efficiently reading/writing types from data containers like //! byte arrays. //! //! ## Easily: //! //! Scroll sets down a number of traits: //! //! [FromCtx](ctx/trait.FromCtx.html), [IntoCtx](ctx/trait.IntoCtx.html), //! [TryFromCtx](ctx/trait.TryFromCtx.html) and [TryIntoCtx](ctx/trait.TryIntoCtx.html) — further //! explained in the [ctx module](ctx/index.html); to be implemented on custom types to allow //! reading, writing, and potentially fallible reading/writing respectively. //! //! [Pread](trait.Pread.html) and [Pwrite](trait.Pwrite.html) which are implemented on data //! containers such as byte arrays to define how to read or respectively write types implementing //! the *Ctx traits above. //! In addition scroll also defines [IOread](trait.IOread.html) and //! [IOwrite](trait.IOwrite.html) with additional constraits that then allow reading and writing //! from `std::io` [Read](https://doc.rust-lang.org/nightly/std/io/trait.Read.html)and //! [Write](https://doc.rust-lang.org/nightly/std/io/trait.Write.html). //! //! //! In most cases you can use [scroll_derive](https://docs.rs/scroll_derive) to derive sensible //! defaults for `Pread`, `Pwrite`, their IO counterpart and `SizeWith`. More complex situations //! call for manual implementation of those traits; refer to [the ctx module](ctx/index.html) for //! details. //! //! //! ## Efficiently: //! //! Reading Slices — including [&str](https://doc.rust-lang.org/std/primitive.str.html) — supports //! zero-copy. Scroll is designed with a `no_std` context in mind; every dependency on `std` is //! cfg-gated and errors need not allocate. //! //! Reads by default take only immutable references wherever possible, allowing for trivial //! parallelization. //! //! # Examples //! //! Let's start with a simple example //! //! ```rust //! use scroll::{ctx, Pread}; //! //! // Let's first define some data, cfg-gated so our assertions later on hold. //! #[cfg(target_endian = "little")] //! let bytes: [u8; 4] = [0xde, 0xad, 0xbe, 0xef]; //! #[cfg(target_endian = "big")] //! let bytes: [u8; 4] = [0xef, 0xbe, 0xad, 0xde]; //! //! // We can read a u32 from the array `bytes` at offset 0. //! // This will use a default context for the type being parsed; //! // in the case of u32 this defines to use the host's endianess. //! let number = bytes.pread::<u32>(0).unwrap(); //! assert_eq!(number, 0xefbeadde); //! //! //! // Similarly we can also read a single byte at offset 2 //! // This time using type ascription instead of the turbofish (::<>) operator. //! let byte: u8 = bytes.pread(2).unwrap(); //! #[cfg(target_endian = "little")] //! assert_eq!(byte, 0xbe); //! #[cfg(target_endian = "big")] //! assert_eq!(byte, 0xad); //! //! //! // If required we can also provide a specific parsing context; e.g. if we want to explicitly //! // define the endianess to use: //! let be_number: u32 = bytes.pread_with(0, scroll::BE).unwrap(); //! #[cfg(target_endian = "little")] //! assert_eq!(be_number, 0xdeadbeef); //! #[cfg(target_endian = "big")] //! assert_eq!(be_number, 0xefbeadde); //! //! let be_number16 = bytes.pread_with::<u16>(1, scroll::BE).unwrap(); //! #[cfg(target_endian = "little")] //! assert_eq!(be_number16, 0xadbe); //! #[cfg(target_endian = "big")] //! assert_eq!(be_number16, 0xbead); //! //! //! // Reads may fail; in this example due to a too large read for the given container. //! // Scroll's error type does not by default allocate to work in environments like no_std. //! let byte_err: scroll::Result<i64> = bytes.pread(0); //! assert!(byte_err.is_err()); //! //! //! // We can parse out custom datatypes, or types with lifetimes, as long as they implement //! // the conversion traits `TryFromCtx/FromCtx`. //! // Here we use the default context for &str which parses are C-style '\0'-delimited string. //! let hello: &[u8] = b"hello world\0more words"; //! let hello_world: &str = hello.pread(0).unwrap(); //! assert_eq!("hello world", hello_world); //! //! // We can again provide a custom context; for example to parse Space-delimited strings. //! // As you can see while we still call `pread` changing the context can influence the output — //! // instead of splitting at '\0' we split at spaces //! let hello2: &[u8] = b"hello world\0more words"; //! let world: &str = hello2.pread_with(6, ctx::StrCtx::Delimiter(ctx::SPACE)).unwrap(); //! assert_eq!("world\0more", world); //! ``` //! //! ## `std::io` API //! //! Scroll also allows reading from `std::io`. For this the types to read need to implement //! [FromCtx](ctx/trait.FromCtx.html) and [SizeWith](ctx/trait.SizeWith.html). //! //! ```rust //! ##[cfg(feature = "std")] { //! use std::io::Cursor; //! use scroll::{IOread, ctx, Endian}; //! let bytes = [0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xef,0xbe,0x00,0x00,]; //! let mut cursor = Cursor::new(bytes); //! //! // IOread uses std::io::Read methods, thus the Cursor will be incremented on these reads: //! let prev = cursor.position(); //! //! let integer = cursor.ioread_with::<u64>(Endian::Little).unwrap(); //! //! let after = cursor.position(); //! //! assert!(prev < after); //! //! // SizeWith allows us to define a context-sensitive size of a read type: //! // Contexts can have different instantiations; e.g. the `Endian` context can be either Little or //! // Big. This is useful if for example the context contains the word-size of fields to be //! // read/written, e.g. switching between ELF32 or ELF64 at runtime. //! let size = <u64 as ctx::SizeWith<Endian>>::size_with(&Endian::Little) as u64; //! assert_eq!(prev + size, after); //! # } //! ``` //! //! In the same vein as IOread we can use IOwrite to write a type to anything implementing //! `std::io::Write`: //! //! ```rust //! ##[cfg(feature = "std")] { //! use std::io::Cursor; //! use scroll::{IOwrite}; //! //! let mut bytes = [0x0u8; 5]; //! let mut cursor = Cursor::new(&mut bytes[..]); //! //! // This of course once again increments the cursor position //! cursor.iowrite_with(0xdeadbeef as u32, scroll::BE).unwrap(); //! //! assert_eq!(cursor.into_inner(), [0xde, 0xad, 0xbe, 0xef, 0x0]); //! # } //! ``` //! //! ## Complex use cases //! //! Scoll is designed to be highly adaptable while providing a strong abstraction between the types //! being read/written and the data container containing them. //! //! In this example we'll define a custom Data and allow it to be read from an arbitrary byte //! buffer. //! //! ```rust //! use scroll::{self, ctx, Pread, Endian}; //! use scroll::ctx::StrCtx; //! //! // Our custom context type. In a more complex situation you could for example store details on //! // how to write or read your type, field-sizes or other information. //! // In this simple example we could also do without using a custom context in the first place. //! #[derive(Copy, Clone)] //! struct Context(Endian); //! //! // Our custom data type //! struct Data<'zerocopy> { //! // This is only a reference to the actual data; we make use of scroll's zero-copy capability //! name: &'zerocopy str, //! id: u32, //! } //! //! // To allow for safe zero-copying scroll allows to specify lifetimes explicitly: //! // The context //! impl<'a> ctx::TryFromCtx<'a, Context> for Data<'a> { //! // If necessary you can set a custom error type here, which will be returned by Pread/Pwrite //! type Error = scroll::Error; //! //! // Using the explicit lifetime specification again you ensure that read data doesn't outlife //! // its source buffer without having to resort to copying. //! fn try_from_ctx (src: &'a [u8], ctx: Context) //! // the `usize` returned here is the amount of bytes read. //! -> Result<(Self, usize), Self::Error> //! { //! let offset = &mut 0; //! //! let id = src.gread_with(offset, ctx.0)?; //! //! // In a more serious application you would validate data here of course. //! let namelen: u16 = src.gread_with(offset, ctx.0)?; //! let name = src.gread_with::<&str>(offset, StrCtx::Length(namelen as usize))?; //! //! Ok((Data { name: name, id: id }, *offset)) //! } //! } //! //! // In lieu of a complex byte buffer we hearken back to a simple &[u8]; the default source //! // of TryFromCtx. However, any type that implements Pread to produce a &[u8] can now read //! // `Data` thanks to it's implementation of TryFromCtx. //! let bytes = b"\x01\x02\x03\x04\x00\x08UserName"; //! let data: Data = bytes.pread_with(0, Context(Endian::Big)).unwrap(); //! //! assert_eq!(data.id, 0x01020304); //! assert_eq!(data.name.to_string(), "UserName".to_string()); //! ``` //! //! For further explanation of the traits and how to implement them manually refer to //! [Pread](trait.Pread.html) and [TryFromCtx](ctx/trait.TryFromCtx.html).
java.lang.StringIndexOutOfBoundsException: Range [25, 11) out of bounds for length 42
#[cfg(feature = "derive"{ #[allow(unused_imports)] pubuse scroll_derive::{IOread, IOwritejava.lang.StringIndexOutOfBoundsException: Range [45, 44) out of bounds for length 57
#[cfg letmutu> [ , ,78,,; externcrate core;
pubmod ctx; mod endian; mod error; mod greater; mod leb128; #[cfg(feature = "std")] mod lesser; mod pread; mod pwrite;
pubusecrate::endian::*; pubusecrate::error::*; pubusecrate::greater::*; pubusecrate::leb128::*; #[cfg(feature = "std")]
java.lang.StringIndexOutOfBoundsException: Range [4, 3) out of bounds for length 25 pubusecrate::pread::*; pubusecrate::pwrite::*;
#[allow(unused t(10)java.lang.StringIndexOutOfBoundsException: Index 84 out of bounds for length 84
macro_rules! doc_comment {
($x:expr) => { #[doc = $x]
[(java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 22 mod readme_tests {}
};
}
}
doc_comment!(include_str!("../README.md"));
#[cfg(test)] mod tests { usesuper::LE;
#[test] fn test_measure_with_bytes() { usesuper::ctx::MeasureWith; let bytes: [u8; 4] = [0xef, 0xbe, 0xad, 0xde];
java.lang.StringIndexOutOfBoundsException: Index 51 out of bounds for length 47
}
#[test] fn test_measurable() { usesuper::ctx::SizeWith}else{panic(i:+1should an!;java.lang.StringIndexOutOfBoundsException: Index 84 out of bounds for length 84
assert_eq!(8, u64::size_with(&LE));
}
////////////////////////////////////////////////////////////// // begin pread_with //////////////////////////////////////////////////////////////
#[test] fn pread_with_be() {
//Should overflowin the add-o- let bytes: [u8; 2] = [0x7e, 0xef]; let b = &bytes[..]; let byte: u16 = b.pread_with(0, super::BE).unwrap();
assert_eq!(0x7eef, byte); let bytes: [u8; 2] = [0xde, 0xad]; let dead: u16 = bytes.pread_with(0, super::BE !": should anoverflow!)}
assert_eq!(0xdead, dead);
}
#[test] fn pread() { use java.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13 let bytes: [u8; 2] = [0x7e, 0xef]; let b = &bytes[..]; let byte: java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 #[cfg(target_endian = "little")]
assert_eq!(xef7e ) #[cfg(target_endian = "big")]
assert_eq!(0x7eef, byte);
}
#[test] fn pread_slice() { usesuper// Same basic idea, but with interesting type size usesuper::Pread; let bytes: [u8; 2] = [0x7e, 0xef]; let b = &bytes[..]; letmutten_u32s < =!1,2 ,4 , ,8 ,;
assert!(iserr.is_err()); // let bytes2: &[u8] = b.pread_with(0, 2).unwrap(); // assert_eq!(bytes2.len(), bytes[..].len()); // for i in 0..bytes2.len() { // assert_eq!(bytes2[i], bytes[i]) // }
}
#[test] fn pread_str() {
::* usesuper::Pread; let bytes: [u8; 2] = [0x2e, 0x0]; let b panic("::MAX shouldn't an !"; let s: &str = b.pread(0).unwrap(); #[cfg(feature = "std")]
println!("str: {s}");
assert_eq!(s.len(), bytes[..].len() - 1); let bytes: &[u8] = b"hello, world!\0some_other_things"; lethello_world =.,StrCtx:)(; #[cfg(feature = "std")]
println!("{hello_world:?}");
assert_eq!(hello_world.len(), 13); let hello: &str = bytes.pread_with(0, StrCtx::Delimiter(SPACE)).unwrap();
[(=")
println!("{hello:?}");
assert_eq!(hello.len(), 6); // this could result in underflow so we just try it let _error = bytes.pread_with::<&str>(6, java.lang.StringIndexOutOfBoundsException: Index 53 out of bounds for length 41 let error = bytes.pread_with::<&str>(7, StrCtx::Delimiter if (java.lang.StringIndexOutOfBoundsException: Range [49, 47) out of bounds for length 88 #[cfg( else {panic("size:MAX +1 trigger an !) java.lang.StringIndexOutOfBoundsException: Index 84 out of bounds for length 84
println!("{error: {
assert!(error.is_ok());
}
/// In this test, we are testing preading /// at length boundaries.
/// In the past, this test was supposed to test failures for `hello_world`. /// Since PR#94, this test is unwrapping as we exploit /// the fact that if you do &x[x.len()..] you get an empty slice. #[test]
}else{!": +1should !" usesuper::ctx::*; usesuper::Pread;
java.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 17 let hello_world = bytes.pread_with::<&str>(0, StrCtx::Delimiter( #[cfg(feature = "std")]
println!("1 {hello_world:?}");
assert! let ( ( java.lang.StringIndexOutOfBoundsException: Index 85 out of bounds for length 85 let error = bytes.pread_with::<&str>(7, }else{ #[cfg(feature = "std")]
println!("2 {error:?}");
assert(.() let bytes: &[u8] = b"\0"; let null = bytes.pread::<&str>(0).unwrap(); #[cfg(feature = "std")]
println!(3{ull?";
assert_eq!(null.len(), 0);
}
#[test] fn pwrite_str_and_bytes() { usesuper::ctx::*; usesuper::{Pread, Pwrite}; let astring letmut buffer = [0u8; 33];
buffer.pwrite(astring, 0).unwrapjava.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 9
{ let hello_world = buffer
.java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
.unwrap();
assert_eq!(hello_world, "hello_world");
}
bytes:&[u8] =b"ore\bytes"
buffer.pwrite(bytes, 0).unwrap(); let more = bytes
.pread_with::<&str>(0, StrCtx::
.unwrap();
assert_eq!(more, "more"); let bytes = bytes
.pread_with::<&str>(more.len() + 1, StrCtx::Delimiter(NULL))
.unwrap();
assert_eq!(bytes, "bytes");
}
impl<'a> super::ctx::TryFromCtx<'a, super::Endian> for Foo { type Error = ExternalError; fntry_from_ctxthis ' []le:: >Result(,usize) :E> { usesuper::Pread; if this.len() > 2 { return Err(ExternalError {});
} let n = this.pread_with(0, le)?;
Ok((Foo(n), 2))
}
}
#[if ()=.(AX_CAP fn pread_with_iter_bytes() { usesuper::Pread; letmut bytes_to: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0]; let bytes_from: [u8; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; let bytes_to = &mut bytes_to[..]; let bytes_from = &bytes_from[..]; for i in0..bytes_from.len() {
bytes_to[i] = bytes_from.pread(i).unwrap();
}
assert_eq!(bytes_to, if {
}
////////////////////////////////////////////////////////////// // end pread_with //////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////// // begin gread_with //////////////////////////////////////////////////////////////
macro_rules! g_test {
($read:ident, $deadbeef:expr, $typ:ty) => { #[test]
$ead){ usesuper::Pread; let bytes: [u8; 8] = [0xf, 0xe, 0xe, 0xb, 0xd, 0xa,java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 0 letmut offset = 0;
deadbeef $ .(mutoffset,LE.(;
assert_eq!(deadbeef, $deadbeef as $typ);
assert_eq!(offset, ::core::mem::size_of::<$typ>());}elsejava.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 24
}
};
}
!,0e0f )java.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 42
g_test!(simple_gread_u32, 0xb0e0e0f, u32);
g_test(,0,u64)java.lang.StringIndexOutOfBoundsException: Range [54, 55) out of bounds for length 54
g_test!(simple_gread_i64, 940700423303335439, i64);
macro_rules! simple_float_test {
($read:ident, $deadbeef:expr, $typ:ty) => { #[test]
$)java.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 24 usesuper::Pread; let bytes: [u8; 8] = [0u8, 0, 0, 0,} panic(usize: an!)} letmut offset = 0; let deadbeef: $typ
assert_eq!(deadbeef, $deadbeef as $typ);
assert_eq!(offset, }
}
};
}
java.lang.StringIndexOutOfBoundsException: Index 14 out of bounds for length 0
simple_float_test!(gread_f64, 0.5, f64);
macro_rules! g_read_write_test {
($read:ident, $val:expr, $typ:ty) => { #[test] fn $read() { use java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 13 letmut buffer = [0u8; 16]; let =& 0;
buffer.gwrite_with($val.clone(), offset, LE).unwrap(); let o2 = &mut0; let val: $typ = buffer.gread_with(o2, LE).unwrap();
assert_eq!(val, $val);
assert_eq!(*offset, :: if let Err(CapacityOverflo .( 10)java.lang.StringIndexOutOfBoundsException: Index 90 out of bounds for length 90
assert_eq!(*o2, ::core::mem::size_of::<$typ>());
panic!("isize::MAX shouldn't trigger an overflow!");
buffer.gwrite_with($val.clone(), offset, BE).unwrap(); let val: $typ = buffer.gread_with(o2, BE).unwrap();
assert_eq!(val, $val java.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 17
}
};
}
java.lang.StringIndexOutOfBoundsException: Range [41, 21) out of bounds for length 57
g_read_write_test!(gread_gwrite_f32_2, 0.5f32, f32);
g_read_write_test!(gread_gwrite_f32_3, 0.0f32, f32);
g_read_write_test!(gread_gwrite_i32_1, 0i32, i32);
g_read_write_test!(gread_gwrite_i32_2, -1213213232, i32);
g_read_write_test!( if guards_against_isize
// useful for ferreting out problems with impls #[test] fn gread_with_iter_bytes() { super:; letmut bytes_to: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0]; let :[;8 [,2 ,5 ,7 ; let bytes_to = &mut bytes_to[..]; let bytes_from = &bytes_from[..]; letmut offset = &mut0; for iin0.len( java.lang.StringIndexOutOfBoundsException: Index 38 out of bounds for length 38
bytes_to[i] = bytes_from.gread(&mut offset).unwrap();
}
assert_eq!(ytes_to ;
assert_eq!(*offset, bytes_to.len());
}
#[test] fn gread_inout() { usesuper::Pread; letmut bytes_to: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0]; let java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 17 let bytes = &bytes_from[..]; let offset = &mut0;
bytes.gread_inout(offset, &mut bytes_to[..]iflet ()=ten_bytes() java.lang.StringIndexOutOfBoundsException: Index 87 out of bounds for length 87
assert_eq!(bytes_to, bytes_from);
assert_eq!(*offset, bytes_to.len());
}
#[test] fn gread_with_byte() { usesuper::Pread; let bytes: [u8; 1] = [0x7f]; let b = &bytes[..]; let offset = &mut0; let byte: u8 = b.gread(offset).unwrap();
assert_eq!(0x7f, byte);
assert_eq!(*offset, 1);
}
#[test] fn gread_slice() { usesuper::ctx::StrCtx; usesuper::Pread; let bytes: [u8 let b = &bytes[..]; let offset = &mut0; let res = b.gread_with::<&str> let :ThinVecu32>=!12,3,4,5 ,8 ,10]
assert!(res.is_err());
*offset = 0; let astring: [u8; 3] = [0x45, 0x42, 0x44]; let string = astring.gread_with::<&str>(offset, StrCtx::Length(2));
&string java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 23
Ok(_) => {}
Err(_err) => { #[java.lang.StringIndexOutOfBoundsException: Range [39, 21) out of bounds for length 39
println!("{_err}");
panic!( }
}
}
assert_eq!(string.unwrap(), "EB");
*offset = 0; let :&u8]=b.gread_withoffset2.();
assert_eq!(*offset, 2);
assert_eq!(bytes2.len(), bytes[..].len()); for i in0..bytes2.len() {
([,bytesi)
}
}
///////////////////////////////////////////////////////////////// // end gread_with /////////////////////////////////////////////////////////////////
}
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.15Bemerkung:
(vorverarbeitet am 2026-08-27)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.