All Projects → m4b → Scroll

m4b / Scroll

Licence: mit
Scroll - making scrolling through buffers fun since 2016

Programming Languages

rust
11053 projects

Projects that are alternatives of or similar to Scroll

Ecst
[WIP] Experimental C++14 multithreaded compile-time entity-component-system library.
Stars: ✭ 418 (+318%)
Mutual labels:  generic, parallel
Binary
Generic and fast binary serializer for Go
Stars: ✭ 86 (-14%)
Mutual labels:  generic
Flowa
🔥Service level control flow for Node.js
Stars: ✭ 66 (-34%)
Mutual labels:  parallel
Cvise
Super-parallel Python port of the C-Reduce
Stars: ✭ 77 (-23%)
Mutual labels:  parallel
Go Tdigest
A T-Digest implementation in golang
Stars: ✭ 67 (-33%)
Mutual labels:  parallel
Cypress Parallel
Reduce up to 40% your Cypress suite execution time parallelizing the test run on the same machine.
Stars: ✭ 78 (-22%)
Mutual labels:  parallel
Openmp Examples
openmp examples
Stars: ✭ 64 (-36%)
Mutual labels:  parallel
Generic Auto Updater
Generic Auto-Updater: a robust, user-friendly, clean and efficient Auto-Updater to maintain any client patched.
Stars: ✭ 95 (-5%)
Mutual labels:  generic
Redrun
✨🐌 🐎✨ fastest npm scripts runner
Stars: ✭ 85 (-15%)
Mutual labels:  parallel
Sorty
Fast Concurrent / Parallel Sorting in Go
Stars: ✭ 74 (-26%)
Mutual labels:  parallel
Parallel
This project now lives on in a rewrite at https://gitlab.redox-os.org/redox-os/parallel
Stars: ✭ 1,181 (+1081%)
Mutual labels:  parallel
Forge
A Generic Low-Code Framework Built on a Config-Driven Tree Walker
Stars: ✭ 70 (-30%)
Mutual labels:  generic
Hibitset
Hierarchical bit set container
Stars: ✭ 81 (-19%)
Mutual labels:  parallel
Parallel
A golang parallel library, used for business logic aggregation and refactory without changing user function declaration.
Stars: ✭ 67 (-33%)
Mutual labels:  parallel
Nytl
Modern C++ generic header-only template library.
Stars: ✭ 87 (-13%)
Mutual labels:  generic
Pelagia
Automatic parallelization (lock-free multithreading thread) tool developed by Surparallel Open Source.Pelagia is embedded key value database that implements a small, fast, high-reliability on ANSI C.
Stars: ✭ 1,132 (+1032%)
Mutual labels:  parallel
Async
Async utilities for Golang.
Stars: ✭ 72 (-28%)
Mutual labels:  parallel
Paraspec
Parallel RSpec test runner
Stars: ✭ 77 (-23%)
Mutual labels:  parallel
Floops.jl
Fast sequential, threaded, and distributed for-loops for Julia—fold for humans™
Stars: ✭ 96 (-4%)
Mutual labels:  parallel
Goreuse
Generic Code for Go
Stars: ✭ 93 (-7%)
Mutual labels:  generic

Build Status

Scroll - cast some magic

         _______________
    ()==(              (@==()
         '______________'|
           |             |
           |   ἀρετή     |
         __)_____________|
    ()==(               (@==()
         '--------------'

Documentation

https://docs.rs/scroll

Usage

Add to your Cargo.toml

[dependencies]
scroll = "0.10"

Overview

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.

Because self is immutable, all reads can be performed in parallel and hence are trivially parallelizable.

A simple example demonstrates its flexibility:

use scroll::{ctx, Pread, LE};

fn main() -> Result<(), scroll::Error> {
    let bytes: [u8; 4] = [0xde, 0xad, 0xbe, 0xef];

    // reads a u32 out of `b` with the endianness of the host machine, at offset 0, turbofish-style
    let number: u32 = bytes.pread::<u32>(0)?;
    // ...or a byte, with type ascription on the binding.
    let byte: u8 = bytes.pread(0)?;

    //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!

    // If we want, we can explicitly add a endianness to read with by calling `pread_with`.
    // The following reads a u32 out of `b` with Big Endian byte order, at offset 0
    let be_number: u32 = bytes.pread_with(0, scroll::BE)?;
    // or a u16 - specify the type either on the variable or with the beloved turbofish
    let be_number2 = bytes.pread_with::<u16>(2, scroll::BE)?;

    // Scroll has core friendly errors (no allocation). This will have the type `scroll::Error::BadOffset` because it tried to read beyond the bound
    let byte: scroll::Result<i64> = bytes.pread(0);

    // Scroll is extensible: as long as the type implements `TryWithCtx`, then you can read your type out of the byte array!

    // We can parse out custom datatypes, or types with lifetimes
    // if they implement the conversion trait `TryFromCtx`; here we parse a C-style \0 delimited &str (safely)
    let hello: &[u8] = b"hello_world\0more words";
    let hello_world: &str = hello.pread(0)?;
    assert_eq!("hello_world", hello_world);

    // ... and this parses the string if its space separated!
    use scroll::ctx::*;
    let spaces: &[u8] = b"hello world some junk";
    let world: &str = spaces.pread_with(6, StrCtx::Delimiter(SPACE))?;
    assert_eq!("world", world);
    Ok(())
}

Deriving Pread and Pwrite

Scroll implements a custom derive that can provide Pread and Pwrite implementations for your structs.

use scroll::{Pread, Pwrite, BE};

#[derive(Pread, Pwrite)]
struct Data {
    one: u32,
    two: u16,
    three: u8,
}

fn main() -> Result<(), scroll::Error> {
    let bytes: [u8; 7] = [0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xff];
    // Read a single `Data` at offset zero in big-endian byte order.
    let data: Data = bytes.pread_with(0, BE)?;
    assert_eq!(data.one, 0xdeadbeef);
    assert_eq!(data.two, 0xface);
    assert_eq!(data.three, 0xff);

    // Write it back to a buffer
    let mut out: [u8; 7] = [0; 7];
    out.pwrite_with(data, 0, BE)?;
    assert_eq!(bytes, out);
    Ok(())
}

This feature is not enabled by default, you must enable the derive feature in Cargo.toml to use it:

[dependencies]
scroll = { version = "0.10", features = ["derive"] }

std::io API

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:

use std::io::Cursor;
use scroll::IOread;

fn main() -> Result<(), scroll::Error> {
    let bytes_ = [0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xef,0xbe,0x00,0x00,];
    let mut bytes = Cursor::new(bytes_);

    // this will bump the cursor's Seek
    let foo = bytes.ioread::<usize>()?;
    // ..ditto
    let bar = bytes.ioread::<u32>()?;
    Ok(())
}

Similarly, we can write to anything that implements std::io::Write quite naturally:

use scroll::{IOwrite, LE, BE};
use std::io::{Write, Cursor};

fn main() -> Result<(), scroll::Error> {
    let mut bytes = [0x0u8; 10];
    let mut cursor = Cursor::new(&mut bytes[..]);
    cursor.write_all(b"hello")?;
    cursor.iowrite_with(0xdeadbeef as u32, BE)?;
    assert_eq!(cursor.into_inner(), [0x68, 0x65, 0x6c, 0x6c, 0x6f, 0xde, 0xad, 0xbe, 0xef, 0x0]);
    Ok(())
}

Advanced Uses

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.

For example, suppose we have a datatype and we want to specify how to parse or serialize this datatype out of some arbitrary byte buffer. In order to do this, we need to provide a TryFromCtx impl for our datatype.

In particular, if we do this for the [u8] target, using the convention (usize, YourCtx), you will automatically get access to calling pread_with::<YourDatatype> on arrays of bytes.

use scroll::{ctx, Pread, BE, Endian};

struct Data<'a> {
  name: &'a str,
  id: u32,
}

// note the lifetime specified here
impl<'a> ctx::TryFromCtx<'a, Endian> for Data<'a> {
  type Error = scroll::Error;
  // and the lifetime annotation on `&'a [u8]` here
  fn try_from_ctx (src: &'a [u8], endian: Endian)
    -> Result<(Self, usize), Self::Error> {
    let offset = &mut 0;
    let name = src.gread::<&str>(offset)?;
    let id = src.gread_with(offset, endian)?;
    Ok((Data { name: name, id: id }, *offset))
  }
}

fn main() -> Result<(), scroll::Error> {
    let bytes = b"UserName\x00\x01\x02\x03\x04";
    let data = bytes.pread_with::<Data>(0, BE)?;
    assert_eq!(data.id, 0x01020304);
    assert_eq!(data.name.to_string(), "UserName".to_string());
    Ok(())
}

Please see the official documentation, or a simple example for more.

Contributing

Any ideas, thoughts, or contributions are welcome!

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].