File tree 5 files changed +129
-3
lines changed
5 files changed +129
-3
lines changed Original file line number Diff line number Diff line change @@ -12,16 +12,43 @@ pub use libc::c_int;
12
12
/// This macro is used to wrap a rust function in an `extern "C"` trampoline
13
13
/// to automatically pass a [`State`](state/struct.State.html) struct as the first
14
14
/// argument instead of a `lua_State` raw pointer
15
+ ///
16
+ /// # Examples
17
+ ///
18
+ /// ```
19
+ /// #[macro_use] extern crate luajit;
20
+ ///
21
+ /// use luajit::{State, c_int, ThreadStatus};
22
+ ///
23
+ /// fn return_42(state: &mut State) -> c_int {
24
+ /// state.push(42);
25
+ ///
26
+ /// 1
27
+ /// }
28
+ ///
29
+ /// fn main() {
30
+ /// let mut state = State::new();
31
+ /// state.open_libs();
32
+ ///
33
+ /// state.push(lua_fn!(return_42));
34
+ /// state.set_global("return_42");
35
+ /// let status = state.do_string("if return_42() ~= 42 then error() end");
36
+ /// assert_eq!(status, ThreadStatus::Ok);
37
+ ///
38
+ /// // Equivalent
39
+ /// state.register("return_42", lua_fn!(return_42).unwrap());
40
+ /// }
41
+ /// ```
15
42
#[ macro_export]
16
43
macro_rules! lua_fn {
17
44
( $method: path) => {
18
45
{
19
46
#[ allow( unused) ]
20
47
unsafe extern "C" fn trampoline( l: * mut $crate:: ffi:: lua_State) -> $crate:: c_int {
21
- $method( & mut State :: from_ptr( l) )
48
+ $method( & mut $crate :: State :: from_ptr( l) )
22
49
} ;
23
50
24
- Some ( trampoline)
51
+ Some ( trampoline as $crate :: LuaFunction )
25
52
}
26
53
}
27
54
}
Original file line number Diff line number Diff line change @@ -430,7 +430,14 @@ impl State {
430
430
/// Registers all functions in `fns` on the global table `name`. If name
431
431
/// is `None`, all functions are instead registered on the value on the top
432
432
/// of the stack.
433
- pub fn register_fns ( & mut self , name : Option < & str > , fns : Vec < luaL_Reg > ) {
433
+ pub fn register_fns ( & mut self , name : Option < & str > , mut fns : Vec < luaL_Reg > ) {
434
+ // Add a sentinel struct, even if one already exists adding a second
435
+ // shouldn't break anything and incur minimal overhead
436
+ fns. push ( luaL_Reg {
437
+ name : ptr:: null ( ) ,
438
+ func : None
439
+ } ) ;
440
+
434
441
match name {
435
442
Some ( s) => unsafe {
436
443
luaL_register ( self . state , CString :: new ( s) . unwrap ( ) . as_ptr ( ) , fns. as_ptr ( ) ) ;
Original file line number Diff line number Diff line change @@ -97,6 +97,20 @@ impl LuaValue for LuaFunction {
97
97
}
98
98
}
99
99
100
+ impl LuaValue for Option < LuaFunction > {
101
+ fn push_val ( self , l : * mut ffi:: lua_State ) {
102
+ if let Some ( func) = self {
103
+ unsafe {
104
+ ffi:: lua_pushcfunction ( l, Some ( func) ) ;
105
+ }
106
+ } else {
107
+ unsafe {
108
+ ffi:: lua_pushnil ( l) ;
109
+ }
110
+ }
111
+ }
112
+ }
113
+
100
114
impl < T > LuaValue for T where T : LuaObject {
101
115
fn push_val ( self , l : * mut ffi:: lua_State ) {
102
116
let mut state = State :: from_ptr ( l) ;
Original file line number Diff line number Diff line change
1
+ #[ macro_use] extern crate luajit;
2
+
3
+ use luajit:: { State , c_int, ThreadStatus } ;
4
+
5
+ fn return_42 ( state : & mut State ) -> c_int {
6
+ state. push ( 42 ) ;
7
+
8
+ 1
9
+ }
10
+
11
+ #[ test]
12
+ fn test_lua_fn ( ) {
13
+ let mut state = State :: new ( ) ;
14
+ state. open_libs ( ) ;
15
+
16
+ state. register ( "return_42" , lua_fn ! ( return_42) . unwrap ( ) ) ;
17
+ let status = state. do_string ( "if return_42() ~= 42 then error() end" ) ;
18
+ assert_eq ! ( status, ThreadStatus :: Ok ) ;
19
+ }
20
+
21
+ #[ test]
22
+ fn test_push_lua_function ( ) {
23
+ let mut state = State :: new ( ) ;
24
+ state. open_libs ( ) ;
25
+
26
+ state. push ( lua_fn ! ( return_42) ) ;
27
+ state. set_global ( "return_42" ) ;
28
+ let status = state. do_string ( "if return_42() ~= 42 then error() end" ) ;
29
+ assert_eq ! ( status, ThreadStatus :: Ok ) ;
30
+ }
Original file line number Diff line number Diff line change @@ -89,4 +89,52 @@ pub fn test_new_struct() {
89
89
if foo:add() ~= 6 then error() end"
90
90
) ;
91
91
assert_eq ! ( res, ThreadStatus :: Ok ) ;
92
+ }
93
+
94
+ struct B {
95
+ pub val : i32
96
+ }
97
+
98
+ impl LuaObject for B {
99
+ fn name ( ) -> * const i8 {
100
+ c_str ! ( "B" )
101
+ }
102
+
103
+ fn lua_fns ( ) -> Vec < ffi:: luaL_Reg > {
104
+ vec ! [
105
+ lua_method!( "add" , B , B :: add) ,
106
+ ffi:: luaL_Reg {
107
+ name: std:: ptr:: null( ) ,
108
+ func: None
109
+ }
110
+ ]
111
+ }
112
+ }
113
+
114
+ impl B {
115
+ fn add ( & mut self , state : & mut State ) -> c_int {
116
+ let x = state. to_int ( 2 ) . unwrap ( ) ;
117
+ self . val += x;
118
+ state. push ( self . val ) ;
119
+
120
+ 1
121
+ }
122
+ }
123
+
124
+ #[ test]
125
+ pub fn test_double_sentinel ( ) {
126
+ let mut state = State :: new ( ) ;
127
+ state. open_libs ( ) ;
128
+
129
+ state. push ( B {
130
+ val : 1 ,
131
+ } ) ;
132
+
133
+ state. set_global ( "test" ) ;
134
+
135
+ let res = state. do_string ( "test:add(4)" ) ;
136
+ assert_eq ! ( res, ThreadStatus :: Ok ) ;
137
+
138
+ let res = state. do_string ( "if test:add(4) ~= 9 then error() end" ) ;
139
+ assert_eq ! ( res, ThreadStatus :: Ok ) ;
92
140
}
You can’t perform that action at this time.
0 commit comments