mlua/
traits.rs

1use std::os::raw::c_int;
2use std::string::String as StdString;
3use std::sync::Arc;
4
5use crate::error::{Error, Result};
6use crate::multi::MultiValue;
7use crate::private::Sealed;
8use crate::state::{Lua, RawLua};
9use crate::types::MaybeSend;
10use crate::util::{check_stack, short_type_name};
11use crate::value::Value;
12
13#[cfg(feature = "async")]
14use std::future::Future;
15
16/// Trait for types convertible to [`Value`].
17pub trait IntoLua: Sized {
18    /// Performs the conversion.
19    fn into_lua(self, lua: &Lua) -> Result<Value>;
20
21    /// Pushes the value into the Lua stack.
22    ///
23    /// # Safety
24    /// This method does not check Lua stack space.
25    #[doc(hidden)]
26    #[inline]
27    unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> {
28        lua.push_value(&self.into_lua(lua.lua())?)
29    }
30}
31
32/// Trait for types convertible from [`Value`].
33pub trait FromLua: Sized {
34    /// Performs the conversion.
35    fn from_lua(value: Value, lua: &Lua) -> Result<Self>;
36
37    /// Performs the conversion for an argument (eg. function argument).
38    ///
39    /// `i` is the argument index (position),
40    /// `to` is a function name that received the argument.
41    #[doc(hidden)]
42    #[inline]
43    fn from_lua_arg(arg: Value, i: usize, to: Option<&str>, lua: &Lua) -> Result<Self> {
44        Self::from_lua(arg, lua).map_err(|err| Error::BadArgument {
45            to: to.map(|s| s.to_string()),
46            pos: i,
47            name: None,
48            cause: Arc::new(err),
49        })
50    }
51
52    /// Performs the conversion for a value in the Lua stack at index `idx`.
53    #[doc(hidden)]
54    #[inline]
55    unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> {
56        Self::from_lua(lua.stack_value(idx, None), lua.lua())
57    }
58
59    /// Same as `from_lua_arg` but for a value in the Lua stack at index `idx`.
60    #[doc(hidden)]
61    #[inline]
62    unsafe fn from_stack_arg(idx: c_int, i: usize, to: Option<&str>, lua: &RawLua) -> Result<Self> {
63        Self::from_stack(idx, lua).map_err(|err| Error::BadArgument {
64            to: to.map(|s| s.to_string()),
65            pos: i,
66            name: None,
67            cause: Arc::new(err),
68        })
69    }
70}
71
72/// Trait for types convertible to any number of Lua values.
73///
74/// This is a generalization of [`IntoLua`], allowing any number of resulting Lua values instead of
75/// just one. Any type that implements [`IntoLua`] will automatically implement this trait.
76pub trait IntoLuaMulti: Sized {
77    /// Performs the conversion.
78    fn into_lua_multi(self, lua: &Lua) -> Result<MultiValue>;
79
80    /// Pushes the values into the Lua stack.
81    ///
82    /// Returns number of pushed values.
83    #[doc(hidden)]
84    #[inline]
85    unsafe fn push_into_stack_multi(self, lua: &RawLua) -> Result<c_int> {
86        let values = self.into_lua_multi(lua.lua())?;
87        let len: c_int = values.len().try_into().unwrap();
88        unsafe {
89            check_stack(lua.state(), len + 1)?;
90            for val in &values {
91                lua.push_value(val)?;
92            }
93        }
94        Ok(len)
95    }
96}
97
98/// Trait for types that can be created from an arbitrary number of Lua values.
99///
100/// This is a generalization of [`FromLua`], allowing an arbitrary number of Lua values to
101/// participate in the conversion. Any type that implements [`FromLua`] will automatically
102/// implement this trait.
103pub trait FromLuaMulti: Sized {
104    /// Performs the conversion.
105    ///
106    /// In case `values` contains more values than needed to perform the conversion, the excess
107    /// values should be ignored. This reflects the semantics of Lua when calling a function or
108    /// assigning values. Similarly, if not enough values are given, conversions should assume that
109    /// any missing values are nil.
110    fn from_lua_multi(values: MultiValue, lua: &Lua) -> Result<Self>;
111
112    /// Performs the conversion for a list of arguments.
113    ///
114    /// `i` is an index (position) of the first argument,
115    /// `to` is a function name that received the arguments.
116    #[doc(hidden)]
117    #[inline]
118    fn from_lua_args(args: MultiValue, i: usize, to: Option<&str>, lua: &Lua) -> Result<Self> {
119        let _ = (i, to);
120        Self::from_lua_multi(args, lua)
121    }
122
123    /// Performs the conversion for a number of values in the Lua stack.
124    #[doc(hidden)]
125    #[inline]
126    unsafe fn from_stack_multi(nvals: c_int, lua: &RawLua) -> Result<Self> {
127        let mut values = MultiValue::with_capacity(nvals as usize);
128        for idx in 0..nvals {
129            values.push_back(lua.stack_value(-nvals + idx, None));
130        }
131        Self::from_lua_multi(values, lua.lua())
132    }
133
134    /// Same as `from_lua_args` but for a number of values in the Lua stack.
135    #[doc(hidden)]
136    #[inline]
137    unsafe fn from_stack_args(nargs: c_int, i: usize, to: Option<&str>, lua: &RawLua) -> Result<Self> {
138        let _ = (i, to);
139        Self::from_stack_multi(nargs, lua)
140    }
141}
142
143/// A trait for types that can be used as Lua objects (usually table and userdata).
144pub trait ObjectLike: Sealed {
145    /// Gets the value associated to `key` from the object, assuming it has `__index` metamethod.
146    fn get<V: FromLua>(&self, key: impl IntoLua) -> Result<V>;
147
148    /// Sets the value associated to `key` in the object, assuming it has `__newindex` metamethod.
149    fn set(&self, key: impl IntoLua, value: impl IntoLua) -> Result<()>;
150
151    /// Calls the object as a function assuming it has `__call` metamethod.
152    ///
153    /// The metamethod is called with the object as its first argument, followed by the passed
154    /// arguments.
155    fn call<R>(&self, args: impl IntoLuaMulti) -> Result<R>
156    where
157        R: FromLuaMulti;
158
159    /// Asynchronously calls the object as a function assuming it has `__call` metamethod.
160    ///
161    /// The metamethod is called with the object as its first argument, followed by the passed
162    /// arguments.
163    #[cfg(feature = "async")]
164    #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
165    fn call_async<R>(&self, args: impl IntoLuaMulti) -> impl Future<Output = Result<R>>
166    where
167        R: FromLuaMulti;
168
169    /// Gets the function associated to key `name` from the object and calls it,
170    /// passing the object itself along with `args` as function arguments.
171    fn call_method<R>(&self, name: &str, args: impl IntoLuaMulti) -> Result<R>
172    where
173        R: FromLuaMulti;
174
175    /// Gets the function associated to key `name` from the object and asynchronously calls it,
176    /// passing the object itself along with `args` as function arguments.
177    ///
178    /// Requires `feature = "async"`
179    ///
180    /// This might invoke the `__index` metamethod.
181    #[cfg(feature = "async")]
182    #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
183    fn call_async_method<R>(&self, name: &str, args: impl IntoLuaMulti) -> impl Future<Output = Result<R>>
184    where
185        R: FromLuaMulti;
186
187    /// Gets the function associated to key `name` from the object and calls it,
188    /// passing `args` as function arguments.
189    ///
190    /// This might invoke the `__index` metamethod.
191    fn call_function<R>(&self, name: &str, args: impl IntoLuaMulti) -> Result<R>
192    where
193        R: FromLuaMulti;
194
195    /// Gets the function associated to key `name` from the object and asynchronously calls it,
196    /// passing `args` as function arguments.
197    ///
198    /// Requires `feature = "async"`
199    ///
200    /// This might invoke the `__index` metamethod.
201    #[cfg(feature = "async")]
202    #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
203    fn call_async_function<R>(&self, name: &str, args: impl IntoLuaMulti) -> impl Future<Output = Result<R>>
204    where
205        R: FromLuaMulti;
206
207    /// Converts the object to a string in a human-readable format.
208    ///
209    /// This might invoke the `__tostring` metamethod.
210    fn to_string(&self) -> Result<StdString>;
211}
212
213/// A trait for types that can be used as Lua functions.
214pub trait LuaNativeFn<A: FromLuaMulti> {
215    type Output: IntoLuaMulti;
216
217    fn call(&self, args: A) -> Self::Output;
218}
219
220/// A trait for types with mutable state that can be used as Lua functions.
221pub trait LuaNativeFnMut<A: FromLuaMulti> {
222    type Output: IntoLuaMulti;
223
224    fn call(&mut self, args: A) -> Self::Output;
225}
226
227/// A trait for types that returns a future and can be used as Lua functions.
228#[cfg(feature = "async")]
229pub trait LuaNativeAsyncFn<A: FromLuaMulti> {
230    type Output: IntoLuaMulti;
231
232    fn call(&self, args: A) -> impl Future<Output = Self::Output> + MaybeSend + 'static;
233}
234
235macro_rules! impl_lua_native_fn {
236    ($($A:ident),*) => {
237        impl<FN, $($A,)* R> LuaNativeFn<($($A,)*)> for FN
238        where
239            FN: Fn($($A,)*) -> R + MaybeSend + 'static,
240            ($($A,)*): FromLuaMulti,
241            R: IntoLuaMulti,
242        {
243            type Output = R;
244
245            #[allow(non_snake_case)]
246            fn call(&self, args: ($($A,)*)) -> Self::Output {
247                let ($($A,)*) = args;
248                self($($A,)*)
249            }
250        }
251
252        impl<FN, $($A,)* R> LuaNativeFnMut<($($A,)*)> for FN
253        where
254            FN: FnMut($($A,)*) -> R + MaybeSend + 'static,
255            ($($A,)*): FromLuaMulti,
256            R: IntoLuaMulti,
257        {
258            type Output = R;
259
260            #[allow(non_snake_case)]
261            fn call(&mut self, args: ($($A,)*)) -> Self::Output {
262                let ($($A,)*) = args;
263                self($($A,)*)
264            }
265        }
266
267        #[cfg(feature = "async")]
268        impl<FN, $($A,)* Fut, R> LuaNativeAsyncFn<($($A,)*)> for FN
269        where
270            FN: Fn($($A,)*) -> Fut + MaybeSend + 'static,
271            ($($A,)*): FromLuaMulti,
272            Fut: Future<Output = R> + MaybeSend + 'static,
273            R: IntoLuaMulti,
274        {
275            type Output = R;
276
277            #[allow(non_snake_case)]
278            fn call(&self, args: ($($A,)*)) -> impl Future<Output = Self::Output> + MaybeSend + 'static {
279                let ($($A,)*) = args;
280                self($($A,)*)
281            }
282        }
283    };
284}
285
286impl_lua_native_fn!();
287impl_lua_native_fn!(A);
288impl_lua_native_fn!(A, B);
289impl_lua_native_fn!(A, B, C);
290impl_lua_native_fn!(A, B, C, D);
291impl_lua_native_fn!(A, B, C, D, E);
292impl_lua_native_fn!(A, B, C, D, E, F);
293impl_lua_native_fn!(A, B, C, D, E, F, G);
294impl_lua_native_fn!(A, B, C, D, E, F, G, H);
295impl_lua_native_fn!(A, B, C, D, E, F, G, H, I);
296impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J);
297impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K);
298impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L);
299impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L, M);
300impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
301impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
302impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
303
304pub(crate) trait ShortTypeName {
305    #[inline(always)]
306    fn type_name() -> StdString {
307        short_type_name::<Self>()
308    }
309}
310
311impl<T> ShortTypeName for T {}