Targets · Rust · Drivers

Drivers

The native drivers that provide the interface, console and network.

Contents

How a Program becomes Rust, in parts. Start with the introduction, then follow each part into the rendered output and the runtime it links against.

Defining a driver

A driver is a type implementing the Driver trait: it drains one context channel and reconciles the resources it owns. Here is a console driver — it drains the Console.Lines channel and prints each line that has changed since the last cycle.

use std::collections::HashMap;

struct ConsoleDriver {
    last_by_id: HashMap<i64, String>,
}

impl Driver for ConsoleDriver {
    fn channel(&self) -> &str { "Console.Lines" }
    fn kind(&self) -> DriverKind { DriverKind::Array }
    fn init(&mut self, _add_updates: AddUpdates) {}

    fn dispatch(&mut self, emissions: Vec<Line>) {
        for line in emissions {
            if self.last_by_id.get(&line.id) != Some(&line.text) {
                println!("{}", line.text);
                self.last_by_id.insert(line.id, line.text);
            }
        }
    }
}

Registering it

A program lists the drivers it uses; the runtime opens a channel for each and never hardcodes one.

fn main() {
    Program::Application(Box::new(|| Main()), vec![
        Box::new(ConsoleDriver { last_by_id: HashMap::new() }),
    ]);
}

How the runtime runs it

Each cycle the runtime opens the driver's channel, runs the reactive program (which emits into it), drains it, and passes the vector to dispatch:

Context::open_array("Console.Lines");
program = Reactive::run(program, updates);
driver.dispatch(Context::drain_array("Console.Lines"));

A driver that produces events — a timer, a network reply, often on its own thread — calls the add_updates it was given in init, which schedules the next cycle. The three shapes are the same as everywhere: a tree renderer (the terminal interface), a request set (network), and a shared ticker.