1use lua::{Index, ToLua, FromLua, State, MULTRET};
2use types::{LuaStackable, LuaGeneric};
3use context::Context;
4use error;
5
6pub struct LuaFunction {
27 index: Index
28}
29
30fn get_callback_index(val: &Option<&LuaFunction>) -> Index {
31 match *val {
32 Some(val) => val.get_pos(),
33 None => 0
34 }
35}
36
37impl LuaFunction {
38 pub fn new(i: Index) -> LuaFunction {
40 LuaFunction {
41 index: i
42 }
43 }
44
45 pub fn pcall(&self, context: &mut Context, args: &[&ToLua], errfunc: Option<&LuaFunction>,
57 nresults: i32) -> error::Result<Vec<LuaGeneric>> {
58 let top_prev = context.get_state().get_top();
59 context.get_state().push_value(self.get_pos());
60 for arg in args {
61 arg.to_lua(context.get_state());
62 }
63 let threadstatus = context.get_state().pcall(
64 args.len() as i32, nresults, get_callback_index(&errfunc));
65 match error::get_status_from_threadstatus(threadstatus) {
66 Err(status) => {
67 error::new_luaresult_err(status, error::pop_error_from_state(context.get_state()))
68 },
69 Ok(_) => {
70 let top_post = context.get_state().get_top();
71 error::new_luaresult_ok((top_prev..top_post)
72 .map(|i| LuaGeneric::new(i+1))
73 .collect())
74 }
75 }
76 }
77
78 pub fn pcall_multiret(&self, context: &mut Context, args: &[&ToLua],
80 errfunc: Option<&LuaFunction>) -> error::Result<Vec<LuaGeneric>> {
81 self.pcall(context, args, errfunc, MULTRET)
82 }
83
84 pub fn pcall_singleret(&self, context: &mut Context, args: &[&ToLua],
86 errfunc: Option<&LuaFunction>) -> error::Result<Option<LuaGeneric>> {
87 self.pcall(context, args, errfunc, 1)
88 .map(|mut v| {
89 match v.len() {
90 0 => None,
91 _ => Some(v.swap_remove(0))
92 }
93 })
94 }
95
96 pub fn pcall_noret(&self, context: &mut Context, args: &[&ToLua],
98 errfunc: Option<&LuaFunction>) -> error::Result<()> {
99 self.pcall(context, args, errfunc, 0)
100 .map(|_|())
101 }
102
103 pub fn call(&self, context: &mut Context, args: &[&ToLua], nresults: i32) -> Vec<LuaGeneric> {
111 let top_prev = context.get_state().get_top();
112 context.get_state().push_value(self.get_pos());
113 for arg in args {
114 arg.to_lua(context.get_state());
115 }
116 context.get_state().call(args.len() as i32, nresults);
117 let top_post = context.get_state().get_top();
118 (top_prev..top_post)
119 .map(|i| LuaGeneric::new(i+1))
120 .collect()
121 }
122
123 pub fn call_singleret(&self, context: &mut Context, args: &[&ToLua]) -> Option<LuaGeneric> {
125 let mut result = self.call(context, args, 1);
126 match result.len() {
127 0 => None,
128 _ => Some(result.swap_remove(0))
129 }
130 }
131
132 pub fn call_multiret(&self, context: &mut Context, args: &[&ToLua]) -> Vec<LuaGeneric> {
134 self.call(context, args, MULTRET)
135 }
136
137 pub fn call_noret(&self, context: &mut Context, args: &[&ToLua]) {
139 self.call(context, args, 0);
140 }
141}
142
143impl LuaStackable for LuaFunction {
144 fn get_pos(&self) -> Index {
145 self.index
146 }
147}
148
149impl ToLua for LuaFunction {
150 fn to_lua(&self, state: &mut State) {
151 state.push_value(self.get_pos());
152 }
153}
154
155impl FromLua for LuaFunction {
156 fn from_lua(state: &mut State, index: Index) -> Option<LuaFunction> {
157 if state.is_fn(index) {
158 Some(LuaFunction::new(index))
159 } else {
160 None
161 }
162 }
163}