Skip to main content

mlua/
traits.rs

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