• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

benches/H03-May-2022-162147

examples/H03-May-2022-2924

src/H03-May-2022-2,1721,329

tests/H03-May-2022-312270

.cargo-checksum.jsonH A D03-May-202289 11

.gitignoreH A D23-Nov-201639 65

.travis.ymlH A D14-Apr-2018218 1311

CHANGELOG.mdH A D22-Sep-2018403 118

Cargo.tomlH A D01-Jan-19701.2 KiB3834

Cargo.toml.orig-cargoH A D23-Sep-2018654 2621

LICENSEH A D11-Jan-20171 KiB2217

README.mdH A D22-Sep-20186.8 KiB226168

build.rsH A D23-Sep-2018200 97

README.md

1 [![Build Status](https://travis-ci.org/m4b/scroll.svg?branch=master)](https://travis-ci.org/m4b/scroll)
2## Scroll - cast some magic
3
4```text
5         _______________
6    ()==(              (@==()
7         '______________'|
8           |             |
9           |   ἀρετή     |
10         __)_____________|
11    ()==(               (@==()
12         '--------------'
13
14```
15
16### Documentation
17
18https://docs.rs/scroll
19
20### Usage
21
22Add to your `Cargo.toml`
23
24```toml
25[dependencies]
26scroll = "0.9"
27```
28
29### Overview
30
31Scroll implements several traits for read/writing generic containers (byte buffers are currently implemented by default). Most familiar will likely be the `Pread` trait, which at its basic takes an immutable reference to self, an immutable offset to read at, (and a parsing context, more on that later), and then returns the deserialized value.
32
33Because self is immutable, _**all** reads can be performed in parallel_ and hence are trivially parallelizable.
34
35A simple example demonstrates its flexibility:
36
37```rust
38extern crate scroll;
39
40use scroll::{ctx, Pread, LE};
41
42fn parse() -> Result<(), scroll::Error> {
43    let bytes: [u8; 4] = [0xde, 0xad, 0xbe, 0xef];
44
45    // reads a u32 out of `b` with the endianness of the host machine, at offset 0, turbofish-style
46    let number: u32 = bytes.pread::<u32>(0)?;
47    // ...or a byte, with type ascription on the binding.
48    let byte: u8 = bytes.pread(0)?;
49
50    //If the type is known another way by the compiler, say reading into a struct field, we can omit the turbofish, and type ascription altogether!
51
52    // If we want, we can explicitly add a endianness to read with by calling `pread_with`.
53    // The following reads a u32 out of `b` with Big Endian byte order, at offset 0
54    let be_number: u32 = bytes.pread_with(0, scroll::BE)?;
55    // or a u16 - specify the type either on the variable or with the beloved turbofish
56    let be_number2 = bytes.pread_with::<u16>(2, scroll::BE)?;
57
58    // Scroll has core friendly errors (no allocation). This will have the type `scroll::Error::BadOffset` because it tried to read beyond the bound
59    let byte: scroll::Result<i64> = bytes.pread(0);
60
61    // Scroll is extensible: as long as the type implements `TryWithCtx`, then you can read your type out of the byte array!
62
63    // We can parse out custom datatypes, or types with lifetimes
64    // if they implement the conversion trait `TryFromCtx`; here we parse a C-style \0 delimited &str (safely)
65    let hello: &[u8] = b"hello_world\0more words";
66    let hello_world: &str = hello.pread(0)?;
67    assert_eq!("hello_world", hello_world);
68
69    // ... and this parses the string if its space separated!
70    use scroll::ctx::*;
71    let spaces: &[u8] = b"hello world some junk";
72    let world: &str = spaces.pread_with(6, StrCtx::Delimiter(SPACE))?;
73    assert_eq!("world", world);
74    Ok(())
75}
76
77fn main() {
78  parse().unwrap();
79}
80```
81
82### Deriving `Pread` and `Pwrite`
83
84Scroll implements a custom derive that can provide `Pread` and `Pwrite` implementations for your types.
85
86``` rust
87#[macro_use]
88extern crate scroll;
89
90use scroll::{Pread, Pwrite, BE};
91
92#[derive(Pread, Pwrite)]
93struct Data {
94    one: u32,
95    two: u16,
96    three: u8,
97}
98
99fn parse() -> Result<(), scroll::Error> {
100    let bytes: [u8; 7] = [0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xff];
101    // Read a single `Data` at offset zero in big-endian byte order.
102    let data: Data = bytes.pread_with(0, BE)?;
103    assert_eq!(data.one, 0xdeadbeef);
104    assert_eq!(data.two, 0xface);
105    assert_eq!(data.three, 0xff);
106
107    // Write it back to a buffer
108    let mut out: [u8; 7] = [0; 7];
109    out.pwrite_with(data, 0, BE)?;
110    assert_eq!(bytes, out);
111    Ok(())
112}
113
114fn main() {
115  parse().unwrap();
116}
117```
118
119This feature is **not** enabled by default, you must enable the `derive` feature in Cargo.toml to use it:
120
121```toml
122[dependencies]
123scroll = { version = "0.9", features = ["derive"] }
124```
125
126# `std::io` API
127
128Scroll can also read/write simple types from a `std::io::Read` or `std::io::Write` implementor. The  built-in numeric types are taken care of for you.  If you want to read a custom type, you need to implement the `FromCtx` (_how_ to parse) and `SizeWith` (_how_ big the parsed thing will be) traits.  You must compile with default features. For example:
129
130```rust
131extern crate scroll;
132
133use std::io::Cursor;
134use scroll::IOread;
135
136fn parse_io() -> Result<(), scroll::Error> {
137    let bytes_ = [0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xef,0xbe,0x00,0x00,];
138    let mut bytes = Cursor::new(bytes_);
139
140    // this will bump the cursor's Seek
141    let foo = bytes.ioread::<usize>()?;
142    // ..ditto
143    let bar = bytes.ioread::<u32>()?;
144    Ok(())
145}
146
147fn main() {
148  parse_io().unwrap();
149}
150```
151
152Similarly, we can write to anything that implements `std::io::Write` quite naturally:
153
154```rust
155extern crate scroll;
156
157use scroll::{IOwrite, LE, BE};
158use std::io::{Write, Cursor};
159
160fn write_io() -> Result<(), scroll::Error> {
161    let mut bytes = [0x0u8; 10];
162    let mut cursor = Cursor::new(&mut bytes[..]);
163    cursor.write_all(b"hello")?;
164    cursor.iowrite_with(0xdeadbeef as u32, BE)?;
165    assert_eq!(cursor.into_inner(), [0x68, 0x65, 0x6c, 0x6c, 0x6f, 0xde, 0xad, 0xbe, 0xef, 0x0]);
166    Ok(())
167}
168
169fn main() {
170  write_io().unwrap();
171}
172```
173
174# Advanced Uses
175
176Scroll is designed to be highly configurable - it allows you to implement various context (`Ctx`) sensitive traits, which then grants the implementor _automatic_ uses of the `Pread` and/or `Pwrite` traits.
177
178For example, suppose we have a datatype and we want to specify how to parse or serialize this datatype out of some arbitrary
179byte buffer. In order to do this, we need to provide a [TryFromCtx](trait.TryFromCtx.html) impl for our datatype.
180
181In particular, if we do this for the `[u8]` target, using the convention `(usize, YourCtx)`, you will automatically get access to
182calling `pread_with::<YourDatatype>` on arrays of bytes.
183
184```rust
185extern crate scroll;
186
187use scroll::{ctx, Pread, BE, Endian};
188
189struct Data<'a> {
190  name: &'a str,
191  id: u32,
192}
193
194// note the lifetime specified here
195impl<'a> ctx::TryFromCtx<'a, Endian> for Data<'a> {
196  type Error = scroll::Error;
197  type Size = usize;
198  // and the lifetime annotation on `&'a [u8]` here
199  fn try_from_ctx (src: &'a [u8], endian: Endian)
200    -> Result<(Self, Self::Size), Self::Error> {
201    let offset = &mut 0;
202    let name = src.gread::<&str>(offset)?;
203    let id = src.gread_with(offset, endian)?;
204    Ok((Data { name: name, id: id }, *offset))
205  }
206}
207
208fn parse_data() -> Result<(), scroll::Error> {
209    let bytes = b"UserName\x00\x01\x02\x03\x04";
210    let data = bytes.pread_with::<Data>(0, BE)?;
211    assert_eq!(data.id, 0x01020304);
212    assert_eq!(data.name.to_string(), "UserName".to_string());
213    Ok(())
214}
215
216fn main() {
217  parse_data().unwrap();
218}
219```
220
221Please see the official documentation, or a simple [example](examples/data_ctx.rs) for more.
222
223# Contributing
224
225Any ideas, thoughts, or contributions are welcome!
226