Merge autoland to mozilla-central a=merge
[gecko.git] / third_party / rust / scroll / README.md
blob50dde54d7eba34b432ab38fe342688a011a9dcad
1 [![Actions][actions-badge]][actions-url]
2 [![crates.io version][crates-scroll-badge]][crates-scroll]
4 <!-- Badges' links -->
6 [actions-badge]: https://github.com/m4b/scroll/workflows/CI/badge.svg?branch=master
7 [actions-url]: https://github.com/m4b/scroll/actions
8 [crates-scroll-badge]: https://img.shields.io/crates/v/scroll.svg
9 [crates-scroll]: https://crates.io/crates/scroll
11 ## Scroll - cast some magic
13 ```text
14          _______________
15     ()==(              (@==()
16          '______________'|
17            |             |
18            |   ἀρετή     |
19          __)_____________|
20     ()==(               (@==()
21          '--------------'
23 ```
25 ### Documentation
27 https://docs.rs/scroll
29 ### Usage
31 Add to your `Cargo.toml`
33 ```toml, no_test
34 [dependencies]
35 scroll = "0.11"
36 ```
38 ### Overview
40 Scroll 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.
42 Because self is immutable, _**all** reads can be performed in parallel_ and hence are trivially parallelizable.
44 A simple example demonstrates its flexibility:
46 ```rust
47 use scroll::{ctx, Pread, LE};
49 fn main() -> Result<(), scroll::Error> {
50     let bytes: [u8; 4] = [0xde, 0xad, 0xbe, 0xef];
52     // reads a u32 out of `b` with the endianness of the host machine, at offset 0, turbofish-style
53     let number: u32 = bytes.pread::<u32>(0)?;
54     // ...or a byte, with type ascription on the binding.
55     let byte: u8 = bytes.pread(0)?;
57     //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!
59     // If we want, we can explicitly add a endianness to read with by calling `pread_with`.
60     // The following reads a u32 out of `b` with Big Endian byte order, at offset 0
61     let be_number: u32 = bytes.pread_with(0, scroll::BE)?;
62     // or a u16 - specify the type either on the variable or with the beloved turbofish
63     let be_number2 = bytes.pread_with::<u16>(2, scroll::BE)?;
65     // Scroll has core friendly errors (no allocation). This will have the type `scroll::Error::BadOffset` because it tried to read beyond the bound
66     let byte: scroll::Result<i64> = bytes.pread(0);
68     // Scroll is extensible: as long as the type implements `TryWithCtx`, then you can read your type out of the byte array!
70     // We can parse out custom datatypes, or types with lifetimes
71     // if they implement the conversion trait `TryFromCtx`; here we parse a C-style \0 delimited &str (safely)
72     let hello: &[u8] = b"hello_world\0more words";
73     let hello_world: &str = hello.pread(0)?;
74     assert_eq!("hello_world", hello_world);
76     // ... and this parses the string if its space separated!
77     use scroll::ctx::*;
78     let spaces: &[u8] = b"hello world some junk";
79     let world: &str = spaces.pread_with(6, StrCtx::Delimiter(SPACE))?;
80     assert_eq!("world", world);
81     Ok(())
83 ```
85 ### Deriving `Pread` and `Pwrite`
87 Scroll implements a custom derive that can provide `Pread` and `Pwrite` implementations for your structs.
89 ```rust
90 use scroll::{Pread, Pwrite, BE};
92 #[derive(Pread, Pwrite)]
93 struct Data {
94     one: u32,
95     two: u16,
96     three: u8,
99 fn main() -> 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);
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(())
115 This feature is **not** enabled by default, you must enable the `derive` feature in Cargo.toml to use it:
117 ```toml, no_test
118 [dependencies]
119 scroll = { version = "0.10", features = ["derive"] }
122 # `std::io` API
124 Scroll 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:
126 ```rust
127 use std::io::Cursor;
128 use scroll::IOread;
130 fn main() -> Result<(), scroll::Error> {
131     let bytes_ = [0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xef,0xbe,0x00,0x00,];
132     let mut bytes = Cursor::new(bytes_);
134     // this will bump the cursor's Seek
135     let foo = bytes.ioread::<usize>()?;
136     // ..ditto
137     let bar = bytes.ioread::<u32>()?;
138     Ok(())
142 Similarly, we can write to anything that implements `std::io::Write` quite naturally:
144 ```rust
145 use scroll::{IOwrite, LE, BE};
146 use std::io::{Write, Cursor};
148 fn main() -> Result<(), scroll::Error> {
149     let mut bytes = [0x0u8; 10];
150     let mut cursor = Cursor::new(&mut bytes[..]);
151     cursor.write_all(b"hello")?;
152     cursor.iowrite_with(0xdeadbeef as u32, BE)?;
153     assert_eq!(cursor.into_inner(), [0x68, 0x65, 0x6c, 0x6c, 0x6f, 0xde, 0xad, 0xbe, 0xef, 0x0]);
154     Ok(())
158 # Advanced Uses
160 Scroll 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.
162 For example, suppose we have a datatype and we want to specify how to parse or serialize this datatype out of some arbitrary
163 byte buffer. In order to do this, we need to provide a [TryFromCtx](trait.TryFromCtx.html) impl for our datatype.
165 In particular, if we do this for the `[u8]` target, using the convention `(usize, YourCtx)`, you will automatically get access to
166 calling `pread_with::<YourDatatype>` on arrays of bytes.
168 ```rust
169 use scroll::{ctx, Pread, BE, Endian};
171 struct Data<'a> {
172   name: &'a str,
173   id: u32,
176 // note the lifetime specified here
177 impl<'a> ctx::TryFromCtx<'a, Endian> for Data<'a> {
178   type Error = scroll::Error;
179   // and the lifetime annotation on `&'a [u8]` here
180   fn try_from_ctx (src: &'a [u8], endian: Endian)
181     -> Result<(Self, usize), Self::Error> {
182     let offset = &mut 0;
183     let name = src.gread::<&str>(offset)?;
184     let id = src.gread_with(offset, endian)?;
185     Ok((Data { name: name, id: id }, *offset))
186   }
189 fn main() -> Result<(), scroll::Error> {
190     let bytes = b"UserName\x00\x01\x02\x03\x04";
191     let data = bytes.pread_with::<Data>(0, BE)?;
192     assert_eq!(data.id, 0x01020304);
193     assert_eq!(data.name.to_string(), "UserName".to_string());
194     Ok(())
198 Please see the official documentation, or a simple [example](examples/data_ctx.rs) for more.
200 # Contributing
202 Any ideas, thoughts, or contributions are welcome!