factorio_mlua/
value.rs

1use std::iter::{self, FromIterator};
2use std::os::raw::c_void;
3use std::{ptr, slice, str, vec};
4
5#[cfg(feature = "serialize")]
6use {
7    serde::ser::{self, Serialize, Serializer},
8    std::convert::TryInto,
9    std::result::Result as StdResult,
10};
11
12use crate::error::{Error, Result};
13use crate::ffi;
14use crate::function::Function;
15use crate::lua::Lua;
16use crate::string::String;
17use crate::table::Table;
18use crate::thread::Thread;
19use crate::types::{Integer, LightUserData, Number};
20use crate::userdata::AnyUserData;
21
22/// A dynamically typed Lua value. The `String`, `Table`, `Function`, `Thread`, and `UserData`
23/// variants contain handle types into the internal Lua state. It is a logic error to mix handle
24/// types between separate `Lua` instances, and doing so will result in a panic.
25#[derive(Debug, Clone)]
26pub enum Value<'lua> {
27    /// The Lua value `nil`.
28    Nil,
29    /// The Lua value `true` or `false`.
30    Boolean(bool),
31    /// A "light userdata" object, equivalent to a raw pointer.
32    LightUserData(LightUserData),
33    /// An integer number.
34    ///
35    /// Any Lua number convertible to a `Integer` will be represented as this variant.
36    Integer(Integer),
37    /// A floating point number.
38    Number(Number),
39    /// A Luau vector.
40    #[cfg(any(feature = "luau", doc))]
41    #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
42    Vector(f32, f32, f32),
43    /// An interned string, managed by Lua.
44    ///
45    /// Unlike Rust strings, Lua strings may not be valid UTF-8.
46    String(String<'lua>),
47    /// Reference to a Lua table.
48    Table(Table<'lua>),
49    /// Reference to a Lua function (or closure).
50    Function(Function<'lua>),
51    /// Reference to a Lua thread (or coroutine).
52    Thread(Thread<'lua>),
53    /// Reference to a userdata object that holds a custom type which implements `UserData`.
54    /// Special builtin userdata types will be represented as other `Value` variants.
55    UserData(AnyUserData<'lua>),
56    /// `Error` is a special builtin userdata type. When received from Lua it is implicitly cloned.
57    Error(Error),
58}
59
60pub use self::Value::Nil;
61
62impl<'lua> Value<'lua> {
63    pub const fn type_name(&self) -> &'static str {
64        match *self {
65            Value::Nil => "nil",
66            Value::Boolean(_) => "boolean",
67            Value::LightUserData(_) => "lightuserdata",
68            Value::Integer(_) => "integer",
69            Value::Number(_) => "number",
70            #[cfg(feature = "luau")]
71            Value::Vector(_, _, _) => "vector",
72            Value::String(_) => "string",
73            Value::Table(_) => "table",
74            Value::Function(_) => "function",
75            Value::Thread(_) => "thread",
76            Value::UserData(_) => "userdata",
77            Value::Error(_) => "error",
78        }
79    }
80
81    /// Compares two values for equality.
82    ///
83    /// Equality comparisons do not convert strings to numbers or vice versa.
84    /// Tables, Functions, Threads, and Userdata are compared by reference:
85    /// two objects are considered equal only if they are the same object.
86    ///
87    /// If Tables or Userdata have `__eq` metamethod then mlua will try to invoke it.
88    /// The first value is checked first. If that value does not define a metamethod
89    /// for `__eq`, then mlua will check the second value.
90    /// Then mlua calls the metamethod with the two values as arguments, if found.
91    pub fn equals<T: AsRef<Self>>(&self, other: T) -> Result<bool> {
92        match (self, other.as_ref()) {
93            (Value::Table(a), Value::Table(b)) => a.equals(b),
94            (Value::UserData(a), Value::UserData(b)) => a.equals(b),
95            _ => Ok(self == other.as_ref()),
96        }
97    }
98
99    /// Converts the value to a generic C pointer.
100    ///
101    /// The value can be a userdata, a table, a thread, a string, or a function; otherwise it returns NULL.
102    /// Different objects will give different pointers.
103    /// There is no way to convert the pointer back to its original value.
104    ///
105    /// Typically this function is used only for hashing and debug information.
106    pub fn to_pointer(&self) -> *const c_void {
107        unsafe {
108            match self {
109                Value::LightUserData(ud) => ud.0,
110                Value::String(String(v))
111                | Value::Table(Table(v))
112                | Value::Function(Function(v))
113                | Value::Thread(Thread(v))
114                | Value::UserData(AnyUserData(v)) => v
115                    .lua
116                    .ref_thread_exec(|refthr| ffi::lua_topointer(refthr, v.index)),
117                _ => ptr::null(),
118            }
119        }
120    }
121}
122
123impl<'lua> PartialEq for Value<'lua> {
124    fn eq(&self, other: &Self) -> bool {
125        match (self, other) {
126            (Value::Nil, Value::Nil) => true,
127            (Value::Boolean(a), Value::Boolean(b)) => a == b,
128            (Value::LightUserData(a), Value::LightUserData(b)) => a == b,
129            (Value::Integer(a), Value::Integer(b)) => *a == *b,
130            (Value::Integer(a), Value::Number(b)) => *a as Number == *b,
131            (Value::Number(a), Value::Integer(b)) => *a == *b as Number,
132            (Value::Number(a), Value::Number(b)) => *a == *b,
133            #[cfg(feature = "luau")]
134            (Value::Vector(x1, y1, z1), Value::Vector(x2, y2, z2)) => (x1, y1, z1) == (x2, y2, z2),
135            (Value::String(a), Value::String(b)) => a == b,
136            (Value::Table(a), Value::Table(b)) => a == b,
137            (Value::Function(a), Value::Function(b)) => a == b,
138            (Value::Thread(a), Value::Thread(b)) => a == b,
139            (Value::UserData(a), Value::UserData(b)) => a == b,
140            _ => false,
141        }
142    }
143}
144
145impl<'lua> AsRef<Value<'lua>> for Value<'lua> {
146    #[inline]
147    fn as_ref(&self) -> &Self {
148        self
149    }
150}
151
152#[cfg(feature = "serialize")]
153impl<'lua> Serialize for Value<'lua> {
154    fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
155    where
156        S: Serializer,
157    {
158        match self {
159            Value::Nil => serializer.serialize_unit(),
160            Value::Boolean(b) => serializer.serialize_bool(*b),
161            #[allow(clippy::useless_conversion)]
162            Value::Integer(i) => serializer
163                .serialize_i64((*i).try_into().expect("cannot convert lua_Integer to i64")),
164            #[allow(clippy::useless_conversion)]
165            Value::Number(n) => serializer.serialize_f64(*n),
166            #[cfg(feature = "luau")]
167            Value::Vector(x, y, z) => (x, y, z).serialize(serializer),
168            Value::String(s) => s.serialize(serializer),
169            Value::Table(t) => t.serialize(serializer),
170            Value::UserData(ud) => ud.serialize(serializer),
171            Value::LightUserData(ud) if ud.0.is_null() => serializer.serialize_none(),
172            Value::Error(_) | Value::LightUserData(_) | Value::Function(_) | Value::Thread(_) => {
173                let msg = format!("cannot serialize <{}>", self.type_name());
174                Err(ser::Error::custom(msg))
175            }
176        }
177    }
178}
179
180/// Trait for types convertible to `Value`.
181pub trait ToLua<'lua> {
182    /// Performs the conversion.
183    fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>>;
184}
185
186/// Trait for types convertible from `Value`.
187pub trait FromLua<'lua>: Sized {
188    /// Performs the conversion.
189    fn from_lua(lua_value: Value<'lua>, lua: &'lua Lua) -> Result<Self>;
190}
191
192/// Multiple Lua values used for both argument passing and also for multiple return values.
193#[derive(Debug, Clone)]
194pub struct MultiValue<'lua>(Vec<Value<'lua>>);
195
196impl<'lua> MultiValue<'lua> {
197    /// Creates an empty `MultiValue` containing no values.
198    #[inline]
199    pub const fn new() -> MultiValue<'lua> {
200        MultiValue(Vec::new())
201    }
202
203    /// Similar to `new` but can return previously used container with allocated capacity.
204    #[inline]
205    pub(crate) fn new_or_cached(lua: &'lua Lua) -> MultiValue<'lua> {
206        lua.new_or_cached_multivalue()
207    }
208}
209
210impl<'lua> Default for MultiValue<'lua> {
211    #[inline]
212    fn default() -> MultiValue<'lua> {
213        MultiValue::new()
214    }
215}
216
217impl<'lua> FromIterator<Value<'lua>> for MultiValue<'lua> {
218    #[inline]
219    fn from_iter<I: IntoIterator<Item = Value<'lua>>>(iter: I) -> Self {
220        MultiValue::from_vec(Vec::from_iter(iter))
221    }
222}
223
224impl<'lua> IntoIterator for MultiValue<'lua> {
225    type Item = Value<'lua>;
226    type IntoIter = iter::Rev<vec::IntoIter<Value<'lua>>>;
227
228    #[inline]
229    fn into_iter(self) -> Self::IntoIter {
230        self.0.into_iter().rev()
231    }
232}
233
234impl<'a, 'lua> IntoIterator for &'a MultiValue<'lua> {
235    type Item = &'a Value<'lua>;
236    type IntoIter = iter::Rev<slice::Iter<'a, Value<'lua>>>;
237
238    #[inline]
239    fn into_iter(self) -> Self::IntoIter {
240        (&self.0).iter().rev()
241    }
242}
243
244impl<'lua> MultiValue<'lua> {
245    #[inline]
246    pub fn from_vec(mut v: Vec<Value<'lua>>) -> MultiValue<'lua> {
247        v.reverse();
248        MultiValue(v)
249    }
250
251    #[inline]
252    pub fn into_vec(self) -> Vec<Value<'lua>> {
253        let mut v = self.0;
254        v.reverse();
255        v
256    }
257
258    #[inline]
259    pub(crate) fn reserve(&mut self, size: usize) {
260        self.0.reserve(size);
261    }
262
263    #[inline]
264    pub(crate) fn push_front(&mut self, value: Value<'lua>) {
265        self.0.push(value);
266    }
267
268    #[inline]
269    pub(crate) fn pop_front(&mut self) -> Option<Value<'lua>> {
270        self.0.pop()
271    }
272
273    #[inline]
274    pub fn clear(&mut self) {
275        self.0.clear();
276    }
277
278    #[inline]
279    pub fn len(&self) -> usize {
280        self.0.len()
281    }
282
283    #[inline]
284    pub fn is_empty(&self) -> bool {
285        self.0.is_empty()
286    }
287
288    #[inline]
289    pub fn iter(&self) -> iter::Rev<slice::Iter<Value<'lua>>> {
290        self.0.iter().rev()
291    }
292
293    #[inline]
294    pub(crate) fn drain_all(&mut self) -> iter::Rev<vec::Drain<Value<'lua>>> {
295        self.0.drain(..).rev()
296    }
297
298    #[inline]
299    pub(crate) fn refill(
300        &mut self,
301        iter: impl IntoIterator<Item = Result<Value<'lua>>>,
302    ) -> Result<()> {
303        self.0.clear();
304        for value in iter {
305            self.0.push(value?);
306        }
307        self.0.reverse();
308        Ok(())
309    }
310}
311
312/// Trait for types convertible to any number of Lua values.
313///
314/// This is a generalization of `ToLua`, allowing any number of resulting Lua values instead of just
315/// one. Any type that implements `ToLua` will automatically implement this trait.
316pub trait ToLuaMulti<'lua> {
317    /// Performs the conversion.
318    fn to_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>>;
319}
320
321/// Trait for types that can be created from an arbitrary number of Lua values.
322///
323/// This is a generalization of `FromLua`, allowing an arbitrary number of Lua values to participate
324/// in the conversion. Any type that implements `FromLua` will automatically implement this trait.
325pub trait FromLuaMulti<'lua>: Sized {
326    /// Performs the conversion.
327    ///
328    /// In case `values` contains more values than needed to perform the conversion, the excess
329    /// values should be ignored. This reflects the semantics of Lua when calling a function or
330    /// assigning values. Similarly, if not enough values are given, conversions should assume that
331    /// any missing values are nil.
332    fn from_lua_multi(values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self>;
333}