1use std::borrow::Cow;
2use std::ffi::c_int;
3use std::fmt;
4use std::mem::ManuallyDrop;
5
6use lua::{ffi::*, Poppable, Pushable};
7use luajit_bindings as lua;
8
9use crate::{
10 Array,
11 Boolean,
12 Dictionary,
13 Float,
14 Function,
15 Integer,
16 LuaRef,
17 NonOwning,
18};
19
20#[repr(C)]
26pub struct Object {
27 ty: ObjectKind,
28 data: ObjectData,
29}
30
31#[derive(Copy, Clone, Debug, Eq, PartialEq)]
35#[repr(C)]
36pub enum ObjectKind {
37 Nil = 0,
38 Boolean,
39 Integer,
40 Float,
41 String,
42 Array,
43 Dictionary,
44 LuaRef,
45}
46
47impl ObjectKind {
48 pub fn as_static(&self) -> &'static str {
49 match self {
50 Self::Nil => "nil",
51 Self::Boolean => "boolean",
52 Self::Integer => "integer",
53 Self::Float => "float",
54 Self::String => "string",
55 Self::Array => "array",
56 Self::Dictionary => "dictionary",
57 Self::LuaRef => "luaref",
58 }
59 }
60}
61
62#[repr(C)]
64union ObjectData {
65 boolean: Boolean,
66 integer: Integer,
67 float: Float,
68 string: ManuallyDrop<crate::String>,
69 array: ManuallyDrop<Array>,
70 dictionary: ManuallyDrop<Dictionary>,
71 luaref: LuaRef,
72}
73
74impl Default for Object {
75 fn default() -> Object {
76 Object::nil()
77 }
78}
79
80impl fmt::Debug for Object {
81 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
82 fmt::Display::fmt(self, f)
83 }
84}
85
86impl fmt::Display for Object {
87 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
88 use ObjectKind::*;
89 match self.ty {
90 Nil => f.write_str("()"),
91 Boolean => write!(f, "{}", unsafe { self.data.boolean }),
92 Integer => write!(f, "{}", unsafe { self.data.integer }),
93 Float => write!(f, "{}", unsafe { self.data.float }),
94 String => write!(f, "\"{}\"", unsafe { &*self.data.string }),
95 Array => write!(f, "{}", unsafe { &*self.data.array }),
96 Dictionary => write!(f, "{}", unsafe { &*self.data.dictionary }),
97 LuaRef => write!(f, "LuaRef({})", unsafe { self.data.luaref }),
98 }
99 }
100}
101
102impl Object {
103 #[inline]
105 pub fn nil() -> Self {
106 Self { ty: ObjectKind::Nil, data: ObjectData { integer: 0 } }
107 }
108
109 #[inline]
110 pub fn is_nil(&self) -> bool {
111 matches!(self.ty, ObjectKind::Nil)
112 }
113
114 #[inline]
115 pub fn is_some(&self) -> bool {
116 !self.is_nil()
117 }
118
119 #[inline(always)]
120 pub fn from_luaref(luaref: LuaRef) -> Self {
121 Self { ty: ObjectKind::LuaRef, data: ObjectData { luaref } }
122 }
123
124 #[inline]
125 pub fn kind(&self) -> ObjectKind {
126 self.ty
127 }
128
129 #[inline]
131 #[doc(hidden)]
132 pub fn non_owning(&self) -> NonOwning<'_, Self> {
133 unsafe { NonOwning::new(std::ptr::read(self)) }
135 }
136
137 #[inline(always)]
138 pub unsafe fn as_boolean_unchecked(&self) -> bool {
139 self.data.boolean
140 }
141
142 #[inline(always)]
143 pub unsafe fn as_integer_unchecked(&self) -> Integer {
144 self.data.integer
145 }
146
147 #[inline(always)]
148 pub unsafe fn as_float_unchecked(&self) -> Float {
149 self.data.float
150 }
151
152 #[inline(always)]
153 pub unsafe fn as_luaref_unchecked(&self) -> LuaRef {
154 self.data.luaref
155 }
156
157 pub unsafe fn into_string_unchecked(self) -> crate::String {
160 let str = ManuallyDrop::new(self);
161 crate::String { ..*str.data.string }
162 }
163
164 pub unsafe fn into_array_unchecked(self) -> Array {
167 let array = ManuallyDrop::new(self);
168 Array { ..*array.data.array }
169 }
170
171 pub unsafe fn into_dict_unchecked(self) -> Dictionary {
174 let dict = ManuallyDrop::new(self);
175 Dictionary { ..*dict.data.dictionary }
176 }
177}
178
179macro_rules! clone_copy {
180 ($self:expr, $field:ident) => {{
181 Self {
182 ty: $self.ty,
183 data: ObjectData { $field: unsafe { $self.data.$field } },
184 }
185 }};
186}
187
188macro_rules! clone_drop {
189 ($self:expr, $field:ident, $as_type:ty) => {{
190 Self {
191 ty: $self.ty,
192 data: ObjectData {
193 $field: ManuallyDrop::new(
194 unsafe { &$self.data.$field as &$as_type }.clone(),
195 ),
196 },
197 }
198 }};
199}
200
201impl Clone for Object {
202 fn clone(&self) -> Self {
203 match self.ty {
204 ObjectKind::Nil => Self::nil(),
205 ObjectKind::Boolean => clone_copy!(self, boolean),
206 ObjectKind::Integer => clone_copy!(self, integer),
207 ObjectKind::Float => clone_copy!(self, float),
208 ObjectKind::String => clone_drop!(self, string, crate::String),
209 ObjectKind::Array => clone_drop!(self, array, Array),
210 ObjectKind::Dictionary => {
211 clone_drop!(self, dictionary, Dictionary)
212 },
213 ObjectKind::LuaRef => clone_copy!(self, luaref),
214 }
215 }
216}
217
218impl Drop for Object {
219 fn drop(&mut self) {
220 use ObjectKind::*;
221 match self.ty {
222 String => unsafe { ManuallyDrop::drop(&mut self.data.string) },
223
224 Array => unsafe { ManuallyDrop::drop(&mut self.data.array) },
225
226 Dictionary => unsafe {
227 ManuallyDrop::drop(&mut self.data.dictionary)
228 },
229
230 _ => {},
231 }
232 }
233}
234
235impl PartialEq<Self> for Object {
236 #[inline]
237 fn eq(&self, other: &Self) -> bool {
238 if self.ty != other.ty {
239 return false;
240 };
241
242 let (lhs, rhs) = (&self.data, &other.data);
243
244 unsafe {
245 use ObjectKind::*;
246 match self.ty {
247 Nil => true,
248 Boolean => lhs.boolean == rhs.boolean,
249 Integer => lhs.boolean == rhs.boolean,
250 Float => lhs.float == rhs.float,
251 String => lhs.string == rhs.string,
252 Array => lhs.array == rhs.array,
253 Dictionary => lhs.dictionary == rhs.dictionary,
254 LuaRef => lhs.luaref == rhs.luaref,
255 }
256 }
257 }
258}
259
260impl From<()> for Object {
261 fn from(_: ()) -> Self {
262 Self::nil()
263 }
264}
265
266macro_rules! from_copy {
268 ($type:ident, $variant:ident, $data:ident) => {
269 impl From<$type> for Object {
270 #[inline(always)]
271 fn from($data: $type) -> Self {
272 Object { ty: ObjectKind::$variant, data: ObjectData { $data } }
273 }
274 }
275 };
276}
277
278from_copy!(Boolean, Boolean, boolean);
279from_copy!(Integer, Integer, integer);
280from_copy!(Float, Float, float);
281
282macro_rules! from_man_drop {
284 ($type:ty, $variant:ident, $data:ident) => {
285 impl From<$type> for Object {
286 #[inline(always)]
287 fn from($data: $type) -> Self {
288 Object {
289 ty: ObjectKind::$variant,
290 data: ObjectData { $data: ManuallyDrop::new($data) },
291 }
292 }
293 }
294 };
295}
296
297from_man_drop!(crate::String, String, string);
298from_man_drop!(Array, Array, array);
299from_man_drop!(Dictionary, Dictionary, dictionary);
300
301impl<A, R> From<Function<A, R>> for Object {
302 fn from(fun: Function<A, R>) -> Self {
303 Self::from_luaref(fun.lua_ref)
304 }
305}
306
307macro_rules! from_int {
309 ($type:ident) => {
310 impl From<$type> for Object {
311 #[inline(always)]
312 fn from(i: $type) -> Self {
313 Integer::from(i).into()
314 }
315 }
316 };
317}
318
319from_int!(i8);
320from_int!(u8);
321from_int!(i16);
322from_int!(u16);
323from_int!(i32);
324from_int!(u32);
325
326impl From<f32> for Object {
327 #[inline(always)]
328 fn from(n: f32) -> Self {
329 Float::from(n).into()
330 }
331}
332
333impl From<String> for Object {
334 #[inline(always)]
335 fn from(s: String) -> Self {
336 crate::String::from(s).into()
337 }
338}
339
340impl From<&str> for Object {
341 #[inline(always)]
342 fn from(s: &str) -> Self {
343 crate::String::from(s).into()
344 }
345}
346
347impl From<char> for Object {
348 #[inline(always)]
349 fn from(ch: char) -> Self {
350 crate::String::from(ch).into()
351 }
352}
353
354impl<T> From<Option<T>> for Object
355where
356 Object: From<T>,
357{
358 #[inline(always)]
359 fn from(maybe: Option<T>) -> Self {
360 maybe.map(Into::into).unwrap_or_default()
361 }
362}
363
364impl<T> From<Box<T>> for Object
365where
366 Object: From<T>,
367{
368 #[inline(always)]
369 fn from(boxed: Box<T>) -> Self {
370 (*boxed).into()
371 }
372}
373
374impl<T> From<Cow<'_, T>> for Object
375where
376 T: Clone,
377 Object: From<T>,
378{
379 #[inline(always)]
380 fn from(moo: Cow<'_, T>) -> Self {
381 moo.into_owned().into()
382 }
383}
384
385impl From<Cow<'_, str>> for Object {
386 fn from(moo: Cow<'_, str>) -> Self {
387 crate::String::from(moo).into()
388 }
389}
390
391impl<T> FromIterator<T> for Object
392where
393 T: Into<Object>,
394{
395 #[inline(always)]
396 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
397 Array::from_iter(iter).into()
398 }
399}
400
401impl<K, V> FromIterator<(K, V)> for Object
402where
403 crate::String: From<K>,
404 Object: From<V>,
405{
406 #[inline(always)]
407 fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
408 Dictionary::from_iter(iter).into()
409 }
410}
411
412impl Pushable for Object {
413 unsafe fn push(self, lstate: *mut lua_State) -> Result<c_int, lua::Error> {
414 match self.kind() {
415 ObjectKind::Nil => ().push(lstate),
416 ObjectKind::Boolean => self.as_boolean_unchecked().push(lstate),
417 ObjectKind::Integer => self.as_integer_unchecked().push(lstate),
418 ObjectKind::Float => self.as_float_unchecked().push(lstate),
419 ObjectKind::String => self.into_string_unchecked().push(lstate),
420 ObjectKind::Array => self.into_array_unchecked().push(lstate),
421 ObjectKind::Dictionary => self.into_dict_unchecked().push(lstate),
422 ObjectKind::LuaRef => {
423 Function::<(), ()>::from_ref(self.as_luaref_unchecked())
424 .push(lstate)
425 },
426 }
427 }
428}
429
430impl Poppable for Object {
431 unsafe fn pop(lstate: *mut lua_State) -> Result<Self, lua::Error> {
432 match lua_type(lstate, -1) {
433 LUA_TNIL => <()>::pop(lstate).map(Into::into),
434
435 LUA_TBOOLEAN => bool::pop(lstate).map(Into::into),
436
437 LUA_TNUMBER => {
438 let n = lua_Number::pop(lstate)?;
439
440 if n == (n as c_int) as lua_Number {
443 Ok(Object::from(n as c_int))
444 } else {
445 Ok(Object::from(n))
446 }
447 },
448
449 LUA_TSTRING => crate::String::pop(lstate).map(Into::into),
450
451 LUA_TTABLE => {
452 if lua::utils::is_table_array(lstate, -1) {
453 Array::pop(lstate).map(Into::into)
454 } else {
455 Dictionary::pop(lstate).map(Into::into)
456 }
457 },
458
459 LUA_TFUNCTION => Function::<(), ()>::pop(lstate).map(Into::into),
460
461 LUA_TNONE => Err(lua::Error::PopEmptyStack),
462
463 LUA_TLIGHTUSERDATA | LUA_TUSERDATA | LUA_TTHREAD => {
464 let typename = lua::utils::debug_type(lstate, -1);
465 lua_pop(lstate, 1);
466
467 Err(lua::Error::pop_error(
468 "Object",
469 format!("unexpected value of type {}", typename),
470 ))
471 },
472
473 _ => unreachable!(),
474 }
475 }
476}
477
478#[cfg(feature = "serde")]
479mod serde {
480 use std::fmt;
481
482 use serde::de::{self, Deserialize};
483
484 use super::Object;
485 use crate::{Array, Dictionary, Integer, LuaRef};
486
487 impl<'de> Deserialize<'de> for Object {
488 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
489 where
490 D: de::Deserializer<'de>,
491 {
492 struct ObjectVisitor;
493
494 macro_rules! visit_into {
495 ($fn_name:ident, $ty:ty) => {
496 fn $fn_name<E>(self, value: $ty) -> Result<Self::Value, E>
497 where
498 E: de::Error,
499 {
500 Ok(Object::from(value))
501 }
502 };
503 }
504
505 impl<'de> de::Visitor<'de> for ObjectVisitor {
506 type Value = Object;
507
508 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
509 f.write_str("either a string of a byte vector")
510 }
511
512 fn visit_unit<E>(self) -> Result<Self::Value, E>
513 where
514 E: de::Error,
515 {
516 Ok(Object::nil())
517 }
518
519 fn visit_bytes<E>(self, b: &[u8]) -> Result<Self::Value, E>
520 where
521 E: de::Error,
522 {
523 Ok(crate::String::from_bytes(b.to_owned()).into())
524 }
525
526 fn visit_u64<E>(self, n: u64) -> Result<Self::Value, E>
527 where
528 E: de::Error,
529 {
530 Integer::try_from(n).map(Object::from).map_err(E::custom)
531 }
532
533 fn visit_f32<E>(self, f: f32) -> Result<Self::Value, E>
534 where
535 E: de::Error,
536 {
537 Ok(Object::from_luaref(f as LuaRef))
538 }
539
540 fn visit_seq<A>(
541 self,
542 mut seq: A,
543 ) -> Result<Self::Value, A::Error>
544 where
545 A: de::SeqAccess<'de>,
546 {
547 let mut vec = Vec::<Object>::with_capacity(
548 seq.size_hint().unwrap_or_default(),
549 );
550
551 while let Some(obj) = seq.next_element::<Object>()? {
552 vec.push(obj);
553 }
554
555 Ok(vec.into_iter().collect::<Array>().into())
556 }
557
558 fn visit_map<A>(
559 self,
560 mut map: A,
561 ) -> Result<Self::Value, A::Error>
562 where
563 A: de::MapAccess<'de>,
564 {
565 let mut vec =
566 Vec::<(crate::String, Object)>::with_capacity(
567 map.size_hint().unwrap_or_default(),
568 );
569
570 while let Some(pair) =
571 map.next_entry::<crate::String, Object>()?
572 {
573 vec.push(pair);
574 }
575
576 Ok(vec.into_iter().collect::<Dictionary>().into())
577 }
578
579 visit_into!(visit_bool, bool);
580 visit_into!(visit_i8, i8);
581 visit_into!(visit_u8, u8);
582 visit_into!(visit_i16, i16);
583 visit_into!(visit_u16, u16);
584 visit_into!(visit_i32, i32);
585 visit_into!(visit_u32, u32);
586 visit_into!(visit_i64, i64);
587 visit_into!(visit_f64, f64);
588 visit_into!(visit_str, &str);
589 }
590
591 deserializer.deserialize_any(ObjectVisitor)
592 }
593 }
594}
595
596#[cfg(test)]
597mod tests {
598 use super::*;
599 use crate::conversion::FromObject;
600
601 #[test]
602 fn std_string_to_obj_and_back() {
603 let str = String::from("foo");
604 let obj = Object::from(str.clone());
605 let str_again = String::from_object(obj);
606 assert!(str_again.is_ok());
607 assert_eq!(str, str_again.unwrap());
608 }
609
610 #[test]
611 fn print_nil() {
612 let obj = Object::nil();
613 assert_eq!("()", &format!("{obj:?}"));
614 assert_eq!("()", &format!("{obj}"));
615 }
616
617 #[test]
618 fn print_boolean() {
619 let obj = Object::from(true);
620 assert_eq!("true", &format!("{obj:?}"));
621 assert_eq!("true", &format!("{obj}"));
622 }
623
624 #[test]
625 fn print_integer() {
626 let obj = Object::from(42);
627 assert_eq!("42", &format!("{obj:?}"));
628 assert_eq!("42", &format!("{obj}"));
629 }
630
631 #[test]
632 fn print_float() {
633 let obj = Object::from(42.1);
634 assert_eq!("42.1", &format!("{obj:?}"));
635 assert_eq!("42.1", &format!("{obj}"));
636 }
637
638 #[test]
639 fn print_string() {
640 let obj = Object::from("foobar");
641 assert_eq!("\"foobar\"", &format!("{obj:?}"));
642 assert_eq!("\"foobar\"", &format!("{obj}"));
643 }
644
645 #[test]
646 fn print_array() {
647 let obj = Object::from(Array::from((42.1, true, "foo")));
648 assert_eq!("[42.1, true, \"foo\"]", &format!("{obj:?}"));
649 assert_eq!("[42.1, true, \"foo\"]", &format!("{obj}"));
650 }
651
652 #[test]
653 fn print_dict() {
654 let obj = Object::from(Dictionary::from_iter([
655 ("foo", Object::from("bar")),
656 ("baz", Object::from(19)),
657 ]));
658 assert_eq!("{foo: \"bar\", baz: 19}", &format!("{obj:?}"));
659 assert_eq!("{foo: \"bar\", baz: 19}", &format!("{obj}"));
660 }
661
662 #[test]
663 fn print_luaref() {
664 let obj = Object::from_luaref(42);
665 assert_eq!("LuaRef(42)", &format!("{obj:?}"));
666 assert_eq!("LuaRef(42)", &format!("{obj}"));
667 }
668}