1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//! # LuaJIT RS
//! 
//! `luajit_rs` is a simple wrapper around the LuaJIT project, allowing it to
//! be called from Rust easily and with minimal overhead. Most functions in this
//! crate correspond directly to underlying Lua C API calls
//! 
//! # Examples
//! 
//! ```
//! #[macro_use]
//! extern crate luajit;
//!
//! use luajit::{c_int, State};
//!
//! fn return_42(state: &mut State) -> c_int {
//!     state.push(42);
//!
//!     1
//! }
//!
//! pub fn main() {
//!     let mut state = State::new();
//!     state.open_libs();
//!     state.do_string(r#"print("Hello world!")"#);
//!
//!     state.push(lua_fn!(return_42));
//!     state.set_global("return_42");
//!     state.do_string(r#"print(return_42())"#);
//! }
//! ```

extern crate libc;

pub mod ffi;
pub mod state;
pub mod types;

pub use state::{State, ThreadStatus};
pub use types::{LuaFunction, LuaObject};

pub use libc::c_int;

/// This macro is used to wrap a rust function in an `extern "C"` trampoline
/// to automatically pass a [`State`](state/struct.State.html) struct as the first
/// argument instead of a `lua_State` raw pointer
/// 
/// # Examples
/// 
/// ```
/// #[macro_use] extern crate luajit;
///
/// use luajit::{State, c_int, ThreadStatus};
///
/// fn return_42(state: &mut State) -> c_int {
///     state.push(42);
///
///     1
/// }
///
/// fn main() {
///     let mut state = State::new();
///     state.open_libs();
///
///     state.push(lua_fn!(return_42));
///     state.set_global("return_42");
///     let status = state.do_string("if return_42() ~= 42 then error() end");
///     assert_eq!(status, ThreadStatus::Ok);
///     
///     // Equivalent
///     state.register("return_42", lua_fn!(return_42).unwrap());
/// }
/// ```
#[macro_export]
macro_rules! lua_fn {
    ($method:path) => {
        {
            #[allow(unused)]
            unsafe extern "C" fn trampoline(l: *mut $crate::ffi::lua_State) -> $crate::c_int {
                $method(&mut $crate::State::from_ptr(l))
            };

            Some(trampoline as $crate::LuaFunction)
        }
    }
}

/// This macro can be used to automatically generate a `luaL_Reg`
/// struct for the provided function, with name `name`
#[macro_export]
macro_rules! lua_func {
    ($name:expr, $method:path) => {
        {
            $crate::ffi::lauxlib::luaL_Reg {
                name: c_str!($name),
                func: lua_fn!($method),
            }
        }
    };
}

/// This macro can be used to automatically generate a `luaL_Reg`
/// struct for the provided method, with name `name`. It automatically
/// reads an instances of struct `$st` from userdata and provides it as
/// an argument.
#[macro_export]
macro_rules! lua_method {
    ($name:expr, $st:ty, $method:path) => {
        {
            #[allow(unused)]
            unsafe extern "C" fn trampoline(l: *mut $crate::ffi::lua_State) -> $crate::c_int {
                let mut state = $crate::State::from_ptr(l);
                let st = &mut *state.check_userdata::<$st>(1).unwrap();

                $method(st, &mut state)
            };

            $crate::ffi::lauxlib::luaL_Reg {
                name: c_str!($name),
                func: Some(trampoline),
            }
        }
    }
}

#[macro_export]
macro_rules! c_str {
    ($s:expr) => {
        concat!($s, "\x00").as_ptr() as *const i8
    }
}