• This repository has been archived on 12/Feb/2020
  • Stars
    star
    141
  • Rank 259,180 (Top 6 %)
  • Language
    Rust
  • Created almost 6 years ago
  • Updated almost 5 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

async for rust without the noise

THIS IS A DEAD END

Sad to say that after evaluating rusts vision versus ours, we have decided to no longer invest into rust. osaka is an important building block in devguard.io, but there will be no updates to make it usable for the general public.


osaka is async for rust, inspired by go and the clay programming language

Its designed around continuations rather than combinators, allowing a much more readable flow.

Why

rust's tokio/futures ecosystem is a complex monolith that doesn't work well for constrained devices such as the 2MB flash mips boxes i work on (tokio is 1Mb alone, plus all the futures combinators) osaka is more of a hack that works for me rather than an attempt to overtake futures.rs.

Continuations are much easier to understand than combinators and require no specific runtime.

what it looks like

originally i was planning to implement a proc macro that would allow for golang style chans

#[osaka]
pub fn something(bar: chan String) {
    let foo <- bar;
}

however, due to lack of interest in alternatives to tokio, i decided to just roll with the absolut minimum effort, so it looks like this:

#[osaka]
pub fn something(bar: Channel<String>) {
    let foo = sync!(bar);
}

in real code you will probably want to register something to a Poll instance to re-activate the closure when the poll is ready.

#[osaka]
pub fn something(poll: Poll) -> Result<Vec<String>, std::io::Error> {
    let sock    = mio::UdpSocket::bind(&"0.0.0.0:0".parse().unwrap())?;
    let token   = poll.register(&sock, mio::Ready::readable(), mio::PollOpt::level()).unwrap();

    loop {
        let mut buf = vec![0; 1024];
        if let Err(e) = sock.recv_from(&mut buf) {
            if e.kind() == std::io::ErrorKind::WouldBlock {
                yield poll.again(token, Some(Duration::from_secs(1)));
            }
        }
    }
}

pub fn main() {
    let poll = osaka::Poll::new();
    something(poll).run().unwrap();
}

note that there is no singleton runtime in the background. the entire executor (poll) is explicitly passed as argument. osaka is significantly more simplistic than futures.rs on purpose.

here's some actual code from osaka-dns:

#[osaka]
pub fn resolve(poll: Poll, names: Vec<String>) -> Result<Vec<String>, Error> {
    //...
    let sock = UdpSocket::bind(&"0.0.0.0:0".parse().unwrap()).map_err(|e| Error::Io(e))?;
    let token = poll
        .register(&sock, mio::Ready::readable(), mio::PollOpt::level())
        .unwrap();
    //...

    // wait for a packet
    let pkt = match loop {
        // wait for the token to be ready, or timeout
        yield poll.again(token.clone(), Some(Duration::from_secs(5)));
        if now.elapsed() >= Duration::from_secs(5) {
            // timeout
            break None;
        }
        // now the socket _should_ be ready
        let (len, from) = match sock.recv_from(&mut buf) {
            Ok(v) => v,
            Err(e) => {
                // but just in case it isn't lets re-loop
                if e.kind() == std::io::ErrorKind::WouldBlock {
                    continue;
                }
                return Err(Error::Io(e));
            }
        };
    }

    // do stuff with the pkt
    // ...
}

pub fn test(poll: Poll) -> Result<(), Error> {
    let mut a = resolve(
        poll.clone(),
        vec![
            "3.carrier.devguard.io".into(),
        ],
    );
    let y = osaka::sync!(a);
    println!("resolved: {:?}", y);
    Ok(())
}

pub fn main() {
    tinylogger::init().ok();
    let poll = osaka::Poll::new();
    test(poll).run().unwrap();
}

differences to async/await

One of the most important features is that all behaviour is well defined. A panic is always a bug in osaka, not in your code. Osaka is generally more designed for the "it compiles, ship it" workflow. and more biased towards explicitness and "easy to argue about" rather than trying to hide the event flow from the user for the sake of "easy to write" code.

  • osaka does not have implicit dependencies
  • osaka::Again contains a continuation token instead of a hidden singleton "task" registry.
  • readyness is explicit, making the code easier to argue about in terms of "what is happening here"
  • all errors are explicit
  • there is no undefined behaviour. a panic is a bug in osaka, not in your code.
  • "hot functions" as described in RFC2394 work fine in osaka, since continuation points are explicit.

More Repositories

1

elfkit

rust elf parsing, manipulation and (re)linking toolkit
Rust
202
star
2

pug-rs

pug.js reimplemented in rust for speed
Rust
27
star
3

vag_reverse_engineering

volkswagen vw audi group reverse engineering
C
19
star
4

aws-terraform-vault-consul-nomad-wireguard

zero to nomad cluster on aws
HCL
11
star
5

zztop

for science
10
star
6

ugo

go without GOPATH
Go
7
star
7

archon

content addressable image store
Rust
6
star
8

usb-mining-watchdog-china

reverse engineering of the crappy chinese usb mining watchdog thing
Rust
5
star
9

Kite

Modern event driven C++ toolkit for embedded linux
C++
5
star
10

MONORAKE

static website builder that just works
Go
4
star
11

kicad

kicad stuff
3
star
12

stonecast

dlna services done my way. i.e. not crappy.
C++
3
star
13

ppsbench

sigrok gui for running current sink test
C++
3
star
14

pn532

Rust
2
star
15

xdo-go

golang wrapper for libxdo
Go
2
star
16

bolter-research

content addressable storage for ELF binaries
Rust
2
star
17

artanis-light

2
star
18

madpack

stupid small json binary encoding
Go
2
star
19

libvirt-hub-agent

C
2
star
20

ceramic-rust

channels over proccess for rust
Rust
2
star
21

bolter

content addressed elf linker
Rust
2
star
22

qtftp

C++
1
star
23

EagleLibraries

1
star
24

screeps

screeps ai in typescript
TypeScript
1
star
25

coinz

Rust
1
star
26

gcmap

Rust
1
star
27

vault-init

bootstrap a a vault-consul-nomad cluster from a single command
Go
1
star
28

codeclimate-rustfmt

this enables rustfmt as codeclimate engine
Shell
1
star
29

btrfs-workspace-plugin

Jenkins plugin to make workspaces btrfs snapshots
Java
1
star
30

kite-mqtt

mqtt client in kite/c++
C++
1
star
31

zzsinglemoduletest

1
star
32

carrier-custom-service-example

Rust
1
star
33

valetudo-dreameadapter

1
star
34

LazerSharks

Embedded Linux C++ HttpServer framework, similator to rack/plug/etc
C++
1
star
35

clay.io.events

Asynch i/o for clay.
1
star
36

witch

A permission elevation mechanism protecting the user from the machine, instead of the other way round.
C++
1
star
37

msul

musl libc, actually.
C
1
star
38

tinylogger

env_logger semi-compatible logger but much much smaller
Rust
1
star
39

feistel

collision-free pseudorandom sequence using a feistel cipher in cycle walking mode
Go
1
star
40

tplink-bootloader

C
1
star
41

rblue

a reimplementation of the bluez userspace in pure ruby
Ruby
1
star