ekzhang/crepe

Lifetime parameters in relations

ekzhang opened this issue · 0 comments

Right now, Crepe recommends that you pass references to types like Strings in relations, rather than values. This is for efficiency reasons, as relations are required to implement the Copy trait. For example, the following code is valid:

use crepe::crepe;

crepe! {
    @input
    struct Edge(&'static str, &'static str);

    @output
    struct Reachable(&'static str, &'static str);

    // Transitive closure
    Reachable(n, m) <- Edge(n, m);
    Reachable(n, m) <- Edge(n, k), Reachable(k, m);
}

fn main() {
    let mut runtime = Crepe::new();
    runtime.extend(&[
        Edge("hello", "world"),
        Edge("world", "foo"),
        Edge("world", "bar"),
    ]);

    let (reachable,) = runtime.run();
    println!("Reachable: {}", reachable.len());
    for Reachable(x, y) in reachable {
        println!("edge: {} -> {}", x, y);
    }
}

However, with non-'static lifetimes, Rust requires that the struct declaration be generic over the lifetime parameter. Currently Crepe does not check for this, but it would be useful to write code with non-static lifetimes such as:

use crepe::crepe;

crepe! {
    @input
    struct Edge<'a>(&'a str, &'a str); // does not compile currently

    @output
    struct Reachable<'a>(&'a str, &'a str); // does not compile currently

    // Transitive closure
    Reachable(n, m) <- Edge(n, m);
    Reachable(n, m) <- Edge(n, k), Reachable(k, m);
}

fn main() {
    let dyn_string = String::from("dynamic");

    let mut runtime = Crepe::new();
    runtime.extend(&[
        Edge("hello", "world"),
        Edge("world", "foo"),
        Edge("world", "bar"),
        Edge("world", &dyn_string),
    ]);

    let (reachable,) = runtime.run();
    println!("Reachable: {}", reachable.len());
    for Reachable(x, y) in reachable {
        println!("edge: {} -> {}", x, y);
    }
}