lua/wrapper/
state.rs

1// The MIT License (MIT)
2//
3// Copyright (c) 2014 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
23use ffi;
24use ffi::{lua_State, lua_Debug};
25
26use libc::{c_int, c_void, c_char, size_t};
27use std::{mem, ptr, str, slice, any};
28use std::ffi::{CString, CStr};
29use std::ops::DerefMut;
30use std::sync::Mutex;
31use super::convert::{ToLua, FromLua};
32
33use ::{
34  Number,
35  Integer,
36  Function,
37  Allocator,
38  Hook,
39  Index,
40};
41
42/// Arithmetic operations for `lua_arith`.
43#[derive(Clone, Copy, Debug, PartialEq, Eq)]
44pub enum Arithmetic {
45  Add = ffi::LUA_OPADD as isize,
46  Sub = ffi::LUA_OPSUB as isize,
47  Mul = ffi::LUA_OPMUL as isize,
48  Mod = ffi::LUA_OPMOD as isize,
49  Pow = ffi::LUA_OPPOW as isize,
50  Div = ffi::LUA_OPDIV as isize,
51  IDiv = ffi::LUA_OPIDIV as isize,
52  BAnd = ffi::LUA_OPBAND as isize,
53  BOr = ffi::LUA_OPBOR as isize,
54  BXor = ffi::LUA_OPBXOR as isize,
55  Shl = ffi::LUA_OPSHL as isize,
56  Shr = ffi::LUA_OPSHR as isize,
57  Unm = ffi::LUA_OPUNM as isize,
58  BNot = ffi::LUA_OPBNOT as isize,
59}
60
61/// Comparison operations for `lua_compare`.
62#[derive(Clone, Copy, Debug, PartialEq, Eq)]
63pub enum Comparison {
64  Eq = ffi::LUA_OPEQ as isize,
65  Lt = ffi::LUA_OPLT as isize,
66  Le = ffi::LUA_OPLE as isize,
67}
68
69/// Status of a Lua state.
70#[must_use]
71#[derive(Clone, Copy, Debug, PartialEq, Eq)]
72pub enum ThreadStatus {
73  Ok = ffi::LUA_OK as isize,
74  Yield = ffi::LUA_YIELD as isize,
75  RuntimeError = ffi::LUA_ERRRUN as isize,
76  SyntaxError = ffi::LUA_ERRSYNTAX as isize,
77  MemoryError = ffi::LUA_ERRMEM as isize,
78  GcError = ffi::LUA_ERRGCMM as isize,
79  MessageHandlerError = ffi::LUA_ERRERR as isize,
80  FileError = ffi::LUA_ERRFILE as isize,
81}
82
83impl ThreadStatus {
84  fn from_c_int(i: c_int) -> ThreadStatus {
85    match i {
86      ffi::LUA_OK => ThreadStatus::Ok,
87      ffi::LUA_YIELD => ThreadStatus::Yield,
88      ffi::LUA_ERRRUN => ThreadStatus::RuntimeError,
89      ffi::LUA_ERRSYNTAX => ThreadStatus::SyntaxError,
90      ffi::LUA_ERRMEM => ThreadStatus::MemoryError,
91      ffi::LUA_ERRGCMM => ThreadStatus::GcError,
92      ffi::LUA_ERRERR => ThreadStatus::MessageHandlerError,
93      ffi::LUA_ERRFILE => ThreadStatus::FileError,
94      _ => panic!("Unknown Lua error code: {}", i),
95    }
96  }
97
98  /// Returns `true` for error statuses and `false` for `Ok` and `Yield`.
99  pub fn is_err(self) -> bool {
100    match self {
101      ThreadStatus::RuntimeError |
102      ThreadStatus::SyntaxError |
103      ThreadStatus::MemoryError |
104      ThreadStatus::GcError |
105      ThreadStatus::MessageHandlerError |
106      ThreadStatus::FileError => true,
107      ThreadStatus::Ok |
108      ThreadStatus::Yield => false,
109    }
110  }
111}
112
113/// Options for the Lua garbage collector.
114#[derive(Clone, Copy, Debug, PartialEq, Eq)]
115pub enum GcOption {
116  Stop = ffi::LUA_GCSTOP as isize,
117  Restart = ffi::LUA_GCRESTART as isize,
118  Collect = ffi::LUA_GCCOLLECT as isize,
119  Count = ffi::LUA_GCCOUNT as isize,
120  CountBytes = ffi::LUA_GCCOUNTB as isize,
121  Step = ffi::LUA_GCSTEP as isize,
122  SetPause = ffi::LUA_GCSETPAUSE as isize,
123  SetStepMul = ffi::LUA_GCSETSTEPMUL as isize,
124  IsRunning = ffi::LUA_GCISRUNNING as isize,
125}
126
127/// Represents all possible Lua data types.
128#[derive(Clone, Copy, Debug, PartialEq, Eq)]
129pub enum Type {
130  None = ffi::LUA_TNONE as isize,
131  Nil = ffi::LUA_TNIL as isize,
132  Boolean = ffi::LUA_TBOOLEAN as isize,
133  LightUserdata = ffi::LUA_TLIGHTUSERDATA as isize,
134  Number = ffi::LUA_TNUMBER as isize,
135  String = ffi::LUA_TSTRING as isize,
136  Table = ffi::LUA_TTABLE as isize,
137  Function = ffi::LUA_TFUNCTION as isize,
138  Userdata = ffi::LUA_TUSERDATA as isize,
139  Thread = ffi::LUA_TTHREAD as isize,
140}
141
142impl Type {
143  fn from_c_int(i: c_int) -> Option<Type> {
144    match i {
145      ffi::LUA_TNIL => Some(Type::Nil),
146      ffi::LUA_TBOOLEAN => Some(Type::Boolean),
147      ffi::LUA_TLIGHTUSERDATA => Some(Type::LightUserdata),
148      ffi::LUA_TNUMBER => Some(Type::Number),
149      ffi::LUA_TSTRING => Some(Type::String),
150      ffi::LUA_TTABLE => Some(Type::Table),
151      ffi::LUA_TFUNCTION => Some(Type::Function),
152      ffi::LUA_TUSERDATA => Some(Type::Userdata),
153      ffi::LUA_TTHREAD => Some(Type::Thread),
154      _ => None
155    }
156  }
157}
158
159/// Represents all built-in libraries
160#[derive(Debug, Clone, Copy, PartialEq, Eq)]
161pub enum Library {
162  Base,
163  Coroutine,
164  Table,
165  Io,
166  Os,
167  String,
168  Utf8,
169  Bit32,
170  Math,
171  Debug,
172  Package,
173}
174
175impl Library {
176  /// The name of the module in lua code
177  pub fn name(&self) -> &'static str {
178    use self::Library::*;
179    match *self {
180      Base => "_G",
181      Coroutine => "coroutine",
182      Table => "table",
183      Io => "io",
184      Os => "os",
185      String => "string",
186      Utf8 => "utf8",
187      Bit32 => "bit32",
188      Math => "math",
189      Debug => "debug",
190      Package => "package",
191    }
192  }
193  /// Returns C function that may be used to load the library
194  #[allow(non_snake_case)]
195  pub fn loader(&self) -> unsafe extern fn (L: *mut lua_State) -> c_int {
196    use self::Library::*;
197    match *self {
198      Base => ffi::luaopen_base,
199      Coroutine => ffi::luaopen_coroutine,
200      Table => ffi::luaopen_table,
201      Io => ffi::luaopen_io,
202      Os => ffi::luaopen_os,
203      String => ffi::luaopen_string,
204      Utf8 => ffi::luaopen_utf8,
205      Bit32 => ffi::luaopen_bit32,
206      Math => ffi::luaopen_math,
207      Debug => ffi::luaopen_debug,
208      Package => ffi::luaopen_package,
209    }
210  }
211}
212
213/// Type of Lua references generated through `reference` and `unreference`.
214#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
215pub struct Reference(c_int);
216
217/// The result of `reference` for `nil` values.
218pub const REFNIL: Reference = Reference(ffi::LUA_REFNIL);
219
220/// A value that will never be returned by `reference`.
221pub const NOREF: Reference = Reference(ffi::LUA_REFNIL);
222
223impl Reference {
224  /// Returns `true` if this reference is equal to `REFNIL`.
225  pub fn is_nil_ref(self) -> bool {
226    self == REFNIL
227  }
228
229  /// Returns `true` if this reference is equal to `NOREF`.
230  pub fn is_no_ref(self) -> bool {
231    self == NOREF
232  }
233
234  /// Convenience function that returns the value of this reference.
235  pub fn value(self) -> c_int {
236    let Reference(value) = self;
237    value
238  }
239}
240
241bitflags! {
242  #[doc="Hook point masks for `lua_sethook`."]
243  flags HookMask: c_int {
244    #[doc="Called when the interpreter calls a function."]
245    const MASKCALL  = ffi::LUA_MASKCALL,
246    #[doc="Called when the interpreter returns from a function."]
247    const MASKRET   = ffi::LUA_MASKRET,
248    #[doc="Called when the interpreter is about to start the execution of a new line of code."]
249    const MASKLINE  = ffi::LUA_MASKLINE,
250    #[doc="Called after the interpreter executes every `count` instructions."]
251    const MASKCOUNT = ffi::LUA_MASKCOUNT
252  }
253}
254
255/// Specifies that all results from a `call` invocation should be pushed onto
256/// the stack.
257pub const MULTRET: c_int = ffi::LUA_MULTRET;
258
259/// Pseudo-index used to access the Lua registry.
260pub const REGISTRYINDEX: Index = ffi::LUA_REGISTRYINDEX;
261
262/// The registry key for the main thread, to be used with `raw_geti`.
263pub const RIDX_MAINTHREAD: Integer = ffi::LUA_RIDX_MAINTHREAD;
264/// The registry key for the global environment, to be used with `raw_geti`.
265pub const RIDX_GLOBALS: Integer = ffi::LUA_RIDX_GLOBALS;
266
267unsafe extern fn continue_func<F>(st: *mut lua_State, status: c_int, ctx: ffi::lua_KContext) -> c_int
268  where F: FnOnce(&mut State, ThreadStatus) -> c_int
269{
270  mem::transmute::<_, Box<F>>(ctx)(&mut State::from_ptr(st), ThreadStatus::from_c_int(status))
271}
272
273/// Box for extra data.
274pub type Extra = Box<any::Any + 'static + Send>;
275type ExtraHolder = *mut *mut Mutex<Option<Extra>>;
276
277unsafe extern fn alloc_func(_: *mut c_void, ptr: *mut c_void, old_size: size_t, new_size: size_t) -> *mut c_void {
278  // In GCC and MSVC, malloc uses an alignment calculated roughly by:
279  //   max(2 * sizeof(size_t), alignof(long double))
280  // The stable high-level API used here does not expose alignment directly, so
281  // we get as close as possible by using usize to determine alignment. Lua
282  // seems unlikely to require 16-byte alignment for any of its purposes.
283
284  #[inline]
285  fn divide_size(size: size_t) -> usize {
286    1 + (size - 1) / mem::size_of::<usize>()
287  }
288
289  let ptr = ptr as *mut usize;
290  if new_size == 0 {
291    // if new_size is 0, act like free()
292    if !ptr.is_null() {
293      // Lua promises to provide the correct old_size
294      drop(Vec::<usize>::from_raw_parts(ptr, 0, divide_size(old_size)));
295    }
296    ptr::null_mut()
297  } else {
298    // otherwise, act like realloc()
299    let mut vec;
300    if ptr.is_null() {
301      // old_size is a type indicator, not used here
302      vec = Vec::<usize>::with_capacity(divide_size(new_size));
303    } else {
304      // Lua promises to provide the correct old_size
305      if new_size > old_size {
306        // resulting capacity should be new_size
307        vec = Vec::<usize>::from_raw_parts(ptr, 0, divide_size(old_size));
308        vec.reserve_exact(divide_size(new_size));
309      } else {
310        // Lua assumes this will never fail
311        vec = Vec::<usize>::from_raw_parts(ptr, divide_size(new_size), divide_size(old_size));
312        vec.shrink_to_fit();
313      }
314    }
315    let res = vec.as_mut_ptr();
316    mem::forget(vec); // don't deallocate
317    res as *mut c_void
318  }
319}
320
321/// An idiomatic, Rust wrapper around `lua_State`.
322///
323/// Function names adhere to Rust naming conventions. Most of the time, this
324/// means breaking up long C function names using underscores; however, there
325/// are some cases where different names are used. Typically, these are cases
326/// where the name itself is a reserved Rust keyword (such as `ref` in
327/// `luaL_ref` or `where` in `luaL_where`) or where the name is used in both
328/// the base Lua library and the auxiliary Lua library (such as
329/// `lua_getmetatable` and `luaL_getmetatable`). More descriptive names have
330/// been chosen for these functions. Finally, any reference to C functions has
331/// been replaced by the term `native functions`. `lua_iscfunction` is
332/// `is_native_fn` and `lua_tocfunction` is `to_native_fn`.
333#[allow(non_snake_case)]
334pub struct State {
335  L: *mut lua_State,
336  owned: bool
337}
338
339unsafe impl Send for State {}
340
341impl State {
342  /// Initializes a new Lua state. This function does not open any libraries
343  /// by default. Calls `lua_newstate` internally.
344  pub fn new() -> State {
345    unsafe {
346      let state = ffi::lua_newstate(Some(alloc_func), ptr::null_mut());
347      let extra_ptr = ffi::lua_getextraspace(state) as ExtraHolder;
348      let mutex = Box::new(Mutex::new(None));
349      *extra_ptr = Box::into_raw(mutex);
350      State { L: state, owned: true }
351    }
352  }
353
354  /// Constructs a wrapper `State` from a raw pointer. This is suitable for use
355  /// inside of native functions that accept a `lua_State` to obtain a wrapper.
356  #[allow(non_snake_case)]
357  pub unsafe fn from_ptr(L: *mut lua_State) -> State {
358    State { L: L, owned: false }
359  }
360
361  /// Returns an unsafe pointer to the wrapped `lua_State`.
362  pub fn as_ptr(&self) -> *mut lua_State {
363    self.L
364  }
365
366  /// Maps to `luaL_openlibs`.
367  pub fn open_libs(&mut self) {
368    unsafe { ffi::luaL_openlibs(self.L) }
369  }
370
371  /// Preloads library, i.e. it's not exposed, but can be required
372  pub fn preload_library(&mut self, lib: Library) {
373    unsafe {
374      let pre = CString::new("_PRELOAD").unwrap();
375      ffi::luaL_getsubtable(self.L, ffi::LUA_REGISTRYINDEX, pre.as_ptr());
376      self.push_fn(Some(lib.loader()));
377      self.set_field(-2, lib.name());
378      self.pop(1);  /* remove lib */
379    }
380  }
381
382  /// Loads a built-in library and exposes it into lua code
383  pub fn load_library(&mut self, lib: Library) {
384    self.requiref(lib.name(), Some(lib.loader()), true);
385    self.pop(1);  /* remove lib */
386  }
387
388  /// Maps to `luaopen_base`.
389  pub fn open_base(&mut self) -> c_int {
390    unsafe { ffi::luaopen_base(self.L) }
391  }
392
393  /// Maps to `luaopen_coroutine`.
394  pub fn open_coroutine(&mut self) -> c_int {
395    unsafe { ffi::luaopen_coroutine(self.L) }
396  }
397
398  /// Maps to `luaopen_table`.
399  pub fn open_table(&mut self) -> c_int {
400    unsafe { ffi::luaopen_table(self.L) }
401  }
402
403  /// Maps to `luaopen_io`.
404  pub fn open_io(&mut self) -> c_int {
405    unsafe { ffi::luaopen_io(self.L) }
406  }
407
408  /// Maps to `luaopen_os`.
409  pub fn open_os(&mut self) -> c_int {
410    unsafe { ffi::luaopen_os(self.L) }
411  }
412
413  /// Maps to `luaopen_string`.
414  pub fn open_string(&mut self) -> c_int {
415    unsafe { ffi::luaopen_string(self.L) }
416  }
417
418  /// Maps to `luaopen_utf8`.
419  pub fn open_utf8(&mut self) -> c_int {
420    unsafe { ffi::luaopen_utf8(self.L) }
421  }
422
423  /// Maps to `luaopen_bit32`.
424  pub fn open_bit32(&mut self) -> c_int {
425    unsafe { ffi::luaopen_bit32(self.L) }
426  }
427
428  /// Maps to `luaopen_math`.
429  pub fn open_math(&mut self) -> c_int {
430    unsafe { ffi::luaopen_math(self.L) }
431  }
432
433  /// Maps to `luaopen_debug`.
434  pub fn open_debug(&mut self) -> c_int {
435    unsafe { ffi::luaopen_debug(self.L) }
436  }
437
438  /// Maps to `luaopen_package`.
439  pub fn open_package(&mut self) -> c_int {
440    unsafe { ffi::luaopen_package(self.L) }
441  }
442
443  /// Maps to `luaL_dofile`.
444  pub fn do_file(&mut self, filename: &str) -> ThreadStatus {
445    let c_str = CString::new(filename).unwrap();
446    let result = unsafe {
447      ffi::luaL_dofile(self.L, c_str.as_ptr())
448    };
449    ThreadStatus::from_c_int(result)
450  }
451
452  /// Maps to `luaL_dostring`.
453  pub fn do_string(&mut self, s: &str) -> ThreadStatus {
454    let c_str = CString::new(s).unwrap();
455    let result = unsafe {
456      ffi::luaL_dostring(self.L, c_str.as_ptr())
457    };
458    ThreadStatus::from_c_int(result)
459  }
460
461  /// Pushes the given value onto the stack.
462  pub fn push<T: ToLua>(&mut self, value: T) {
463    value.to_lua(self);
464  }
465
466  /// Converts the value on top of the stack to a value of type `T` and returns
467  /// it.
468  pub fn to_type<T: FromLua>(&mut self, index: Index) -> Option<T> {
469    FromLua::from_lua(self, index)
470  }
471
472  //===========================================================================
473  // State manipulation
474  //===========================================================================
475  /// Maps to `lua_close`.
476  pub fn close(self) {
477    // lua_close will be called in the Drop impl
478    if !self.owned {
479      panic!("cannot explicitly close non-owned Lua state")
480    }
481  }
482
483  /// Maps to `lua_newthread`.
484  pub fn new_thread(&mut self) -> State {
485    unsafe {
486      State::from_ptr(ffi::lua_newthread(self.L))
487    }
488  }
489
490  /// Maps to `lua_atpanic`.
491  pub fn at_panic(&mut self, panicf: Function) -> Function {
492    unsafe { ffi::lua_atpanic(self.L, panicf) }
493  }
494
495  /// Maps to `lua_version`.
496  pub fn version(state: Option<&mut State>) -> Number {
497    let ptr = match state {
498      Some(state) => state.L,
499      None        => ptr::null_mut()
500    };
501    unsafe { *ffi::lua_version(ptr) }
502  }
503
504  //===========================================================================
505  // Basic stack manipulation
506  //===========================================================================
507  /// Maps to `lua_absindex`.
508  pub fn abs_index(&mut self, idx: Index) -> Index {
509    unsafe { ffi::lua_absindex(self.L, idx) }
510  }
511
512  /// Maps to `lua_gettop`.
513  pub fn get_top(&mut self) -> Index {
514    unsafe { ffi::lua_gettop(self.L) }
515  }
516
517  /// Maps to `lua_settop`.
518  pub fn set_top(&mut self, index: Index) {
519    unsafe { ffi::lua_settop(self.L, index) }
520  }
521
522  /// Maps to `lua_pushvalue`.
523  pub fn push_value(&mut self, index: Index) {
524    unsafe { ffi::lua_pushvalue(self.L, index) }
525  }
526
527  /// Maps to `lua_rotate`.
528  pub fn rotate(&mut self, idx: Index, n: c_int) {
529    unsafe { ffi::lua_rotate(self.L, idx, n) }
530  }
531
532  /// Maps to `lua_copy`.
533  pub fn copy(&mut self, from_idx: Index, to_idx: Index) {
534    unsafe { ffi::lua_copy(self.L, from_idx, to_idx) }
535  }
536
537  /// Maps to `lua_checkstack`.
538  pub fn check_stack(&mut self, extra: c_int) -> bool {
539    let result = unsafe { ffi::lua_checkstack(self.L, extra) };
540    result != 0
541  }
542
543  /// Maps to `lua_xmove`.
544  pub fn xmove(&mut self, to: &mut State, n: c_int) {
545    unsafe { ffi::lua_xmove(self.L, to.L, n) }
546  }
547
548  //===========================================================================
549  // Access functions (stack -> C)
550  //===========================================================================
551  /// Maps to `lua_isnumber`.
552  pub fn is_number(&mut self, index: Index) -> bool {
553    unsafe { ffi::lua_isnumber(self.L, index) == 1 }
554  }
555
556  /// Maps to `lua_isstring`.
557  pub fn is_string(&mut self, index: Index) -> bool {
558    unsafe { ffi::lua_isstring(self.L, index) == 1 }
559  }
560
561  /// Maps to `lua_iscfunction`.
562  pub fn is_native_fn(&mut self, index: Index) -> bool {
563    unsafe { ffi::lua_iscfunction(self.L, index) == 1 }
564  }
565
566  /// Maps to `lua_isinteger`.
567  pub fn is_integer(&mut self, index: Index) -> bool {
568    unsafe { ffi::lua_isinteger(self.L, index) == 1 }
569  }
570
571  /// Maps to `lua_isuserdata`.
572  pub fn is_userdata(&mut self, index: Index) -> bool {
573    unsafe { ffi::lua_isuserdata(self.L, index) == 1 }
574  }
575
576  /// Maps to `lua_type`.
577  pub fn type_of(&mut self, index: Index) -> Option<Type> {
578    let result = unsafe { ffi::lua_type(self.L, index) };
579    Type::from_c_int(result)
580  }
581
582  /// Maps to `lua_typename`.
583  pub fn typename_of(&mut self, tp: Type) -> &'static str {
584    unsafe {
585      let ptr = ffi::lua_typename(self.L, tp as c_int);
586      let slice = CStr::from_ptr(ptr).to_bytes();
587      str::from_utf8(slice).unwrap()
588    }
589  }
590
591  /// Maps to `lua_tonumberx`.
592  pub fn to_numberx(&mut self, index: Index) -> Option<Number> {
593    let mut isnum: c_int = 0;
594    let result = unsafe { ffi::lua_tonumberx(self.L, index, &mut isnum) };
595    if isnum == 0 {
596      None
597    } else {
598      Some(result)
599    }
600  }
601
602  /// Maps to `lua_tointegerx`.
603  pub fn to_integerx(&mut self, index: Index) -> Option<Integer> {
604    let mut isnum: c_int = 0;
605    let result = unsafe { ffi::lua_tointegerx(self.L, index, &mut isnum) };
606    if isnum == 0 {
607      None
608    } else {
609      Some(result)
610    }
611  }
612
613  /// Maps to `lua_toboolean`.
614  pub fn to_bool(&mut self, index: Index) -> bool {
615    let result = unsafe { ffi::lua_toboolean(self.L, index) };
616    result != 0
617  }
618
619  // omitted: lua_tolstring
620
621  /// Maps to `lua_rawlen`.
622  pub fn raw_len(&mut self, index: Index) -> size_t {
623    unsafe { ffi::lua_rawlen(self.L, index) }
624  }
625
626  /// Maps to `lua_tocfunction`.
627  pub fn to_native_fn(&mut self, index: Index) -> Function {
628    let result = unsafe { ffi::lua_tocfunction(self.L, index) };
629    result
630  }
631
632  /// Maps to `lua_touserdata`.
633  pub fn to_userdata(&mut self, index: Index) -> *mut c_void {
634    unsafe { ffi::lua_touserdata(self.L, index) }
635  }
636
637  /// Convenience function that calls `to_userdata` and performs a cast.
638  //#[unstable(reason="this is an experimental function")]
639  pub unsafe fn to_userdata_typed<'a, T>(&'a mut self, index: Index) -> Option<&'a mut T> {
640    mem::transmute(self.to_userdata(index))
641  }
642
643  /// Maps to `lua_tothread`.
644  pub fn to_thread(&mut self, index: Index) -> Option<State> {
645    let state = unsafe { ffi::lua_tothread(self.L, index) };
646    if state.is_null() {
647      None
648    } else {
649      Some(unsafe { State::from_ptr(state) })
650    }
651  }
652
653  /// Maps to `lua_topointer`.
654  pub fn to_pointer(&mut self, index: Index) -> *const c_void {
655    unsafe { ffi::lua_topointer(self.L, index) }
656  }
657
658  //===========================================================================
659  // Comparison and arithmetic functions
660  //===========================================================================
661  /// Maps to `lua_arith`.
662  pub fn arith(&mut self, op: Arithmetic) {
663    unsafe { ffi::lua_arith(self.L, op as c_int) }
664  }
665
666  /// Maps to `lua_rawequal`.
667  pub fn raw_equal(&mut self, idx1: Index, idx2: Index) -> bool {
668    let result = unsafe { ffi::lua_rawequal(self.L, idx1, idx2) };
669    result != 0
670  }
671
672  /// Maps to `lua_compare`.
673  pub fn compare(&mut self, idx1: Index, idx2: Index, op: Comparison) -> bool {
674    let result = unsafe { ffi::lua_compare(self.L, idx1, idx2, op as c_int) };
675    result != 0
676  }
677
678  //===========================================================================
679  // Push functions (C -> stack)
680  //===========================================================================
681  /// Maps to `lua_pushnil`.
682  pub fn push_nil(&mut self) {
683    unsafe { ffi::lua_pushnil(self.L) }
684  }
685
686  /// Maps to `lua_pushnumber`.
687  pub fn push_number(&mut self, n: Number) {
688    unsafe { ffi::lua_pushnumber(self.L, n) }
689  }
690
691  /// Maps to `lua_pushinteger`.
692  pub fn push_integer(&mut self, i: Integer) {
693    unsafe { ffi::lua_pushinteger(self.L, i) }
694  }
695
696  // omitted: lua_pushstring
697
698  /// Maps to `lua_pushlstring`.
699  pub fn push_string(&mut self, s: &str) {
700    unsafe { ffi::lua_pushlstring(self.L, s.as_ptr() as *const _, s.len() as size_t) };
701  }
702
703  // omitted: lua_pushvfstring
704  // omitted: lua_pushfstring
705
706  /// Maps to `lua_pushcclosure`.
707  pub fn push_closure(&mut self, f: Function, n: c_int) {
708    unsafe { ffi::lua_pushcclosure(self.L, f, n) }
709  }
710
711  /// Maps to `lua_pushboolean`.
712  pub fn push_bool(&mut self, b: bool) {
713    unsafe { ffi::lua_pushboolean(self.L, b as c_int) }
714  }
715
716  /// Maps to `lua_pushlightuserdata`. The Lua state will receive a pointer to
717  /// the given value. The caller is responsible for cleaning up the data. Any
718  /// code that manipulates the userdata is free to modify its contents, so
719  /// memory safety is not guaranteed.
720  pub unsafe fn push_light_userdata<T>(&mut self, ud: *mut T) {
721    ffi::lua_pushlightuserdata(self.L, mem::transmute(ud))
722  }
723
724  /// Maps to `lua_pushthread`.
725  pub fn push_thread(&mut self) -> bool {
726    let result = unsafe { ffi::lua_pushthread(self.L) };
727    result != 1
728  }
729
730  //===========================================================================
731  // Get functions (Lua -> stack)
732  //===========================================================================
733  /// Maps to `lua_getglobal`.
734  pub fn get_global(&mut self, name: &str) -> Type {
735    let c_str = CString::new(name).unwrap();
736    let ty = unsafe {
737      ffi::lua_getglobal(self.L, c_str.as_ptr())
738    };
739    Type::from_c_int(ty).unwrap()
740  }
741
742  /// Maps to `lua_gettable`.
743  pub fn get_table(&mut self, index: Index) -> Type {
744    let ty = unsafe { ffi::lua_gettable(self.L, index) };
745    Type::from_c_int(ty).unwrap()
746  }
747
748  /// Maps to `lua_getfield`.
749  pub fn get_field(&mut self, index: Index, k: &str) -> Type {
750    let c_str = CString::new(k).unwrap();
751    let ty = unsafe {
752      ffi::lua_getfield(self.L, index, c_str.as_ptr())
753    };
754    Type::from_c_int(ty).unwrap()
755  }
756
757  /// Maps to `lua_geti`.
758  pub fn geti(&mut self, index: Index, i: Integer) -> Type {
759    let ty = unsafe {
760      ffi::lua_geti(self.L, index, i)
761    };
762    Type::from_c_int(ty).unwrap()
763  }
764
765  /// Maps to `lua_rawget`.
766  pub fn raw_get(&mut self, index: Index) -> Type {
767    let ty = unsafe { ffi::lua_rawget(self.L, index) };
768    Type::from_c_int(ty).unwrap()
769  }
770
771  /// Maps to `lua_rawgeti`.
772  pub fn raw_geti(&mut self, index: Index, n: Integer) -> Type {
773    let ty = unsafe { ffi::lua_rawgeti(self.L, index, n) };
774    Type::from_c_int(ty).unwrap()
775  }
776
777  /// Maps to `lua_rawgetp`.
778  pub fn raw_getp<T>(&mut self, index: Index, p: *const T) -> Type {
779    let ty = unsafe { ffi::lua_rawgetp(self.L, index, mem::transmute(p)) };
780    Type::from_c_int(ty).unwrap()
781  }
782
783  /// Maps to `lua_createtable`.
784  pub fn create_table(&mut self, narr: c_int, nrec: c_int) {
785    unsafe { ffi::lua_createtable(self.L, narr, nrec) }
786  }
787
788  /// Maps to `lua_newuserdata`. The pointer returned is owned by the Lua state
789  /// and it will be garbage collected when it is no longer in use or the state
790  /// is closed. To specify custom cleanup behavior, use a `__gc` metamethod.
791  pub fn new_userdata(&mut self, sz: size_t) -> *mut c_void {
792    unsafe { ffi::lua_newuserdata(self.L, sz) }
793  }
794
795  /// Convenience function that uses type information to call `new_userdata`
796  /// and perform a cast.
797  ///
798  /// # Example
799  ///
800  /// ```ignore
801  /// unsafe { *state.new_userdata_typed() = MyStruct::new(...); }
802  /// state.set_metatable_from_registry("MyStruct");
803  /// ```
804  //#[unstable(reason="this is an experimental function")]
805  pub fn new_userdata_typed<T>(&mut self) -> *mut T {
806    self.new_userdata(mem::size_of::<T>() as size_t) as *mut T
807  }
808
809  /// Maps to `lua_getmetatable`.
810  pub fn get_metatable(&mut self, objindex: Index) -> bool {
811    let result = unsafe { ffi::lua_getmetatable(self.L, objindex) };
812    result != 0
813  }
814
815  /// Maps to `lua_getuservalue`.
816  pub fn get_uservalue(&mut self, idx: Index) -> Type {
817    let result = unsafe { ffi::lua_getuservalue(self.L, idx) };
818    Type::from_c_int(result).unwrap()
819  }
820
821  //===========================================================================
822  // Set functions (stack -> Lua)
823  //===========================================================================
824  /// Maps to `lua_setglobal`.
825  pub fn set_global(&mut self, var: &str) {
826    let c_str = CString::new(var).unwrap();
827    unsafe { ffi::lua_setglobal(self.L, c_str.as_ptr()) }
828  }
829
830  /// Maps to `lua_settable`.
831  pub fn set_table(&mut self, idx: Index) {
832    unsafe { ffi::lua_settable(self.L, idx) }
833  }
834
835  /// Maps to `lua_setfield`.
836  pub fn set_field(&mut self, idx: Index, k: &str) {
837    let c_str = CString::new(k).unwrap();
838    unsafe { ffi::lua_setfield(self.L, idx, c_str.as_ptr()) }
839  }
840
841  /// Maps to `lua_seti`.
842  pub fn seti(&mut self, idx: Index, n: Integer) {
843    unsafe { ffi::lua_seti(self.L, idx, n) }
844  }
845
846  /// Maps to `lua_rawset`.
847  pub fn raw_set(&mut self, idx: Index) {
848    unsafe { ffi::lua_rawset(self.L, idx) }
849  }
850
851  /// Maps to `lua_rawseti`.
852  pub fn raw_seti(&mut self, idx: Index, n: Integer) {
853    unsafe { ffi::lua_rawseti(self.L, idx, n) }
854  }
855
856  /// Maps to `lua_rawsetp`.
857  pub fn raw_setp<T>(&mut self, idx: Index, p: *const T) {
858    unsafe { ffi::lua_rawsetp(self.L, idx, mem::transmute(p)) }
859  }
860
861  /// Maps to `lua_setmetatable`.
862  pub fn set_metatable(&mut self, objindex: Index) {
863    unsafe { ffi::lua_setmetatable(self.L, objindex) };
864  }
865
866  /// Maps to `lua_setuservalue`.
867  pub fn set_uservalue(&mut self, idx: Index) {
868    unsafe { ffi::lua_setuservalue(self.L, idx) }
869  }
870
871  //===========================================================================
872  // 'load' and 'call' functions (load and run Lua code)
873  //===========================================================================
874  /// Maps to `lua_callk`.
875  pub fn callk<F>(&mut self, nargs: c_int, nresults: c_int, continuation: F)
876    where F: FnOnce(&mut State, ThreadStatus) -> c_int
877  {
878    let func = continue_func::<F>;
879    unsafe {
880      let ctx = mem::transmute(Box::new(continuation));
881      ffi::lua_callk(self.L, nargs, nresults, ctx, Some(func));
882      // no yield occurred, so call the continuation
883      func(self.L, ffi::LUA_OK, ctx);
884    }
885  }
886
887  /// Maps to `lua_call`.
888  pub fn call(&mut self, nargs: c_int, nresults: c_int) {
889    unsafe { ffi::lua_call(self.L, nargs, nresults) }
890  }
891
892  /// Maps to `lua_pcallk`.
893  pub fn pcallk<F>(&mut self, nargs: c_int, nresults: c_int, msgh: c_int, continuation: F) -> c_int
894    where F: FnOnce(&mut State, ThreadStatus) -> c_int
895  {
896    let func = continue_func::<F>;
897    unsafe {
898      let ctx = mem::transmute(Box::new(continuation));
899      // lua_pcallk only returns if no yield occurs, so call the continuation
900      func(self.L, ffi::lua_pcallk(self.L, nargs, nresults, msgh, ctx, Some(func)), ctx)
901    }
902  }
903
904  /// Maps to `lua_pcall`.
905  pub fn pcall(&mut self, nargs: c_int, nresults: c_int, msgh: c_int) -> ThreadStatus {
906    let result = unsafe {
907      ffi::lua_pcall(self.L, nargs, nresults, msgh)
908    };
909    ThreadStatus::from_c_int(result)
910  }
911
912  // TODO: mode typing?
913  /// Maps to `lua_load`.
914  pub fn load<F>(&mut self, mut reader: F, source: &str, mode: &str) -> ThreadStatus
915    where F: FnMut(&mut State) -> &[u8]
916  {
917    unsafe extern fn read<F>(st: *mut lua_State, ud: *mut c_void, sz: *mut size_t) -> *const c_char
918      where F: FnMut(&mut State) -> &[u8]
919    {
920      let mut state = State::from_ptr(st);
921      let slice = mem::transmute::<_, &mut F>(ud)(&mut state);
922      *sz = slice.len() as size_t;
923      slice.as_ptr() as *const _
924    }
925    let source_c_str = CString::new(source).unwrap();
926    let mode_c_str = CString::new(mode).unwrap();
927    let result = unsafe {
928      ffi::lua_load(self.L, Some(read::<F>), mem::transmute(&mut reader), source_c_str.as_ptr(), mode_c_str.as_ptr())
929    };
930    ThreadStatus::from_c_int(result)
931  }
932
933  // returns isize because the return value is dependent on the writer - seems to
934  // be usable for anything
935  /// Maps to `lua_dump`.
936  pub fn dump<F>(&mut self, mut writer: F, strip: bool) -> c_int
937    where F: FnMut(&mut State, &[u8]) -> c_int
938  {
939    unsafe extern fn write<F>(st: *mut lua_State, p: *const c_void, sz: size_t, ud: *mut c_void) -> c_int
940      where F: FnMut(&mut State, &[u8]) -> c_int
941    {
942      mem::transmute::<_, &mut F>(ud)(&mut State::from_ptr(st), slice::from_raw_parts(p as *const _, sz as usize))
943    }
944    unsafe { ffi::lua_dump(self.L, Some(write::<F>), mem::transmute(&mut writer), strip as c_int) }
945  }
946
947  //===========================================================================
948  // Coroutine functions
949  //===========================================================================
950  /// Maps to `lua_yieldk`.
951  pub fn co_yieldk<F>(&mut self, nresults: c_int, continuation: F) -> !
952    where F: FnOnce(&mut State, ThreadStatus) -> c_int
953  {
954    unsafe { ffi::lua_yieldk(self.L, nresults, mem::transmute(Box::new(continuation)), Some(continue_func::<F>)) };
955    panic!("co_yieldk called in non-coroutine context; check is_yieldable first")
956  }
957
958  /// Maps to `lua_yield`. This function is not called `yield` because it is a
959  /// reserved keyword.
960  pub fn co_yield(&mut self, nresults: c_int) -> ! {
961    unsafe { ffi::lua_yield(self.L, nresults) };
962    panic!("co_yield called in non-coroutine context; check is_yieldable first")
963  }
964
965  /// Maps to `lua_resume`.
966  pub fn resume(&mut self, from: Option<&mut State>, nargs: c_int) -> ThreadStatus {
967    let from_ptr = match from {
968      Some(state) => state.L,
969      None        => ptr::null_mut()
970    };
971    let result = unsafe {
972      ffi::lua_resume(self.L, from_ptr, nargs)
973    };
974    ThreadStatus::from_c_int(result)
975  }
976
977  /// Maps to `lua_status`.
978  pub fn status(&mut self) -> ThreadStatus {
979    let result = unsafe { ffi::lua_status(self.L) };
980    ThreadStatus::from_c_int(result)
981  }
982
983  /// Maps to `lua_isyieldable`.
984  pub fn is_yieldable(&mut self) -> bool {
985    let result = unsafe { ffi::lua_isyieldable(self.L) };
986    result != 0
987  }
988
989  //===========================================================================
990  // Garbage-collection function
991  //===========================================================================
992  // TODO: return typing?
993  /// Maps to `lua_gc`.
994  pub fn gc(&mut self, what: GcOption, data: c_int) -> c_int {
995    unsafe { ffi::lua_gc(self.L, what as c_int, data) }
996  }
997
998  //===========================================================================
999  // Miscellaneous functions
1000  //===========================================================================
1001  /// Maps to `lua_error`.
1002  pub fn error(&mut self) -> ! {
1003    unsafe { ffi::lua_error(self.L) };
1004    unreachable!()
1005  }
1006
1007  /// Maps to `lua_next`.
1008  pub fn next(&mut self, idx: Index) -> bool {
1009    let result = unsafe { ffi::lua_next(self.L, idx) };
1010    result != 0
1011  }
1012
1013  /// Maps to `lua_concat`.
1014  pub fn concat(&mut self, n: c_int) {
1015    unsafe { ffi::lua_concat(self.L, n) }
1016  }
1017
1018  /// Maps to `lua_len`.
1019  pub fn len(&mut self, idx: Index) {
1020    unsafe { ffi::lua_len(self.L, idx) }
1021  }
1022
1023  /// Maps to `lua_stringtonumber`.
1024  pub fn string_to_number(&mut self, s: &str) -> size_t {
1025    let c_str = CString::new(s).unwrap();
1026    unsafe { ffi::lua_stringtonumber(self.L, c_str.as_ptr()) }
1027  }
1028
1029  /// Maps to `lua_getallocf`.
1030  pub fn get_alloc_fn(&mut self) -> (Allocator, *mut c_void) {
1031    let mut slot = ptr::null_mut();
1032    (unsafe { ffi::lua_getallocf(self.L, &mut slot) }, slot)
1033  }
1034
1035  /// Maps to `lua_setallocf`.
1036  pub fn set_alloc_fn(&mut self, f: Allocator, ud: *mut c_void) {
1037    unsafe { ffi::lua_setallocf(self.L, f, ud) }
1038  }
1039
1040  //===========================================================================
1041  // Some useful macros (here implemented as functions)
1042  //===========================================================================
1043
1044  /// Set extra data. Return previous value if it was set.
1045  pub fn set_extra(&mut self, extra: Option<Extra>) -> Option<Extra> {
1046    self.with_extra(|opt_extra| mem::replace(opt_extra, extra))
1047  }
1048
1049  /// Do some actions with mutable extra.
1050  pub fn with_extra<F, R>(&mut self, closure: F) -> R
1051    where F: FnOnce(&mut Option<Extra>) -> R {
1052    unsafe {
1053      let extra_ptr = ffi::lua_getextraspace(self.L) as ExtraHolder;
1054      let mutex = Box::from_raw(*extra_ptr);
1055      let result = {
1056        let mut guard = mutex.lock().unwrap();
1057        closure(guard.deref_mut())
1058      };
1059      mem::forget(mutex);
1060      result
1061    }
1062  }
1063
1064  /// Unwrap and downcast extra to typed.
1065  ///
1066  /// # Panics
1067  ///
1068  /// Panics if state has no attached `Extra` or it's impossible to downcast to `T`.
1069  ///
1070  pub fn with_extra_typed<T, F, R>(&mut self, closure: F) -> R
1071    where T: any::Any, F: FnOnce(&mut T) -> R {
1072    self.with_extra(|extra| {
1073      let data = extra.as_mut().unwrap()
1074        .downcast_mut::<T>().unwrap();
1075      closure(data)
1076    })
1077  }
1078
1079  /// Maps to `lua_tonumber`.
1080  pub fn to_number(&mut self, index: Index) -> Number {
1081    unsafe { ffi::lua_tonumber(self.L, index) }
1082  }
1083
1084  /// Maps to `lua_tointeger`.
1085  pub fn to_integer(&mut self, index: Index) -> Integer {
1086    unsafe { ffi::lua_tointeger(self.L, index) }
1087  }
1088
1089  /// Maps to `lua_pop`.
1090  pub fn pop(&mut self, n: c_int) {
1091    unsafe { ffi::lua_pop(self.L, n) }
1092  }
1093
1094  /// Maps to `lua_newtable`.
1095  pub fn new_table(&mut self) {
1096    unsafe { ffi::lua_newtable(self.L) }
1097  }
1098
1099  /// Maps to `lua_register`.
1100  pub fn register(&mut self, n: &str, f: Function) {
1101    let c_str = CString::new(n).unwrap();
1102    unsafe { ffi::lua_register(self.L, c_str.as_ptr(), f) }
1103  }
1104
1105  /// Maps to `lua_pushcfunction`.
1106  pub fn push_fn(&mut self, f: Function) {
1107    unsafe { ffi::lua_pushcfunction(self.L, f) }
1108  }
1109
1110  /// Maps to `lua_isfunction`.
1111  pub fn is_fn(&mut self, index: Index) -> bool {
1112    unsafe { ffi::lua_isfunction(self.L, index) == 1 }
1113  }
1114
1115  /// Maps to `lua_istable`.
1116  pub fn is_table(&mut self, index: Index) -> bool {
1117    unsafe { ffi::lua_istable(self.L, index) == 1 }
1118  }
1119
1120  /// Maps to `lua_islightuserdata`.
1121  pub fn is_light_userdata(&mut self, index: Index) -> bool {
1122    unsafe { ffi::lua_islightuserdata(self.L, index) == 1 }
1123  }
1124
1125  /// Maps to `lua_isnil`.
1126  pub fn is_nil(&mut self, index: Index) -> bool {
1127    unsafe { ffi::lua_isnil(self.L, index) == 1 }
1128  }
1129
1130  /// Maps to `lua_isboolean`.
1131  pub fn is_bool(&mut self, index: Index) -> bool {
1132    unsafe { ffi::lua_isboolean(self.L, index) == 1 }
1133  }
1134
1135  /// Maps to `lua_isthread`.
1136  pub fn is_thread(&mut self, index: Index) -> bool {
1137    unsafe { ffi::lua_isthread(self.L, index) == 1 }
1138  }
1139
1140  /// Maps to `lua_isnone`.
1141  pub fn is_none(&mut self, index: Index) -> bool {
1142    unsafe { ffi::lua_isnone(self.L, index) == 1 }
1143  }
1144
1145  /// Maps to `lua_isnoneornil`.
1146  pub fn is_none_or_nil(&mut self, index: Index) -> bool {
1147    unsafe { ffi::lua_isnoneornil(self.L, index) == 1 }
1148  }
1149
1150  // omitted: lua_pushliteral
1151
1152  /// Maps to `lua_pushglobaltable`.
1153  pub fn push_global_table(&mut self) {
1154    unsafe { ffi::lua_pushglobaltable(self.L) };
1155  }
1156
1157  /// Maps to `lua_insert`.
1158  pub fn insert(&mut self, idx: Index) {
1159    unsafe { ffi::lua_insert(self.L, idx) }
1160  }
1161
1162  /// Maps to `lua_remove`.
1163  pub fn remove(&mut self, idx: Index) {
1164    unsafe { ffi::lua_remove(self.L, idx) }
1165  }
1166
1167  /// Maps to `lua_replace`.
1168  pub fn replace(&mut self, idx: Index) {
1169    unsafe { ffi::lua_replace(self.L, idx) }
1170  }
1171
1172  //===========================================================================
1173  // Debug API
1174  //===========================================================================
1175  /// Maps to `lua_getstack`.
1176  pub fn get_stack(&mut self, level: c_int) -> Option<lua_Debug> {
1177    let mut ar: lua_Debug = unsafe { mem::uninitialized() };
1178    let result = unsafe { ffi::lua_getstack(self.L, level, &mut ar) };
1179    if result == 0 {
1180      None
1181    } else {
1182      Some(ar)
1183    }
1184  }
1185
1186  /// Maps to `lua_getinfo`.
1187  pub fn get_info(&mut self, what: &str) -> Option<lua_Debug> {
1188    let mut ar: lua_Debug = unsafe { mem::uninitialized() };
1189    let c_str = CString::new(what).unwrap();
1190    let result = unsafe { ffi::lua_getinfo(self.L, c_str.as_ptr(), &mut ar) };
1191    if result == 0 {
1192      None
1193    } else {
1194      Some(ar)
1195    }
1196  }
1197
1198  /// Maps to `lua_getlocal`.
1199  pub fn get_local(&mut self, ar: &lua_Debug, n: c_int) -> Option<&str> {
1200    let ptr = unsafe { ffi::lua_getlocal(self.L, ar, n) };
1201    if ptr.is_null() {
1202      None
1203    } else {
1204      let slice = unsafe { CStr::from_ptr(ptr).to_bytes() };
1205      str::from_utf8(slice).ok()
1206    }
1207  }
1208
1209  /// Maps to `lua_setlocal`.
1210  pub fn set_local(&mut self, ar: &lua_Debug, n: c_int) -> Option<&str> {
1211    let ptr = unsafe { ffi::lua_setlocal(self.L, ar, n) };
1212    if ptr.is_null() {
1213      None
1214    } else {
1215      let slice = unsafe { CStr::from_ptr(ptr).to_bytes() };
1216      str::from_utf8(slice).ok()
1217    }
1218  }
1219
1220  /// Maps to `lua_getupvalue`.
1221  pub fn get_upvalue(&mut self, funcindex: Index, n: c_int) -> Option<&str> {
1222    let ptr = unsafe { ffi::lua_getupvalue(self.L, funcindex, n) };
1223    if ptr.is_null() {
1224      None
1225    } else {
1226      let slice = unsafe { CStr::from_ptr(ptr).to_bytes() };
1227      str::from_utf8(slice).ok()
1228    }
1229  }
1230
1231  /// Maps to `lua_setupvalue`.
1232  pub fn set_upvalue(&mut self, funcindex: Index, n: c_int) -> Option<&str> {
1233    let ptr = unsafe { ffi::lua_setupvalue(self.L, funcindex, n) };
1234    if ptr.is_null() {
1235      None
1236    } else {
1237      let slice = unsafe { CStr::from_ptr(ptr).to_bytes() };
1238      str::from_utf8(slice).ok()
1239    }
1240  }
1241
1242  /// Maps to `lua_upvalueid`.
1243  pub fn upvalue_id(&mut self, funcindex: Index, n: c_int) -> *mut c_void {
1244    unsafe { ffi::lua_upvalueid(self.L, funcindex, n) }
1245  }
1246
1247  /// Maps to `lua_upvaluejoin`.
1248  pub fn upvalue_join(&mut self, fidx1: Index, n1: c_int, fidx2: Index, n2: c_int) {
1249    unsafe { ffi::lua_upvaluejoin(self.L, fidx1, n1, fidx2, n2) }
1250  }
1251
1252  /// Maps to `lua_sethook`.
1253  pub fn set_hook(&mut self, func: Hook, mask: HookMask, count: c_int) {
1254    unsafe { ffi::lua_sethook(self.L, func, mask.bits(), count) }
1255  }
1256
1257  /// Maps to `lua_gethook`.
1258  pub fn get_hook(&mut self) -> Hook {
1259    unsafe { ffi::lua_gethook(self.L) }
1260  }
1261
1262  /// Maps to `lua_gethookmask`.
1263  pub fn get_hook_mask(&mut self) -> HookMask {
1264    let result = unsafe { ffi::lua_gethookmask(self.L) };
1265    HookMask::from_bits_truncate(result)
1266  }
1267
1268  /// Maps to `lua_gethookcount`.
1269  pub fn get_hook_count(&mut self) -> c_int {
1270    unsafe { ffi::lua_gethookcount(self.L) }
1271  }
1272
1273  //===========================================================================
1274  // Auxiliary library functions
1275  //===========================================================================
1276  /// Maps to `luaL_checkversion`.
1277  pub fn check_version(&mut self) {
1278    unsafe { ffi::luaL_checkversion(self.L) }
1279  }
1280
1281  /// Maps to `luaL_getmetafield`.
1282  pub fn get_metafield(&mut self, obj: Index, e: &str) -> bool {
1283    let c_str = CString::new(e).unwrap();
1284    let result = unsafe {
1285      ffi::luaL_getmetafield(self.L, obj, c_str.as_ptr())
1286    };
1287    result != 0
1288  }
1289
1290  /// Maps to `luaL_callmeta`.
1291  pub fn call_meta(&mut self, obj: Index, e: &str) -> bool {
1292    let c_str = CString::new(e).unwrap();
1293    let result = unsafe {
1294      ffi::luaL_callmeta(self.L, obj, c_str.as_ptr())
1295    };
1296    result != 0
1297  }
1298
1299  /// Maps to `luaL_tolstring`. This function is not called `to_string` because
1300  /// that method name is used for the `ToString` trait. This function returns
1301  /// a reference to the string at the given index, on which `to_owned` may be
1302  /// called.
1303  pub fn to_str(&mut self, index: Index) -> Option<&str> {
1304    let mut len = 0;
1305    let ptr = unsafe { ffi::luaL_tolstring(self.L, index, &mut len) };
1306    if ptr.is_null() {
1307      None
1308    } else {
1309      let slice = unsafe { slice::from_raw_parts(ptr as *const u8, len as usize) };
1310      str::from_utf8(slice).ok()
1311    }
1312  }
1313
1314  /// Maps to `lua_tolstring`. This function is not called `to_string` because
1315  /// that method name is used for the `ToString` trait. This function returns
1316  /// a reference to the string at the given index, on which `to_owned` may be
1317  /// called.
1318  pub fn to_str_in_place(&mut self, index: Index) -> Option<&str> {
1319    let mut len = 0;
1320    let ptr = unsafe { ffi::lua_tolstring(self.L, index, &mut len) };
1321    if ptr.is_null() {
1322      None
1323    } else {
1324      let slice = unsafe { slice::from_raw_parts(ptr as *const u8, len as usize) };
1325      str::from_utf8(slice).ok()
1326    }
1327  }
1328
1329  /// Maps to `luaL_argerror`.
1330  pub fn arg_error(&mut self, arg: Index, extramsg: &str) -> ! {
1331    // nb: leaks the CString
1332    let c_str = CString::new(extramsg).unwrap();
1333    unsafe { ffi::luaL_argerror(self.L, arg, c_str.as_ptr()) };
1334    unreachable!()
1335  }
1336
1337  // omitted: luaL_checkstring
1338  // omitted: luaL_optstring
1339
1340  /// Maps to `luaL_checknumber`.
1341  pub fn check_number(&mut self, arg: Index) -> Number {
1342    unsafe { ffi::luaL_checknumber(self.L, arg) }
1343  }
1344
1345  /// Maps to `luaL_optnumber`.
1346  pub fn opt_number(&mut self, arg: Index, def: Number) -> Number {
1347    unsafe { ffi::luaL_optnumber(self.L, arg, def) }
1348  }
1349
1350  /// Maps to `luaL_checkinteger`.
1351  pub fn check_integer(&mut self, arg: Index) -> Integer {
1352    unsafe { ffi::luaL_checkinteger(self.L, arg) }
1353  }
1354
1355  /// Maps to `luaL_optinteger`.
1356  pub fn opt_integer(&mut self, arg: Index, def: Integer) -> Integer {
1357    unsafe { ffi::luaL_optinteger(self.L, arg, def) }
1358  }
1359
1360  /// Maps to `luaL_checkstack`.
1361  pub fn check_stack_msg(&mut self, sz: c_int, msg: &str) {
1362    let c_str = CString::new(msg).unwrap();
1363    unsafe { ffi::luaL_checkstack(self.L, sz, c_str.as_ptr()) }
1364  }
1365
1366  /// Maps to `luaL_checktype`.
1367  pub fn check_type(&mut self, arg: Index, t: Type) {
1368    unsafe { ffi::luaL_checktype(self.L, arg, t as c_int) }
1369  }
1370
1371  /// Maps to `luaL_checkany`.
1372  pub fn check_any(&mut self, arg: Index) {
1373    unsafe { ffi::luaL_checkany(self.L, arg) }
1374  }
1375
1376  /// Maps to `luaL_newmetatable`.
1377  pub fn new_metatable(&mut self, tname: &str) -> bool {
1378    let c_str = CString::new(tname).unwrap();
1379    let result = unsafe {
1380      ffi::luaL_newmetatable(self.L, c_str.as_ptr())
1381    };
1382    result != 0
1383  }
1384
1385  /// Maps to `luaL_setmetatable`.
1386  pub fn set_metatable_from_registry(&mut self, tname: &str) {
1387    let c_str = CString::new(tname).unwrap();
1388    unsafe { ffi::luaL_setmetatable(self.L, c_str.as_ptr()) }
1389  }
1390
1391  /// Maps to `luaL_testudata`.
1392  pub fn test_userdata(&mut self, arg: Index, tname: &str) -> *mut c_void {
1393    let c_str = CString::new(tname).unwrap();
1394    unsafe { ffi::luaL_testudata(self.L, arg, c_str.as_ptr()) }
1395  }
1396
1397  /// Convenience function that calls `test_userdata` and performs a cast.
1398  //#[unstable(reason="this is an experimental function")]
1399  pub unsafe fn test_userdata_typed<'a, T>(&'a mut self, arg: Index, tname: &str) -> Option<&'a mut T> {
1400    mem::transmute(self.test_userdata(arg, tname))
1401  }
1402
1403  /// Maps to `luaL_checkudata`.
1404  pub fn check_userdata(&mut self, arg: Index, tname: &str) -> *mut c_void {
1405    let c_str = CString::new(tname).unwrap();
1406    unsafe { ffi::luaL_checkudata(self.L, arg, c_str.as_ptr()) }
1407  }
1408
1409  /// Convenience function that calls `check_userdata` and performs a cast.
1410  //#[unstable(reason="this is an experimental function")]
1411  pub unsafe fn check_userdata_typed<'a, T>(&'a mut self, arg: Index, tname: &str) -> &'a mut T {
1412    mem::transmute(self.check_userdata(arg, tname))
1413  }
1414
1415  /// Maps to `luaL_where`. `where` is a reserved keyword.
1416  pub fn location(&mut self, lvl: c_int) {
1417    unsafe { ffi::luaL_where(self.L, lvl) }
1418  }
1419
1420  // omitted: luaL_error
1421
1422  /// Maps to `luaL_checkoption`.
1423  pub fn check_option(&mut self, arg: Index, def: Option<&str>, lst: &[&str]) -> usize {
1424    use std::vec::Vec;
1425    use libc::c_char;
1426    let mut vec: Vec<*const c_char> = Vec::with_capacity(lst.len() + 1);
1427    let cstrs: Vec<CString> = lst.iter().map(|ent| CString::new(*ent).unwrap()).collect();
1428    for ent in cstrs.iter() {
1429      vec.push(ent.as_ptr());
1430    }
1431    vec.push(ptr::null());
1432    let result = match def {
1433      Some(def) => unsafe {
1434        let c_str = CString::new(def).unwrap();
1435        ffi::luaL_checkoption(self.L, arg, c_str.as_ptr(), vec.as_ptr())
1436      },
1437      None      => unsafe {
1438        ffi::luaL_checkoption(self.L, arg, ptr::null(), vec.as_ptr())
1439      }
1440    };
1441    result as usize
1442  }
1443
1444  /// Maps to `luaL_fileresult`.
1445  pub fn file_result(&mut self, stat: c_int, fname: &str) -> c_int {
1446    let c_str = CString::new(fname).unwrap();
1447    unsafe { ffi::luaL_fileresult(self.L, stat, c_str.as_ptr()) }
1448  }
1449
1450  /// Maps to `luaL_execresult`.
1451  pub fn exec_result(&mut self, stat: c_int) -> c_int {
1452    unsafe { ffi::luaL_execresult(self.L, stat) }
1453  }
1454
1455  /// Maps to `luaL_ref`.
1456  pub fn reference(&mut self, t: Index) -> Reference {
1457    let result = unsafe { ffi::luaL_ref(self.L, t) };
1458    Reference(result)
1459  }
1460
1461  /// Maps to `luaL_unref`.
1462  pub fn unreference(&mut self, t: Index, reference: Reference) {
1463    unsafe { ffi::luaL_unref(self.L, t, reference.value()) }
1464  }
1465
1466  /// Maps to `luaL_loadfilex`.
1467  pub fn load_filex(&mut self, filename: &str, mode: &str) -> ThreadStatus {
1468    let result = unsafe {
1469      let filename_c_str = CString::new(filename).unwrap();
1470      let mode_c_str = CString::new(mode).unwrap();
1471      ffi::luaL_loadfilex(self.L, filename_c_str.as_ptr(), mode_c_str.as_ptr())
1472    };
1473    ThreadStatus::from_c_int(result)
1474  }
1475
1476  /// Maps to `luaL_loadfile`.
1477  pub fn load_file(&mut self, filename: &str) -> ThreadStatus {
1478    let c_str = CString::new(filename).unwrap();
1479    let result = unsafe {
1480      ffi::luaL_loadfile(self.L, c_str.as_ptr())
1481    };
1482    ThreadStatus::from_c_int(result)
1483  }
1484
1485  /// Maps to `luaL_loadbufferx`.
1486  pub fn load_bufferx(&mut self, buff: &[u8], name: &str, mode: &str) -> ThreadStatus {
1487    let name_c_str = CString::new(name).unwrap();
1488    let mode_c_str = CString::new(mode).unwrap();
1489    let result = unsafe { ffi::luaL_loadbufferx(self.L, buff.as_ptr() as *const _, buff.len() as size_t, name_c_str.as_ptr(), mode_c_str.as_ptr()) };
1490    ThreadStatus::from_c_int(result)
1491  }
1492
1493  /// Maps to `luaL_loadstring`.
1494  pub fn load_string(&mut self, source: &str) -> ThreadStatus {
1495    let c_str = CString::new(source).unwrap();
1496    let result = unsafe { ffi::luaL_loadstring(self.L, c_str.as_ptr()) };
1497    ThreadStatus::from_c_int(result)
1498  }
1499
1500  // omitted: luaL_newstate (covered by State constructor)
1501
1502  /// Maps to `luaL_len`.
1503  pub fn len_direct(&mut self, index: Index) -> Integer {
1504    unsafe { ffi::luaL_len(self.L, index) }
1505  }
1506
1507  /// Maps to `luaL_gsub`.
1508  pub fn gsub(&mut self, s: &str, p: &str, r: &str) -> &str {
1509    let s_c_str = CString::new(s).unwrap();
1510    let p_c_str = CString::new(p).unwrap();
1511    let r_c_str = CString::new(r).unwrap();
1512    let ptr = unsafe {
1513      ffi::luaL_gsub(self.L, s_c_str.as_ptr(), p_c_str.as_ptr(), r_c_str.as_ptr())
1514    };
1515    let slice = unsafe { CStr::from_ptr(ptr).to_bytes() };
1516    str::from_utf8(slice).unwrap()
1517  }
1518
1519  /// Maps to `luaL_setfuncs`.
1520  pub fn set_fns(&mut self, l: &[(&str, Function)], nup: c_int) {
1521    use std::vec::Vec;
1522    let mut reg: Vec<ffi::luaL_Reg> = Vec::with_capacity(l.len() + 1);
1523    let ents: Vec<(CString, Function)> = l.iter().map(|&(s, f)| (CString::new(s).unwrap(), f)).collect();
1524    for &(ref s, f) in ents.iter() {
1525      reg.push(ffi::luaL_Reg {
1526        name: s.as_ptr(),
1527        func: f
1528      });
1529    }
1530    reg.push(ffi::luaL_Reg {name: ptr::null(), func: None});
1531    unsafe { ffi::luaL_setfuncs(self.L, reg.as_ptr(), nup) }
1532  }
1533
1534  /// Maps to `luaL_getsubtable`.
1535  pub fn get_subtable(&mut self, idx: Index, fname: &str) -> bool {
1536    let c_str = CString::new(fname).unwrap();
1537    let result = unsafe {
1538      ffi::luaL_getsubtable(self.L, idx, c_str.as_ptr())
1539    };
1540    result != 0
1541  }
1542
1543  /// Maps to `luaL_traceback`.
1544  pub fn traceback(&mut self, state: &mut State, msg: &str, level: c_int) {
1545    let c_str = CString::new(msg).unwrap();
1546    unsafe { ffi::luaL_traceback(self.L, state.L, c_str.as_ptr(), level) }
1547  }
1548
1549  /// Maps to `luaL_requiref`.
1550  pub fn requiref(&mut self, modname: &str, openf: Function, glb: bool) {
1551    let c_str = CString::new(modname).unwrap();
1552    unsafe { ffi::luaL_requiref(self.L, c_str.as_ptr(), openf, glb as c_int) }
1553  }
1554
1555  /// Maps to `luaL_newlibtable`.
1556  pub fn new_lib_table(&mut self, l: &[(&str, Function)]) {
1557    self.create_table(0, l.len() as c_int)
1558  }
1559
1560  /// Maps to `luaL_newlib`.
1561  pub fn new_lib(&mut self, l: &[(&str, Function)]) {
1562    self.check_version();
1563    self.new_lib_table(l);
1564    self.set_fns(l, 0)
1565  }
1566
1567  /// Maps to `luaL_argcheck`.
1568  pub fn arg_check(&mut self, cond: bool, arg: Index, extramsg: &str) {
1569    let c_str = CString::new(extramsg).unwrap();
1570    unsafe {
1571      ffi::luaL_argcheck(self.L, cond as c_int, arg, c_str.as_ptr())
1572    }
1573  }
1574
1575  /// Maps to `luaL_checklstring`.
1576  pub fn check_string(&mut self, n: Index) -> &str {
1577    let mut size = 0;
1578    let ptr = unsafe { ffi::luaL_checklstring(self.L, n, &mut size) };
1579    let slice = unsafe { slice::from_raw_parts(ptr as *const u8, size as usize) };
1580    str::from_utf8(slice).unwrap()
1581  }
1582
1583  /// Maps to `luaL_optlstring`.
1584  pub fn opt_string<'a>(&'a mut self, n: Index, default: &'a str) -> &'a str {
1585    let mut size = 0;
1586    let c_str = CString::new(default).unwrap();
1587    let ptr = unsafe { ffi::luaL_optlstring(self.L, n, c_str.as_ptr(), &mut size) };
1588    if ptr == c_str.as_ptr() {
1589      default
1590    } else {
1591      let slice = unsafe { slice::from_raw_parts(ptr as *const u8, size as usize) };
1592      str::from_utf8(slice).unwrap()
1593    }
1594  }
1595
1596  // omitted: luaL_checkint (use .check_integer)
1597  // omitted: luaL_optint (use .opt_integer)
1598  // omitted: luaL_checklong (use .check_integer)
1599  // omitted: luaL_optlong (use .opt_integer)
1600
1601  /// Maps to `luaL_typename`.
1602  pub fn typename_at(&mut self, n: Index) -> &'static str {
1603    let typeid = self.type_of(n).unwrap();
1604    self.typename_of(typeid)
1605  }
1606
1607  // luaL_dofile and luaL_dostring implemented above
1608
1609  /// Maps to `luaL_getmetatable`.
1610  pub fn get_metatable_from_registry(&mut self, tname: &str) {
1611    let c_str = CString::new(tname).unwrap();
1612    unsafe { ffi::luaL_getmetatable(self.L, c_str.as_ptr()) }
1613  }
1614
1615  // omitted: luaL_opt (undocumented function)
1616
1617  /// Maps to `luaL_loadbuffer`.
1618  pub fn load_buffer(&mut self, buff: &[u8], name: &str) -> ThreadStatus {
1619    let name_c_str = CString::new(name).unwrap();
1620    let result = unsafe { ffi::luaL_loadbuffer(self.L, buff.as_ptr() as *const _, buff.len() as size_t, name_c_str.as_ptr()) };
1621    ThreadStatus::from_c_int(result)
1622  }
1623
1624  // TODO: omitted: buffer functions
1625}
1626
1627impl Drop for State {
1628  fn drop(&mut self) {
1629    if self.owned {
1630      unsafe {
1631        let extra_ptr = ffi::lua_getextraspace(self.L) as ExtraHolder;
1632        ptr::drop_in_place(*extra_ptr);
1633        ffi::lua_close(self.L);
1634      }
1635    }
1636  }
1637}