{"id":15389267,"url":"https://github.com/m4b/scroll","last_synced_at":"2025-04-13T08:55:25.435Z","repository":{"id":37484378,"uuid":"74545261","full_name":"m4b/scroll","owner":"m4b","description":"Scroll - making scrolling through buffers fun since 2016","archived":false,"fork":false,"pushed_at":"2025-03-29T22:07:32.000Z","size":288,"stargazers_count":169,"open_issues_count":22,"forks_count":37,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-04-06T05:05:46.122Z","etag":null,"topics":["bytebuffer","endianness","generic","parallel","pread"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/m4b.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-11-23T05:58:52.000Z","updated_at":"2025-04-02T12:22:35.000Z","dependencies_parsed_at":"2022-09-15T04:10:22.236Z","dependency_job_id":"b1915f5c-3dff-484a-94d6-e5f21769751e","html_url":"https://github.com/m4b/scroll","commit_stats":{"total_commits":193,"total_committers":26,"mean_commits":7.423076923076923,"dds":"0.24352331606217614","last_synced_commit":"a5680ac5f04a34a8f8abe23c738d200b73e32035"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/m4b%2Fscroll","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/m4b%2Fscroll/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/m4b%2Fscroll/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/m4b%2Fscroll/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/m4b","download_url":"https://codeload.github.com/m4b/scroll/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248688544,"owners_count":21145763,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bytebuffer","endianness","generic","parallel","pread"],"created_at":"2024-10-01T14:59:53.393Z","updated_at":"2025-04-13T08:55:25.413Z","avatar_url":"https://github.com/m4b.png","language":"Rust","readme":"[![Actions][actions-badge]][actions-url]\n[![crates.io version][crates-scroll-badge]][crates-scroll]\n\n\u003c!-- Badges' links --\u003e\n\n[actions-badge]: https://github.com/m4b/scroll/workflows/CI/badge.svg?branch=master\n[actions-url]: https://github.com/m4b/scroll/actions\n[crates-scroll-badge]: https://img.shields.io/crates/v/scroll.svg\n[crates-scroll]: https://crates.io/crates/scroll\n\n## Scroll - cast some magic\n\n```text\n         _______________\n    ()==(              (@==()\n         '______________'|\n           |             |\n           |   ἀρετή     |\n         __)_____________|\n    ()==(               (@==()\n         '--------------'\n\n```\n\n### Documentation\n\nhttps://docs.rs/scroll\n\n### Usage\n\nAdd to your `Cargo.toml`\n\n```toml, no_test\n[dependencies]\nscroll = \"0.11\"\n```\n\n### Overview\n\nScroll 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.\n\nBecause self is immutable, _**all** reads can be performed in parallel_ and hence are trivially parallelizable.\n\nA simple example demonstrates its flexibility:\n\n```rust\nuse scroll::{ctx, Pread, LE};\n\nfn main() -\u003e Result\u003c(), scroll::Error\u003e {\n    let bytes: [u8; 4] = [0xde, 0xad, 0xbe, 0xef];\n\n    // reads a u32 out of `b` with the endianness of the host machine, at offset 0, turbofish-style\n    let number: u32 = bytes.pread::\u003cu32\u003e(0)?;\n    // ...or a byte, with type ascription on the binding.\n    let byte: u8 = bytes.pread(0)?;\n\n    //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!\n\n    // If we want, we can explicitly add a endianness to read with by calling `pread_with`.\n    // The following reads a u32 out of `b` with Big Endian byte order, at offset 0\n    let be_number: u32 = bytes.pread_with(0, scroll::BE)?;\n    // or a u16 - specify the type either on the variable or with the beloved turbofish\n    let be_number2 = bytes.pread_with::\u003cu16\u003e(2, scroll::BE)?;\n\n    // Scroll has core friendly errors (no allocation). This will have the type `scroll::Error::BadOffset` because it tried to read beyond the bound\n    let byte: scroll::Result\u003ci64\u003e = bytes.pread(0);\n\n    // Scroll is extensible: as long as the type implements `TryWithCtx`, then you can read your type out of the byte array!\n\n    // We can parse out custom datatypes, or types with lifetimes\n    // if they implement the conversion trait `TryFromCtx`; here we parse a C-style \\0 delimited \u0026str (safely)\n    let hello: \u0026[u8] = b\"hello_world\\0more words\";\n    let hello_world: \u0026str = hello.pread(0)?;\n    assert_eq!(\"hello_world\", hello_world);\n\n    // ... and this parses the string if its space separated!\n    use scroll::ctx::*;\n    let spaces: \u0026[u8] = b\"hello world some junk\";\n    let world: \u0026str = spaces.pread_with(6, StrCtx::Delimiter(SPACE))?;\n    assert_eq!(\"world\", world);\n    Ok(())\n}\n```\n\n### Deriving `Pread` and `Pwrite`\n\nScroll implements a custom derive that can provide `Pread` and `Pwrite` implementations for your structs.\n\n```rust\nuse scroll::{Pread, Pwrite, BE};\n\n#[derive(Pread, Pwrite)]\nstruct Data {\n    one: u32,\n    two: u16,\n    three: u8,\n}\n\nfn main() -\u003e Result\u003c(), scroll::Error\u003e {\n    let bytes: [u8; 7] = [0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xff];\n    // Read a single `Data` at offset zero in big-endian byte order.\n    let data: Data = bytes.pread_with(0, BE)?;\n    assert_eq!(data.one, 0xdeadbeef);\n    assert_eq!(data.two, 0xface);\n    assert_eq!(data.three, 0xff);\n\n    // Write it back to a buffer\n    let mut out: [u8; 7] = [0; 7];\n    out.pwrite_with(data, 0, BE)?;\n    assert_eq!(bytes, out);\n    Ok(())\n}\n```\n\nThis feature is **not** enabled by default, you must enable the `derive` feature in Cargo.toml to use it:\n\n```toml, no_test\n[dependencies]\nscroll = { version = \"0.10\", features = [\"derive\"] }\n```\n\n# `std::io` API\n\nScroll 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:\n\n```rust\nuse std::io::Cursor;\nuse scroll::IOread;\n\nfn main() -\u003e Result\u003c(), scroll::Error\u003e {\n    let bytes_ = [0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xef,0xbe,0x00,0x00,];\n    let mut bytes = Cursor::new(bytes_);\n\n    // this will bump the cursor's Seek\n    let foo = bytes.ioread::\u003cusize\u003e()?;\n    // ..ditto\n    let bar = bytes.ioread::\u003cu32\u003e()?;\n    Ok(())\n}\n```\n\nSimilarly, we can write to anything that implements `std::io::Write` quite naturally:\n\n```rust\nuse scroll::{IOwrite, LE, BE};\nuse std::io::{Write, Cursor};\n\nfn main() -\u003e Result\u003c(), scroll::Error\u003e {\n    let mut bytes = [0x0u8; 10];\n    let mut cursor = Cursor::new(\u0026mut bytes[..]);\n    cursor.write_all(b\"hello\")?;\n    cursor.iowrite_with(0xdeadbeef as u32, BE)?;\n    assert_eq!(cursor.into_inner(), [0x68, 0x65, 0x6c, 0x6c, 0x6f, 0xde, 0xad, 0xbe, 0xef, 0x0]);\n    Ok(())\n}\n```\n\n# Advanced Uses\n\nScroll 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.\n\nFor example, suppose we have a datatype and we want to specify how to parse or serialize this datatype out of some arbitrary\nbyte buffer. In order to do this, we need to provide a [TryFromCtx](trait.TryFromCtx.html) impl for our datatype.\n\nIn particular, if we do this for the `[u8]` target, using the convention `(usize, YourCtx)`, you will automatically get access to\ncalling `pread_with::\u003cYourDatatype\u003e` on arrays of bytes.\n\n```rust\nuse scroll::{ctx, Pread, BE, Endian};\n\nstruct Data\u003c'a\u003e {\n  name: \u0026'a str,\n  id: u32,\n}\n\n// note the lifetime specified here\nimpl\u003c'a\u003e ctx::TryFromCtx\u003c'a, Endian\u003e for Data\u003c'a\u003e {\n  type Error = scroll::Error;\n  // and the lifetime annotation on `\u0026'a [u8]` here\n  fn try_from_ctx (src: \u0026'a [u8], endian: Endian)\n    -\u003e Result\u003c(Self, usize), Self::Error\u003e {\n    let offset = \u0026mut 0;\n    let name = src.gread::\u003c\u0026str\u003e(offset)?;\n    let id = src.gread_with(offset, endian)?;\n    Ok((Data { name: name, id: id }, *offset))\n  }\n}\n\nfn main() -\u003e Result\u003c(), scroll::Error\u003e {\n    let bytes = b\"UserName\\x00\\x01\\x02\\x03\\x04\";\n    let data = bytes.pread_with::\u003cData\u003e(0, BE)?;\n    assert_eq!(data.id, 0x01020304);\n    assert_eq!(data.name.to_string(), \"UserName\".to_string());\n    Ok(())\n}\n```\n\nPlease see the official documentation, or a simple [example](examples/data_ctx.rs) for more.\n\n# Contributing\n\nAny ideas, thoughts, or contributions are welcome!\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fm4b%2Fscroll","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fm4b%2Fscroll","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fm4b%2Fscroll/lists"}