factorio_mlua/
multi.rs

1#![allow(clippy::wrong_self_convention)]
2
3use std::iter::FromIterator;
4use std::ops::{Deref, DerefMut};
5use std::result::Result as StdResult;
6
7use crate::error::Result;
8use crate::lua::Lua;
9use crate::value::{FromLua, FromLuaMulti, MultiValue, Nil, ToLua, ToLuaMulti};
10
11/// Result is convertible to `MultiValue` following the common Lua idiom of returning the result
12/// on success, or in the case of an error, returning `nil` and an error message.
13impl<'lua, T: ToLua<'lua>, E: ToLua<'lua>> ToLuaMulti<'lua> for StdResult<T, E> {
14    #[inline]
15    fn to_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
16        let mut result = MultiValue::new_or_cached(lua);
17        match self {
18            Ok(v) => result.push_front(v.to_lua(lua)?),
19            Err(e) => {
20                result.push_front(e.to_lua(lua)?);
21                result.push_front(Nil);
22            }
23        }
24        Ok(result)
25    }
26}
27
28impl<'lua, T: ToLua<'lua>> ToLuaMulti<'lua> for T {
29    #[inline]
30    fn to_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
31        let mut v = MultiValue::new_or_cached(lua);
32        v.push_front(self.to_lua(lua)?);
33        Ok(v)
34    }
35}
36
37impl<'lua, T: FromLua<'lua>> FromLuaMulti<'lua> for T {
38    #[inline]
39    fn from_lua_multi(mut values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self> {
40        let res = T::from_lua(values.pop_front().unwrap_or(Nil), lua);
41        lua.cache_multivalue(values);
42        res
43    }
44}
45
46impl<'lua> ToLuaMulti<'lua> for MultiValue<'lua> {
47    #[inline]
48    fn to_lua_multi(self, _: &'lua Lua) -> Result<MultiValue<'lua>> {
49        Ok(self)
50    }
51}
52
53impl<'lua> FromLuaMulti<'lua> for MultiValue<'lua> {
54    #[inline]
55    fn from_lua_multi(values: MultiValue<'lua>, _: &'lua Lua) -> Result<Self> {
56        Ok(values)
57    }
58}
59
60/// Wraps a variable number of `T`s.
61///
62/// Can be used to work with variadic functions more easily. Using this type as the last argument of
63/// a Rust callback will accept any number of arguments from Lua and convert them to the type `T`
64/// using [`FromLua`]. `Variadic<T>` can also be returned from a callback, returning a variable
65/// number of values to Lua.
66///
67/// The [`MultiValue`] type is equivalent to `Variadic<Value>`.
68///
69/// # Examples
70///
71/// ```
72/// # use mlua::{Lua, Result, Variadic};
73/// # fn main() -> Result<()> {
74/// # let lua = Lua::new();
75/// let add = lua.create_function(|_, vals: Variadic<f64>| -> Result<f64> {
76///     Ok(vals.iter().sum())
77/// })?;
78/// lua.globals().set("add", add)?;
79/// assert_eq!(lua.load("add(3, 2, 5)").eval::<f32>()?, 10.0);
80/// # Ok(())
81/// # }
82/// ```
83///
84/// [`FromLua`]: crate::FromLua
85/// [`MultiValue`]: crate::MultiValue
86#[derive(Debug, Clone)]
87pub struct Variadic<T>(Vec<T>);
88
89impl<T> Variadic<T> {
90    /// Creates an empty `Variadic` wrapper containing no values.
91    pub const fn new() -> Variadic<T> {
92        Variadic(Vec::new())
93    }
94}
95
96impl<T> Default for Variadic<T> {
97    fn default() -> Variadic<T> {
98        Variadic::new()
99    }
100}
101
102impl<T> FromIterator<T> for Variadic<T> {
103    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
104        Variadic(Vec::from_iter(iter))
105    }
106}
107
108impl<T> IntoIterator for Variadic<T> {
109    type Item = T;
110    type IntoIter = <Vec<T> as IntoIterator>::IntoIter;
111
112    fn into_iter(self) -> Self::IntoIter {
113        self.0.into_iter()
114    }
115}
116
117impl<T> Deref for Variadic<T> {
118    type Target = Vec<T>;
119
120    fn deref(&self) -> &Self::Target {
121        &self.0
122    }
123}
124
125impl<T> DerefMut for Variadic<T> {
126    fn deref_mut(&mut self) -> &mut Self::Target {
127        &mut self.0
128    }
129}
130
131impl<'lua, T: ToLua<'lua>> ToLuaMulti<'lua> for Variadic<T> {
132    #[inline]
133    fn to_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
134        let mut values = MultiValue::new_or_cached(lua);
135        values.refill(self.0.into_iter().map(|e| e.to_lua(lua)))?;
136        Ok(values)
137    }
138}
139
140impl<'lua, T: FromLua<'lua>> FromLuaMulti<'lua> for Variadic<T> {
141    #[inline]
142    fn from_lua_multi(mut values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self> {
143        let res = values
144            .drain_all()
145            .map(|e| T::from_lua(e, lua))
146            .collect::<Result<Vec<T>>>()
147            .map(Variadic);
148        lua.cache_multivalue(values);
149        res
150    }
151}
152
153macro_rules! impl_tuple {
154    () => (
155        impl<'lua> ToLuaMulti<'lua> for () {
156            #[inline]
157            fn to_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
158                Ok(MultiValue::new_or_cached(lua))
159            }
160        }
161
162        impl<'lua> FromLuaMulti<'lua> for () {
163            #[inline]
164            fn from_lua_multi(values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self> {
165                lua.cache_multivalue(values);
166                Ok(())
167            }
168        }
169    );
170
171    ($last:ident $($name:ident)*) => (
172        impl<'lua, $($name,)* $last> ToLuaMulti<'lua> for ($($name,)* $last,)
173            where $($name: ToLua<'lua>,)*
174                  $last: ToLuaMulti<'lua>
175        {
176            #[allow(unused_mut)]
177            #[allow(non_snake_case)]
178            #[inline]
179            fn to_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
180                let ($($name,)* $last,) = self;
181
182                let mut results = $last.to_lua_multi(lua)?;
183                push_reverse!(results, $($name.to_lua(lua)?,)*);
184                Ok(results)
185            }
186        }
187
188        impl<'lua, $($name,)* $last> FromLuaMulti<'lua> for ($($name,)* $last,)
189            where $($name: FromLua<'lua>,)*
190                  $last: FromLuaMulti<'lua>
191        {
192            #[allow(unused_mut)]
193            #[allow(non_snake_case)]
194            #[inline]
195            fn from_lua_multi(mut values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self> {
196                $(let $name = values.pop_front().unwrap_or(Nil);)*
197                let $last = FromLuaMulti::from_lua_multi(values, lua)?;
198                Ok(($(FromLua::from_lua($name, lua)?,)* $last,))
199            }
200        }
201    );
202}
203
204macro_rules! push_reverse {
205    ($multi_value:expr, $first:expr, $($rest:expr,)*) => (
206        push_reverse!($multi_value, $($rest,)*);
207        $multi_value.push_front($first);
208    );
209
210    ($multi_value:expr, $first:expr) => (
211        $multi_value.push_front($first);
212    );
213
214    ($multi_value:expr,) => ();
215}
216
217impl_tuple!();
218impl_tuple!(A);
219impl_tuple!(A B);
220impl_tuple!(A B C);
221impl_tuple!(A B C D);
222impl_tuple!(A B C D E);
223impl_tuple!(A B C D E F);
224impl_tuple!(A B C D E F G);
225impl_tuple!(A B C D E F G H);
226impl_tuple!(A B C D E F G H I);
227impl_tuple!(A B C D E F G H I J);
228impl_tuple!(A B C D E F G H I J K);
229impl_tuple!(A B C D E F G H I J K L);
230impl_tuple!(A B C D E F G H I J K L M);
231impl_tuple!(A B C D E F G H I J K L M N);
232impl_tuple!(A B C D E F G H I J K L M N O);
233impl_tuple!(A B C D E F G H I J K L M N O P);