eclisp 0.2.0

Bindings for Embeddable Common Lisp
use eclisp::{Lisp, LispClass, LispError, lisp_impl};

// Check examples/replicate.rs for a simpler example before this.

#[derive(LispClass)]
#[lisp(name = "transform", auto)]
struct Transform {
    x: f32,
    y: f32,
}

#[derive(LispClass)]
#[lisp(name = "player", impl)]
struct Player {
    #[lisp]
    health: i32,

    // `#[lisp(ref)]` creates the accessor by reference for another structure implementing
    // `LispClass`.
    #[lisp(ref)]
    transform: Transform,
}

#[lisp_impl]
impl Player {
    // A method can also return a reference.
    #[method]
    fn transform_ref(&mut self) -> &mut Transform {
        &mut self.transform
    }
}

fn main() -> Result<(), LispError> {
    let lisp = Lisp::new()?;

    lisp.enter(|ctx| {
        ctx.defclass(Transform::class())?;
        ctx.defclass(Player::class())?;

        ctx.eval(
            r#"
(defun move-player (player)
  (let ((transform (player-transform player)))
    (incf (transform-x transform) 5.0)
    (incf (transform-y transform) 10.0)))
"#,
        )?;

        let mut player = Player {
            health: 100,
            transform: Transform { x: 1.0, y: 2.0 },
        };

        println!("Player before:");
        println!("  Health: {}", player.health);
        println!(
            "  Position: ({}, {})",
            player.transform.x, player.transform.y
        );

        ctx.with(&mut player, |obj| {
            ctx.call("move-player", &[obj])?;

            let transform = ctx.call("player-transform-ref", &[obj])?;
            let x = ctx.call("transform-x", &[&transform])?;
            let y = ctx.call("transform-y", &[&transform])?;

            println!(
                "Position through Lisp: ({}, {})",
                x.try_as_f64()?,
                y.try_as_f64()?
            );

            Ok::<(), LispError>(())
        })?;

        println!("\nPlayer after:");
        println!("  Health: {}", player.health);
        println!(
            "  Position: ({}, {})",
            player.transform.x, player.transform.y
        );

        Ok::<(), LispError>(())
    })
}