TyOverby / ares

A Lisp made for easy integration with Rust.
9 stars 1 forks source link

Start working context into the repo #14

Closed TyOverby closed 9 years ago

TyOverby commented 9 years ago

This is taking over the other context pull-request because it is way simpler and easier to make iterative improvements to.

bwo commented 9 years ago

This does seem much simpler. One question I had about the earlier PR was that it seems as if you'll need different contexts for rust/ares interactions modifying different types (Or perhaps just different values? Can the context be reloaded?). How will those contexts interact? Can they be layered?

TyOverby commented 9 years ago

The earlier PR (which I plan on adding things from iteratively) limited the context to being "loaded" with only one type. I think this will be reasonable for most applications because they can think of that type as the "public api" that Ares gets access to. That API struct could contain mutable borrows into whatever else you wanted to access.

The context can certainly be reloaded! The way the contexts work is that Context lets you read/write global variables at will, but LoadedContext will let you read/write AND do eval. (This is because doing an eval on an unloaded Context could call a ForeignFunction that wants to modify a state, whereas reading and writing globals never requires the state to be filled).

LoadedContexts are always temporary. They borrow their state by mutable reference so that when they go out of scope, they release the borrow on the rust state object and release the borrow on the unloaded Context (which can be loaded again).

Here's another example (the state stuff is not finished yet):

// Our context will have a bool as the state
let mut context: Context<bool> = Context::new();
// So we can write functions that expect a boolean state
context.set("trigger", user_fn(|args, ctx| *ctx.state = true));

for _ in 0 .. 10 {
    // A new state for each loop!
    bool triggered = false;
    // The context gets loaded once for every iteration in the loop
    let mut loaded = context.load(&mut triggered);
    // Cann the function that we loaded in the bare Context
    loaded.eval_str("(trigger)");
    // Our local state gets modified
    assert!(triggered);
}
TyOverby commented 9 years ago

Oh. I should point out that if the user doesn't want to load a state 100% of the time, that person could just have their state be Option<T> instead of just T and then load a None.