userdata/
main.rs

1// The MIT License (MIT)
2//
3// Copyright (c) 2016 J.C. Moyer
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in
13// all copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21// THE SOFTWARE.
22
23extern crate lua;
24extern crate libc;
25
26use lua::ffi::lua_State;
27use lua::{State, Function};
28use libc::c_int;
29
30struct Point2D {
31  // using i64 for convenience since lua defaults to 64 bit integers
32  x: i64,
33  y: i64
34}
35
36impl Point2D {
37  fn new(x: i64, y: i64) -> Point2D {
38    return Point2D {
39      x: x, y: y
40    };
41  }
42
43  #[allow(non_snake_case)]
44  unsafe extern "C" fn lua_new(L: *mut lua_State) -> c_int {
45    let mut state = State::from_ptr(L);
46    // takes two optional integer parameters
47    let x = state.opt_integer(1, 0);
48    let y = state.opt_integer(2, 0);
49    // construct new userdata in lua space and initialize it
50    *state.new_userdata_typed::<Point2D>() = Point2D::new(x, y);
51    // set the userdata's metatable so we can call methods on it
52    state.set_metatable_from_registry("Point2D");
53    // return the userdata on top of the stack
54    1
55  }
56
57  #[allow(non_snake_case)]
58  unsafe extern "C" fn lua_x(L: *mut lua_State) -> c_int {
59    let mut state = State::from_ptr(L);
60    let point = state.check_userdata(1, "Point2D") as *mut Point2D;
61    state.push_integer((*point).x);
62    1
63  }
64
65  #[allow(non_snake_case)]
66  unsafe extern "C" fn lua_y(L: *mut lua_State) -> c_int {
67    let mut state = State::from_ptr(L);
68    let point = state.check_userdata(1, "Point2D") as *mut Point2D;
69    state.push_integer((*point).y);
70    1
71  }
72}
73
74const POINT2D_LIB: [(&'static str, Function); 3] = [
75  ("new", Some(Point2D::lua_new)),
76  ("x",   Some(Point2D::lua_x)),
77  ("y",   Some(Point2D::lua_y))
78];
79
80fn main() {
81  let mut state = lua::State::new();
82
83  state.open_libs();
84
85  // make a Point2D table globally available to the lua state and register
86  // our functions there:
87  state.new_table();
88  state.set_fns(&POINT2D_LIB, 0);
89  // copy reference to Point2D table so we can keep the original reference on
90  // the stack for later
91  state.push_value(-1);
92  state.set_global("Point2D");
93
94  // create a metatable for Point2D in the lua registry that refers to the
95  // global Point2D table:
96  state.new_metatable("Point2D");
97  // copy reference to Point2D table
98  state.push_value(-2);
99  // Point2Dmetatable.__index = Point2D
100  state.set_field(-2, "__index");
101
102  // pop metatable and Point2D table from the stack
103  state.pop(2);
104
105  // try it out:
106  state.do_string("local p = Point2D.new(12, 34)
107                   print(p:x(), p:y())");
108}