ketos 0.12.0

Lisp dialect scripting and extension language
Documentation
//! Demonstrates interoperation -- calling methods on Rust values from Ketos

#[macro_use] extern crate ketos;
#[macro_use] extern crate ketos_derive;

use std::cell::Cell;
use std::rc::Rc;

use ketos::{Error, Interpreter, Value};

/// A simple structure that says "Hello."
#[derive(Debug, ForeignValue, FromValueRef)]
pub struct Hello {
    who: String,
}

impl Hello {
    /// Creates a new `Hello` to say "Hello" to `who`.
    pub fn new(who: String) -> Hello {
        Hello{who: who}
    }

    /// Returns a string saying "Hello" to someone.
    pub fn say_hello(&self) -> String {
        format!("Hello, {}!", self.who)
    }
}

/// Contains an internal counter
#[derive(Debug, ForeignValue, FromValueRef)]
pub struct Counter {
    // Sharing a value with Ketos means we can only access it through `&self`.
    // Mutation of values is possible through internally mutable containers,
    // such as `Cell` and `RefCell`.
    count: Cell<u32>,
}

impl Counter {
    /// Creates a new `Counter` with counter value `0`.
    pub fn new() -> Counter {
        Counter{count: Cell::new(0)}
    }

    /// Increments the internal counter and returns the previous value.
    pub fn count(&self) -> u32 {
        let old = self.count.get();
        self.count.set(old + 1);
        old
    }
}

// Ketos wrapper for `Hello::say_hello`
fn say_hello(hello: &Hello) -> Result<String, Error> {
    Ok(hello.say_hello())
}

// Ketos wrapper for `Counter::count`
fn count(counter: &Counter) -> Result<u32, Error> {
    Ok(counter.count())
}

fn main() {
    // First, create an interpreter.
    let interp = Interpreter::new();

    // Create a shared `Hello` value.
    let hello = Rc::new(Hello::new("world".into()));

    // Create a shared `Counter` value.
    let counter = Rc::new(Counter::new());

    // Inserts wrapper functions into the global scope.
    ketos_fn!{ interp.scope() => "count" =>
        fn count(counter: &Counter) -> u32 }
    ketos_fn!{ interp.scope() => "say-hello" =>
        fn say_hello(hello: &Hello) -> String }

    // Defines a `main` function within the global scope to accept our values.
    interp.run_code(r#"
        (define (main hello counter)
          (do
            (println "Hello from Ketos: ~a" (say-hello hello))
            (println "Count from Ketos: ~a" (count counter))))
        "#, None).unwrap();

    interp.call("main", vec![
        Value::Foreign(hello.clone()),
        Value::Foreign(counter.clone()),
    ]).unwrap();

    println!("Hello from Rust: {}", hello.say_hello());
    println!("Count from Rust: {}", counter.count());
}