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 {}