effect handlers in rust
Go to file
annieversary 224d61d4e1 rewrite parsing. add support for paths and optional name 2022-01-21 10:38:02 +00:00
effers-derive rewrite parsing. add support for paths and optional name 2022-01-21 10:38:02 +00:00
examples rewrite parsing. add support for paths and optional name 2022-01-21 10:38:02 +00:00
src rewrite parsing. add support for paths and optional name 2022-01-21 10:38:02 +00:00
.gitignore start and finish lmao 2022-01-19 20:56:39 +00:00
Cargo.toml start and finish lmao 2022-01-19 20:56:39 +00:00
README.org readme 2022-01-19 21:14:40 +00:00

README.org

effers

effect handlers in rust

how to use

defining effects

effects are defined with traits

trait Printer {
    fn print(&mut self, s: &str);
}
trait Logger {
    fn debug(&mut self, s: &str);
    fn info(&mut self, s: &str);
}

all the trait functions (that are used in programs) must take &mut self as a parameter

defining a program

programs are defined as a normal function, with the added program attribute

#[program(Smth => Printer(print as p), Logger(debug, info))]
fn smth(val: u8) -> u8 {
    p("hey hi hello");

    debug("this is a debug-level log");
    info("this is a info-level log");

    val + 3
}

the first token (Smth) will be the name of the program. effects are listed after the => token

listing effects

effects are listed by writing the trait's name, followed by a parenthesized list of the functions that will be used

functions can be given an alias using the as keyword

defining effect handlers

effect handlers are defined by declaring a struct, and implementing the trait on it

struct IoPrinter;
impl Printer for IoPrinter {
    fn print(&mut self, s: &str) {
        println!("{}", s)
    }
}

struct FileLogger;
impl Logger for FileLogger {
    fn debug(&mut self, s: &str) {
        println!("debug: {}", s)
    }
    fn info(&mut self, s: &str) {
        println!("info: {}", s)
    }
}

running programs

programs are run by providing the corresponding handlers in order, and finally calling the run method, providing it the required parameters

let result: u8 = Smth.add(IoPrinter).add(FileLogger).run(3);
assert_eq!(result, 6);

full example

use effers::program;

#[program(Smth => Printer(print as p), Logger(debug, info))]
fn smth(val: u8) -> u8 {
    p("hey hi hello");

    debug("this is a debug-level log");
    info("this is a info-level log");

    val + 3
}

fn main() {
    // maybe smth like this?
    let result: u8 = Smth.add(IoPrinter).add(FileLogger).run(3);
    assert_eq!(result, 6);
    let other_result: u8 = Smth
        .add(IoPrinter)
        .add(NetworkLogger {
            credentials: "secret password".to_string(),
        })
        .run(8);
    assert_eq!(other_result, 11);
}

// effects
trait Printer {
    fn print(&mut self, s: &str);
}
trait Logger {
    fn debug(&mut self, s: &str);
    fn info(&mut self, s: &str);
}

struct IoPrinter;
impl Printer for IoPrinter {
    fn print(&mut self, s: &str) {
        println!("{}", s)
    }
}

struct FileLogger;
impl Logger for FileLogger {
    fn debug(&mut self, s: &str) {
        println!("debug: {}", s)
    }
    fn info(&mut self, s: &str) {
        println!("info: {}", s)
    }
}

struct NetworkLogger {
    credentials: String,
}
impl Logger for NetworkLogger {
    fn debug(&mut self, s: &str) {
        println!(
            "debug through network: {}; with password {}",
            s, self.credentials
        )
    }
    fn info(&mut self, s: &str) {
        println!(
            "info through network: {}; with password {}",
            s, self.credentials
        )
    }
}