mlua/
multi.rs

1use std::ops::{Deref, DerefMut};
2use std::os::raw::c_int;
3use std::result::Result as StdResult;
4
5use crate::error::Result;
6use crate::lua::Lua;
7use crate::util::check_stack;
8use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, MultiValue, Nil};
9
10/// Result is convertible to `MultiValue` following the common Lua idiom of returning the result
11/// on success, or in the case of an error, returning `nil` and an error message.
12impl<'lua, T: IntoLua<'lua>, E: IntoLua<'lua>> IntoLuaMulti<'lua> for StdResult<T, E> {
13    #[inline]
14    fn into_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
15        let mut result = MultiValue::with_lua_and_capacity(lua, 2);
16        match self {
17            Ok(v) => result.push_front(v.into_lua(lua)?),
18            Err(e) => {
19                result.push_front(e.into_lua(lua)?);
20                result.push_front(Nil);
21            }
22        }
23        Ok(result)
24    }
25
26    #[inline]
27    unsafe fn push_into_stack_multi(self, lua: &'lua Lua) -> Result<c_int> {
28        match self {
29            Ok(v) => v.push_into_stack(lua).map(|_| 1),
30            Err(e) => {
31                let state = lua.state();
32                check_stack(state, 3)?;
33                ffi::lua_pushnil(state);
34                e.push_into_stack(lua)?;
35                Ok(2)
36            }
37        }
38    }
39}
40
41impl<'lua, E: IntoLua<'lua>> IntoLuaMulti<'lua> for StdResult<(), E> {
42    #[inline]
43    fn into_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
44        match self {
45            Ok(_) => return Ok(MultiValue::new()),
46            Err(e) => {
47                let mut result = MultiValue::with_lua_and_capacity(lua, 2);
48                result.push_front(e.into_lua(lua)?);
49                result.push_front(Nil);
50                Ok(result)
51            }
52        }
53    }
54
55    #[inline]
56    unsafe fn push_into_stack_multi(self, lua: &'lua Lua) -> Result<c_int> {
57        match self {
58            Ok(_) => Ok(0),
59            Err(e) => {
60                let state = lua.state();
61                check_stack(state, 3)?;
62                ffi::lua_pushnil(state);
63                e.push_into_stack(lua)?;
64                Ok(2)
65            }
66        }
67    }
68}
69
70impl<'lua, T: IntoLua<'lua>> IntoLuaMulti<'lua> for T {
71    #[inline]
72    fn into_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
73        let mut v = MultiValue::with_lua_and_capacity(lua, 1);
74        v.push_front(self.into_lua(lua)?);
75        Ok(v)
76    }
77
78    #[inline]
79    unsafe fn push_into_stack_multi(self, lua: &'lua Lua) -> Result<c_int> {
80        self.push_into_stack(lua)?;
81        Ok(1)
82    }
83}
84
85impl<'lua, T: FromLua<'lua>> FromLuaMulti<'lua> for T {
86    #[inline]
87    fn from_lua_multi(mut values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self> {
88        T::from_lua(values.pop_front().unwrap_or(Nil), lua)
89    }
90
91    #[inline]
92    fn from_lua_args(
93        mut args: MultiValue<'lua>,
94        i: usize,
95        to: Option<&str>,
96        lua: &'lua Lua,
97    ) -> Result<Self> {
98        T::from_lua_arg(args.pop_front().unwrap_or(Nil), i, to, lua)
99    }
100
101    #[inline]
102    unsafe fn from_stack_multi(nvals: c_int, lua: &'lua Lua) -> Result<Self> {
103        if nvals == 0 {
104            return T::from_lua(Nil, lua);
105        }
106        T::from_stack(-nvals, lua)
107    }
108
109    #[inline]
110    unsafe fn from_stack_args(
111        nargs: c_int,
112        i: usize,
113        to: Option<&str>,
114        lua: &'lua Lua,
115    ) -> Result<Self> {
116        if nargs == 0 {
117            return T::from_lua_arg(Nil, i, to, lua);
118        }
119        T::from_stack_arg(-nargs, i, to, lua)
120    }
121}
122
123impl<'lua> IntoLuaMulti<'lua> for MultiValue<'lua> {
124    #[inline]
125    fn into_lua_multi(self, _: &'lua Lua) -> Result<MultiValue<'lua>> {
126        Ok(self)
127    }
128}
129
130impl<'lua> FromLuaMulti<'lua> for MultiValue<'lua> {
131    #[inline]
132    fn from_lua_multi(values: MultiValue<'lua>, _: &'lua Lua) -> Result<Self> {
133        Ok(values)
134    }
135}
136
137/// Wraps a variable number of `T`s.
138///
139/// Can be used to work with variadic functions more easily. Using this type as the last argument of
140/// a Rust callback will accept any number of arguments from Lua and convert them to the type `T`
141/// using [`FromLua`]. `Variadic<T>` can also be returned from a callback, returning a variable
142/// number of values to Lua.
143///
144/// The [`MultiValue`] type is equivalent to `Variadic<Value>`.
145///
146/// # Examples
147///
148/// ```
149/// # use mlua::{Lua, Result, Variadic};
150/// # fn main() -> Result<()> {
151/// # let lua = Lua::new();
152/// let add = lua.create_function(|_, vals: Variadic<f64>| -> Result<f64> {
153///     Ok(vals.iter().sum())
154/// })?;
155/// lua.globals().set("add", add)?;
156/// assert_eq!(lua.load("add(3, 2, 5)").eval::<f32>()?, 10.0);
157/// # Ok(())
158/// # }
159/// ```
160///
161/// [`FromLua`]: crate::FromLua
162/// [`MultiValue`]: crate::MultiValue
163#[derive(Debug, Clone)]
164pub struct Variadic<T>(Vec<T>);
165
166impl<T> Variadic<T> {
167    /// Creates an empty `Variadic` wrapper containing no values.
168    pub const fn new() -> Variadic<T> {
169        Variadic(Vec::new())
170    }
171}
172
173impl<T> Default for Variadic<T> {
174    fn default() -> Variadic<T> {
175        Variadic::new()
176    }
177}
178
179impl<T> FromIterator<T> for Variadic<T> {
180    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
181        Variadic(Vec::from_iter(iter))
182    }
183}
184
185impl<T> IntoIterator for Variadic<T> {
186    type Item = T;
187    type IntoIter = <Vec<T> as IntoIterator>::IntoIter;
188
189    fn into_iter(self) -> Self::IntoIter {
190        self.0.into_iter()
191    }
192}
193
194impl<T> Deref for Variadic<T> {
195    type Target = Vec<T>;
196
197    fn deref(&self) -> &Self::Target {
198        &self.0
199    }
200}
201
202impl<T> DerefMut for Variadic<T> {
203    fn deref_mut(&mut self) -> &mut Self::Target {
204        &mut self.0
205    }
206}
207
208impl<'lua, T: IntoLua<'lua>> IntoLuaMulti<'lua> for Variadic<T> {
209    #[inline]
210    fn into_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
211        let mut values = MultiValue::with_lua_and_capacity(lua, self.0.len());
212        values.refill(self.0.into_iter().map(|e| e.into_lua(lua)))?;
213        Ok(values)
214    }
215}
216
217impl<'lua, T: FromLua<'lua>> FromLuaMulti<'lua> for Variadic<T> {
218    #[inline]
219    fn from_lua_multi(mut values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self> {
220        values
221            .drain_all()
222            .map(|e| T::from_lua(e, lua))
223            .collect::<Result<Vec<T>>>()
224            .map(Variadic)
225    }
226}
227
228macro_rules! impl_tuple {
229    () => (
230        impl<'lua> IntoLuaMulti<'lua> for () {
231            #[inline]
232            fn into_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
233                Ok(MultiValue::with_lua_and_capacity(lua, 0))
234            }
235
236            #[inline]
237            unsafe fn push_into_stack_multi(self, _lua: &'lua Lua) -> Result<c_int> {
238                Ok(0)
239            }
240        }
241
242        impl<'lua> FromLuaMulti<'lua> for () {
243            #[inline]
244            fn from_lua_multi(_values: MultiValue<'lua>, _lua: &'lua Lua) -> Result<Self> {
245                Ok(())
246            }
247
248            #[inline]
249            unsafe fn from_stack_multi(nvals: c_int, lua: &'lua Lua) -> Result<Self> {
250                if nvals > 0 {
251                    ffi::lua_pop(lua.state(), nvals);
252                }
253                Ok(())
254            }
255        }
256    );
257
258    ($last:ident $($name:ident)*) => (
259        impl<'lua, $($name,)* $last> IntoLuaMulti<'lua> for ($($name,)* $last,)
260            where $($name: IntoLua<'lua>,)*
261                  $last: IntoLuaMulti<'lua>
262        {
263            #[allow(unused_mut, non_snake_case)]
264            #[inline]
265            fn into_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
266                let ($($name,)* $last,) = self;
267
268                let mut results = $last.into_lua_multi(lua)?;
269                push_reverse!(results, $($name.into_lua(lua)?,)*);
270                Ok(results)
271            }
272
273            #[allow(non_snake_case)]
274            #[inline]
275            unsafe fn push_into_stack_multi(self, lua: &'lua Lua) -> Result<c_int> {
276                let ($($name,)* $last,) = self;
277                let mut nresults = 0;
278                $(
279                    _ = $name;
280                    nresults += 1;
281                )*
282                check_stack(lua.state(), nresults + 1)?;
283                $(
284                    $name.push_into_stack(lua)?;
285                )*
286                nresults += $last.push_into_stack_multi(lua)?;
287                Ok(nresults)
288            }
289        }
290
291        impl<'lua, $($name,)* $last> FromLuaMulti<'lua> for ($($name,)* $last,)
292            where $($name: FromLua<'lua>,)*
293                  $last: FromLuaMulti<'lua>
294        {
295            #[allow(unused_mut, non_snake_case)]
296            #[inline]
297            fn from_lua_multi(mut values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self> {
298                $(let $name = FromLua::from_lua(values.pop_front().unwrap_or(Nil), lua)?;)*
299                let $last = FromLuaMulti::from_lua_multi(values, lua)?;
300                Ok(($($name,)* $last,))
301            }
302
303            #[allow(unused_mut, non_snake_case)]
304            #[inline]
305            fn from_lua_args(mut args: MultiValue<'lua>, mut i: usize, to: Option<&str>, lua: &'lua Lua) -> Result<Self> {
306                $(
307                    let $name = FromLua::from_lua_arg(args.pop_front().unwrap_or(Nil), i, to, lua)?;
308                    i += 1;
309                )*
310                let $last = FromLuaMulti::from_lua_args(args, i, to, lua)?;
311                Ok(($($name,)* $last,))
312            }
313
314            #[allow(unused_mut, non_snake_case)]
315            #[inline]
316            unsafe fn from_stack_multi(mut nvals: c_int, lua: &'lua Lua) -> Result<Self> {
317                $(
318                    let $name = if nvals > 0 {
319                        nvals -= 1;
320                        FromLua::from_stack(-(nvals + 1), lua)
321                    } else {
322                        FromLua::from_lua(Nil, lua)
323                    }?;
324                )*
325                let $last = FromLuaMulti::from_stack_multi(nvals, lua)?;
326                Ok(($($name,)* $last,))
327            }
328
329            #[allow(unused_mut, non_snake_case)]
330            #[inline]
331            unsafe fn from_stack_args(mut nargs: c_int, mut i: usize, to: Option<&str>, lua: &'lua Lua) -> Result<Self> {
332                $(
333                    let $name = if nargs > 0 {
334                        nargs -= 1;
335                        FromLua::from_stack_arg(-(nargs + 1), i, to, lua)
336                    } else {
337                        FromLua::from_lua_arg(Nil, i, to, lua)
338                    }?;
339                    i += 1;
340                )*
341                let $last = FromLuaMulti::from_stack_args(nargs, i, to, lua)?;
342                Ok(($($name,)* $last,))
343            }
344        }
345    );
346}
347
348macro_rules! push_reverse {
349    ($multi_value:expr, $first:expr, $($rest:expr,)*) => (
350        push_reverse!($multi_value, $($rest,)*);
351        $multi_value.push_front($first);
352    );
353
354    ($multi_value:expr, $first:expr) => (
355        $multi_value.push_front($first);
356    );
357
358    ($multi_value:expr,) => ();
359}
360
361impl_tuple!();
362impl_tuple!(A);
363impl_tuple!(A B);
364impl_tuple!(A B C);
365impl_tuple!(A B C D);
366impl_tuple!(A B C D E);
367impl_tuple!(A B C D E F);
368impl_tuple!(A B C D E F G);
369impl_tuple!(A B C D E F G H);
370impl_tuple!(A B C D E F G H I);
371impl_tuple!(A B C D E F G H I J);
372impl_tuple!(A B C D E F G H I J K);
373impl_tuple!(A B C D E F G H I J K L);
374impl_tuple!(A B C D E F G H I J K L M);
375impl_tuple!(A B C D E F G H I J K L M N);
376impl_tuple!(A B C D E F G H I J K L M N O);
377impl_tuple!(A B C D E F G H I J K L M N O P);