Skip to main content

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, WeakLua};
9use crate::types::MaybeSend;
10use crate::util::{check_stack, parse_lookup_path, short_type_name};
11use crate::value::Value;
12
13#[cfg(feature = "async")]
14use {crate::function::AsyncCallFuture, 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) -> AsyncCallFuture<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    /// This might invoke the `__index` metamethod.
179    #[cfg(feature = "async")]
180    #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
181    fn call_async_method<R>(&self, name: &str, args: impl IntoLuaMulti) -> AsyncCallFuture<R>
182    where
183        R: FromLuaMulti;
184
185    /// Gets the function associated to key `name` from the object and calls it,
186    /// passing `args` as function arguments.
187    ///
188    /// This might invoke the `__index` metamethod.
189    fn call_function<R>(&self, name: &str, args: impl IntoLuaMulti) -> Result<R>
190    where
191        R: FromLuaMulti;
192
193    /// Gets the function associated to key `name` from the object and asynchronously calls it,
194    /// passing `args` as function arguments.
195    ///
196    /// This might invoke the `__index` metamethod.
197    #[cfg(feature = "async")]
198    #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
199    fn call_async_function<R>(&self, name: &str, args: impl IntoLuaMulti) -> AsyncCallFuture<R>
200    where
201        R: FromLuaMulti;
202
203    /// Look up a value by a path of keys.
204    ///
205    /// The syntax is similar to accessing nested tables in Lua, with additional support for
206    /// `?` operator to perform safe navigation.
207    ///
208    /// For example, the path `a[1].c` is equivalent to `table.a[1].c` in Lua.
209    /// With `?` operator, `a[1]?.c` is equivalent to `table.a[1] and table.a[1].c or nil` in Lua.
210    ///
211    /// Bracket notation rules:
212    /// - `[123]` - integer keys
213    /// - `["string key"]` or `['string key']` - string keys (must be quoted)
214    /// - String keys support escape sequences: `\"`, `\'`, `\\`
215    fn get_path<V: FromLua>(&self, path: &str) -> Result<V> {
216        let mut current = self.to_value();
217        for (key, safe_nil) in parse_lookup_path(path)? {
218            current = match current {
219                Value::Table(table) => table.get::<Value>(key),
220                Value::UserData(ud) => ud.get::<Value>(key),
221                _ => {
222                    let type_name = current.type_name();
223                    let err = format!("attempt to index a {type_name} value with key '{key}'");
224                    Err(Error::runtime(err))
225                }
226            }?;
227            if safe_nil && (current == Value::Nil || current == Value::NULL) {
228                break;
229            }
230        }
231
232        let lua = self.weak_lua().lock();
233        V::from_lua(current, lua.lua())
234    }
235
236    /// Converts the object to a string in a human-readable format.
237    ///
238    /// This might invoke the `__tostring` metamethod.
239    fn to_string(&self) -> Result<StdString>;
240
241    /// Converts the object to a Lua value.
242    fn to_value(&self) -> Value;
243
244    /// Gets a reference to the associated Lua state.
245    #[doc(hidden)]
246    fn weak_lua(&self) -> &WeakLua;
247}
248
249/// A trait for types that can be used as Lua functions.
250pub trait LuaNativeFn<A: FromLuaMulti> {
251    type Output: IntoLuaMulti;
252
253    fn call(&self, args: A) -> Self::Output;
254}
255
256/// A trait for types with mutable state that can be used as Lua functions.
257pub trait LuaNativeFnMut<A: FromLuaMulti> {
258    type Output: IntoLuaMulti;
259
260    fn call(&mut self, args: A) -> Self::Output;
261}
262
263/// A trait for types that returns a future and can be used as Lua functions.
264#[cfg(feature = "async")]
265pub trait LuaNativeAsyncFn<A: FromLuaMulti> {
266    type Output: IntoLuaMulti;
267
268    fn call(&self, args: A) -> impl Future<Output = Self::Output> + MaybeSend + 'static;
269}
270
271macro_rules! impl_lua_native_fn {
272    ($($A:ident),*) => {
273        impl<FN, $($A,)* R> LuaNativeFn<($($A,)*)> for FN
274        where
275            FN: Fn($($A,)*) -> R + MaybeSend + 'static,
276            ($($A,)*): FromLuaMulti,
277            R: IntoLuaMulti,
278        {
279            type Output = R;
280
281            #[allow(non_snake_case)]
282            fn call(&self, args: ($($A,)*)) -> Self::Output {
283                let ($($A,)*) = args;
284                self($($A,)*)
285            }
286        }
287
288        impl<FN, $($A,)* R> LuaNativeFnMut<($($A,)*)> for FN
289        where
290            FN: FnMut($($A,)*) -> R + MaybeSend + 'static,
291            ($($A,)*): FromLuaMulti,
292            R: IntoLuaMulti,
293        {
294            type Output = R;
295
296            #[allow(non_snake_case)]
297            fn call(&mut self, args: ($($A,)*)) -> Self::Output {
298                let ($($A,)*) = args;
299                self($($A,)*)
300            }
301        }
302
303        #[cfg(feature = "async")]
304        impl<FN, $($A,)* Fut, R> LuaNativeAsyncFn<($($A,)*)> for FN
305        where
306            FN: Fn($($A,)*) -> Fut + MaybeSend + 'static,
307            ($($A,)*): FromLuaMulti,
308            Fut: Future<Output = R> + MaybeSend + 'static,
309            R: IntoLuaMulti,
310        {
311            type Output = R;
312
313            #[allow(non_snake_case)]
314            fn call(&self, args: ($($A,)*)) -> impl Future<Output = Self::Output> + MaybeSend + 'static {
315                let ($($A,)*) = args;
316                self($($A,)*)
317            }
318        }
319    };
320}
321
322impl_lua_native_fn!();
323impl_lua_native_fn!(A);
324impl_lua_native_fn!(A, B);
325impl_lua_native_fn!(A, B, C);
326impl_lua_native_fn!(A, B, C, D);
327impl_lua_native_fn!(A, B, C, D, E);
328impl_lua_native_fn!(A, B, C, D, E, F);
329impl_lua_native_fn!(A, B, C, D, E, F, G);
330impl_lua_native_fn!(A, B, C, D, E, F, G, H);
331impl_lua_native_fn!(A, B, C, D, E, F, G, H, I);
332impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J);
333impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K);
334impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L);
335impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L, M);
336impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
337impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
338impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
339
340pub(crate) trait ShortTypeName {
341    #[inline(always)]
342    fn type_name() -> StdString {
343        short_type_name::<Self>()
344    }
345}
346
347impl<T> ShortTypeName for T {}