Skip to main content

mlua/
traits.rs

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