nvim_oxi_types/
object.rs

1use std::borrow::Cow;
2use std::ffi::c_int;
3use std::mem::ManuallyDrop;
4
5use lua::{Poppable, Pushable, ffi::*};
6use luajit as lua;
7
8use crate::{
9    Array,
10    Boolean,
11    Dictionary,
12    Float,
13    Function,
14    Integer,
15    LuaRef,
16    NonOwning,
17    NvimStr,
18    String as NvimString,
19};
20
21// https://github.com/neovim/neovim/blob/v0.9.0/src/nvim/api/private/defs.h#L109-L120
22//
23/// Binding to a Neovim object.
24///
25/// Represents any valid Neovim type.
26#[repr(C)]
27pub struct Object {
28    ty: ObjectKind,
29    data: ObjectData,
30}
31
32// https://github.com/neovim/neovim/blob/v0.9.0/src/nvim/api/private/defs.h#L94-L107
33//
34/// Specifies the kind of a Neovim [`Object`].
35#[derive(Copy, Clone, Debug, Eq, PartialEq)]
36#[repr(C)]
37pub enum ObjectKind {
38    Nil = 0,
39    Boolean,
40    Integer,
41    Float,
42    String,
43    Array,
44    Dictionary,
45    LuaRef,
46    Buffer,
47    Window,
48    TabPage,
49}
50
51impl ObjectKind {
52    pub fn as_static(&self) -> &'static str {
53        match self {
54            Self::Nil => "nil",
55            Self::Boolean => "boolean",
56            Self::Integer => "integer",
57            Self::Float => "float",
58            Self::String => "string",
59            Self::Array => "array",
60            Self::Dictionary => "dictionary",
61            Self::LuaRef => "luaref",
62            Self::Buffer => "buffer",
63            Self::Window => "window",
64            Self::TabPage => "tabpage",
65        }
66    }
67}
68
69// https://github.com/neovim/neovim/blob/v0.9.0/src/nvim/api/private/defs.h#L111-L119
70#[repr(C)]
71union ObjectData {
72    boolean: Boolean,
73    integer: Integer,
74    float: Float,
75    string: ManuallyDrop<NvimString>,
76    array: ManuallyDrop<Array>,
77    dictionary: ManuallyDrop<Dictionary>,
78    luaref: LuaRef,
79}
80
81impl Default for Object {
82    fn default() -> Object {
83        Object::nil()
84    }
85}
86
87impl core::fmt::Debug for Object {
88    #[inline]
89    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
90        let field: &dyn core::fmt::Debug = match self.ty {
91            ObjectKind::Nil => return f.write_str("nil"),
92
93            ObjectKind::Boolean => unsafe { &self.data.boolean },
94
95            ObjectKind::Integer
96            | ObjectKind::Buffer
97            | ObjectKind::Window
98            | ObjectKind::TabPage => unsafe { &self.data.integer },
99
100            ObjectKind::Float => unsafe { &self.data.float },
101
102            ObjectKind::String => unsafe { &*self.data.string },
103
104            ObjectKind::Array => unsafe { &*self.data.array },
105
106            ObjectKind::Dictionary => unsafe { &*self.data.dictionary },
107
108            ObjectKind::LuaRef => {
109                let luaref = unsafe { self.data.luaref };
110                return write!(f, "Object(LuaRef({luaref}))");
111            },
112        };
113
114        field.fmt(f)
115    }
116}
117
118impl Object {
119    /// Returns a new nil object.
120    #[inline]
121    pub fn nil() -> Self {
122        Self { ty: ObjectKind::Nil, data: ObjectData { integer: 0 } }
123    }
124
125    #[inline]
126    pub fn is_nil(&self) -> bool {
127        matches!(self.ty, ObjectKind::Nil)
128    }
129
130    #[inline]
131    pub fn is_some(&self) -> bool {
132        !self.is_nil()
133    }
134
135    #[inline(always)]
136    pub fn from_luaref(luaref: LuaRef) -> Self {
137        Self { ty: ObjectKind::LuaRef, data: ObjectData { luaref } }
138    }
139
140    #[inline]
141    pub fn kind(&self) -> ObjectKind {
142        self.ty
143    }
144
145    /// Make a non-owning version of this `Object`.
146    #[inline]
147    #[doc(hidden)]
148    pub fn non_owning(&self) -> NonOwning<'_, Self> {
149        // Using ptr::read, because can't copy the union.
150        unsafe { NonOwning::new(std::ptr::read(self)) }
151    }
152
153    /// Returns the boolean stored in this [`Object`].
154    ///
155    /// This is a zero-cost method that directly accesses the underlying value
156    /// without performing any runtime checks.
157    ///
158    /// # Safety
159    ///
160    /// This `Object`'s [`ObjectKind`] must be a
161    /// [`Boolean`][ObjectKind::Boolean]. Calling this method on an `Object`
162    /// with any other kind may result in undefined behavior.
163    #[cfg_attr(debug_assertions, track_caller)]
164    #[inline(always)]
165    pub unsafe fn as_boolean_unchecked(&self) -> bool {
166        debug_assert!(self.ty == ObjectKind::Boolean, "{:?}", self.ty);
167        self.data.boolean
168    }
169
170    /// Returns a mutable reference to the boolean stored in this
171    /// [`Object`].
172    ///
173    /// This is a zero-cost method that directly accesses the underlying
174    /// value without performing any runtime checks.
175    ///
176    /// # Safety
177    ///
178    /// This `Object`'s [`ObjectKind`] must be a
179    /// [`Boolean`][ObjectKind::Boolean]. Calling this method on an `Object`
180    /// with any other kind may result in undefined behavior.
181    #[cfg_attr(debug_assertions, track_caller)]
182    #[inline(always)]
183    pub unsafe fn as_boolean_unchecked_mut(&mut self) -> &mut bool {
184        debug_assert!(self.ty == ObjectKind::Boolean, "{:?}", self.ty);
185        &mut self.data.boolean
186    }
187
188    /// Returns the integer stored in this [`Object`].
189    ///
190    /// This is a zero-cost method that directly accesses the underlying
191    /// value without performing any runtime checks.
192    ///
193    /// # Safety
194    ///
195    /// This `Object`'s [`ObjectKind`] must be one of
196    /// [`Integer`][ObjectKind::Integer], [`Buffer`][ObjectKind::Buffer],
197    /// [`Window`][ObjectKind::Window], or [`TabPage`][ObjectKind::TabPage].
198    /// Calling this method on an `Object` with any other kind may result in
199    /// undefined
200    /// behavior.
201    #[cfg_attr(debug_assertions, track_caller)]
202    #[inline(always)]
203    pub unsafe fn as_integer_unchecked(&self) -> Integer {
204        debug_assert!(
205            matches!(
206                self.ty,
207                ObjectKind::Integer
208                    | ObjectKind::Buffer
209                    | ObjectKind::Window
210                    | ObjectKind::TabPage
211            ),
212            "{:?}",
213            self.ty
214        );
215        self.data.integer
216    }
217
218    /// Returns a mutable reference to the integer stored in this
219    /// [`Object`].
220    ///
221    /// This is a zero-cost method that directly accesses the underlying
222    /// value without performing any runtime checks.
223    ///
224    /// # Safety
225    ///
226    /// This `Object`'s [`ObjectKind`] must be one of
227    /// [`Integer`][ObjectKind::Integer], [`Buffer`][ObjectKind::Buffer],
228    /// [`Window`][ObjectKind::Window], or [`TabPage`][ObjectKind::TabPage].
229    /// Calling this method on an `Object` with any other kind may result in
230    /// undefined
231    /// behavior.
232    #[cfg_attr(debug_assertions, track_caller)]
233    #[inline(always)]
234    pub unsafe fn as_integer_unchecked_mut(&mut self) -> &mut Integer {
235        debug_assert!(
236            matches!(
237                self.ty,
238                ObjectKind::Integer
239                    | ObjectKind::Buffer
240                    | ObjectKind::Window
241                    | ObjectKind::TabPage
242            ),
243            "{:?}",
244            self.ty
245        );
246        &mut self.data.integer
247    }
248
249    /// Returns the float stored in this [`Object`].
250    ///
251    /// This is a zero-cost method that directly accesses the underlying
252    /// value without performing any runtime checks.
253    ///
254    /// # Safety
255    ///
256    /// This `Object`'s [`ObjectKind`] must be a [`Float`][ObjectKind::Float].
257    /// Calling this method on an `Object` with any other kind may result in
258    /// undefined behavior.
259    #[cfg_attr(debug_assertions, track_caller)]
260    #[inline(always)]
261    pub unsafe fn as_float_unchecked(&self) -> Float {
262        debug_assert!(self.ty == ObjectKind::Float, "{:?}", self.ty);
263        self.data.float
264    }
265
266    /// Returns a mutable reference to the float stored in this
267    /// [`Object`].
268    ///
269    /// This is a zero-cost method that directly accesses the underlying
270    /// value without performing any runtime checks.
271    ///
272    /// # Safety
273    ///
274    /// This `Object`'s [`ObjectKind`] must be a [`Float`][ObjectKind::Float].
275    /// Calling this method on an `Object` with any other kind may result in
276    /// undefined behavior.
277    #[cfg_attr(debug_assertions, track_caller)]
278    #[inline(always)]
279    pub unsafe fn as_float_unchecked_mut(&mut self) -> &mut Float {
280        debug_assert!(self.ty == ObjectKind::Float, "{:?}", self.ty);
281        &mut self.data.float
282    }
283
284    /// Returns the Lua reference stored in this [`Object`].
285    ///
286    /// This is a zero-cost method that directly accesses the underlying
287    /// value without performing any runtime checks.
288    ///
289    /// # Safety
290    ///
291    /// This `Object`'s [`ObjectKind`] must be a
292    /// [`LuaRef`][ObjectKind::LuaRef]. Calling this method on an `Object` with
293    /// any other kind may result in undefined behavior.
294    #[cfg_attr(debug_assertions, track_caller)]
295    #[inline(always)]
296    pub unsafe fn as_luaref_unchecked(&self) -> LuaRef {
297        debug_assert!(self.ty == ObjectKind::LuaRef, "{:?}", self.ty);
298        self.data.luaref
299    }
300
301    /// Returns a mutable reference to the Lua reference stored in this
302    /// [`Object`].
303    ///
304    /// This is a zero-cost method that directly accesses the underlying
305    /// value without performing any runtime checks.
306    ///
307    /// # Safety
308    ///
309    /// This `Object`'s [`ObjectKind`] must be a
310    /// [`LuaRef`][ObjectKind::LuaRef]. Calling this method on an `Object` with
311    /// any other kind may result in undefined behavior.
312    #[cfg_attr(debug_assertions, track_caller)]
313    #[inline(always)]
314    pub unsafe fn as_luaref_unchecked_mut(&mut self) -> &mut LuaRef {
315        debug_assert!(self.ty == ObjectKind::LuaRef, "{:?}", self.ty);
316        &mut self.data.luaref
317    }
318
319    /// Returns a reference to the string stored in this [`Object`].
320    ///
321    /// This is a zero-cost method that directly accesses the underlying
322    /// value without performing any runtime checks.
323    ///
324    /// # Safety
325    ///
326    /// This `Object`'s [`ObjectKind`] must be a
327    /// [`String`][ObjectKind::String]. Calling this method on an `Object` with
328    /// any other kind may result in undefined behavior.
329    #[cfg_attr(debug_assertions, track_caller)]
330    pub unsafe fn as_nvim_str_unchecked(&self) -> NvimStr<'_> {
331        debug_assert!(self.ty == ObjectKind::String, "{:?}", self.ty);
332        self.data.string.as_nvim_str()
333    }
334
335    /// Returns the string stored in this [`Object`].
336    ///
337    /// This is a zero-cost method that directly accesses the underlying value
338    /// without performing any runtime checks.
339    ///
340    /// # Safety
341    ///
342    /// This `Object`'s [`ObjectKind`] must be a
343    /// [`String`][ObjectKind::String]. Calling this method on an `Object` with
344    /// any other kind may result in undefined behavior.
345    #[cfg_attr(debug_assertions, track_caller)]
346    pub unsafe fn into_string_unchecked(self) -> NvimString {
347        debug_assert!(self.ty == ObjectKind::String, "{:?}", self.ty);
348        let string = &self.data.string;
349        let string = unsafe {
350            NvimString::from_raw_parts(string.as_ptr(), string.len())
351        };
352        core::mem::forget(self);
353        string
354    }
355
356    /// Returns a reference to the array stored in this [`Object`].
357    ///
358    /// This is a zero-cost method that directly accesses the underlying value
359    /// without performing any runtime checks.
360    ///
361    /// # Safety
362    ///
363    /// This `Object`'s [`ObjectKind`] must be an [`Array`][ObjectKind::Array].
364    /// Calling this method on an `Object` with any other kind may result in
365    /// undefined behavior.
366    #[cfg_attr(debug_assertions, track_caller)]
367    pub unsafe fn as_array_unchecked(&self) -> &Array {
368        debug_assert!(self.ty == ObjectKind::Array, "{:?}", self.ty);
369        &self.data.array
370    }
371
372    /// Returns a mutable reference to the array stored in this
373    /// [`Object`].
374    ///
375    /// This is a zero-cost method that directly accesses the underlying value
376    /// without performing any runtime checks.
377    ///
378    /// # Safety
379    ///
380    /// This `Object`'s [`ObjectKind`] must be an [`Array`][ObjectKind::Array].
381    /// Calling this method on an `Object` with any other kind may result in
382    /// undefined behavior.
383    #[cfg_attr(debug_assertions, track_caller)]
384    pub unsafe fn as_array_unchecked_mut(&mut self) -> &mut Array {
385        debug_assert!(self.ty == ObjectKind::Array, "{:?}", self.ty);
386        &mut self.data.array
387    }
388
389    /// Returns the array stored in this [`Object`].
390    ///
391    /// This is a zero-cost method that directly accesses the underlying value
392    /// without performing any runtime checks.
393    ///
394    /// # Safety
395    ///
396    /// This `Object`'s [`ObjectKind`] must be an [`Array`][ObjectKind::Array].
397    /// Calling this method on an `Object` with any other kind may result in
398    /// undefined behavior.
399    #[cfg_attr(debug_assertions, track_caller)]
400    pub unsafe fn into_array_unchecked(self) -> Array {
401        debug_assert!(self.ty == ObjectKind::Array, "{:?}", self.ty);
402        #[allow(clippy::unnecessary_struct_initialization)]
403        let array = Array(crate::kvec::KVec { ..self.data.array.0 });
404        core::mem::forget(self);
405        array
406    }
407
408    /// Returns a reference to the dictionary stored in this [`Object`].
409    ///
410    /// This is a zero-cost method that directly accesses the underlying value
411    /// without performing any runtime checks.
412    ///
413    /// # Safety
414    ///
415    /// This `Object`'s [`ObjectKind`] must be a
416    /// [`Dictionary`][ObjectKind::Dictionary]. Calling this method on an
417    /// `Object` with any other kind may result in undefined behavior.
418    #[cfg_attr(debug_assertions, track_caller)]
419    pub unsafe fn as_dictionary_unchecked(&self) -> &Dictionary {
420        debug_assert!(self.ty == ObjectKind::Dictionary, "{:?}", self.ty);
421        &self.data.dictionary
422    }
423
424    /// Returns a mutable reference to the dictionary stored in this
425    /// [`Object`].
426    ///
427    /// This is a zero-cost method that directly accesses the underlying value
428    /// without performing any runtime checks.
429    ///
430    /// # Safety
431    ///
432    /// This `Object`'s [`ObjectKind`] must be a
433    /// [`Dictionary`][ObjectKind::Dictionary]. Calling this method on an
434    /// `Object` with any other kind may result in undefined behavior.
435    #[cfg_attr(debug_assertions, track_caller)]
436    pub unsafe fn as_dictionary_unchecked_mut(&mut self) -> &mut Dictionary {
437        debug_assert!(self.ty == ObjectKind::Dictionary, "{:?}", self.ty);
438        &mut self.data.dictionary
439    }
440
441    /// Returns the dictionary stored in this [`Object`].
442    ///
443    /// This is a zero-cost method that directly accesses the underlying value
444    /// without performing any runtime checks.
445    ///
446    /// # Safety
447    ///
448    /// This `Object`'s [`ObjectKind`] must be a
449    /// [`Dictionary`][ObjectKind::Dictionary]. Calling this method on an
450    /// `Object` with any other kind may result in undefined behavior.
451    #[cfg_attr(debug_assertions, track_caller)]
452    pub unsafe fn into_dictionary_unchecked(self) -> Dictionary {
453        debug_assert!(self.ty == ObjectKind::Dictionary, "{:?}", self.ty);
454        #[allow(clippy::unnecessary_struct_initialization)]
455        let dict = Dictionary(crate::kvec::KVec { ..self.data.dictionary.0 });
456        core::mem::forget(self);
457        dict
458    }
459}
460
461macro_rules! clone_copy {
462    ($self:expr, $field:ident) => {{
463        Self {
464            ty: $self.ty,
465            data: ObjectData { $field: unsafe { $self.data.$field } },
466        }
467    }};
468}
469
470macro_rules! clone_drop {
471    ($self:expr, $field:ident, $as_type:ty) => {{
472        Self {
473            ty: $self.ty,
474            data: ObjectData {
475                $field: ManuallyDrop::new(
476                    unsafe { &$self.data.$field as &$as_type }.clone(),
477                ),
478            },
479        }
480    }};
481}
482
483impl Clone for Object {
484    fn clone(&self) -> Self {
485        match self.ty {
486            ObjectKind::Nil => Self::nil(),
487            ObjectKind::Boolean => clone_copy!(self, boolean),
488            ObjectKind::Integer
489            | ObjectKind::Buffer
490            | ObjectKind::Window
491            | ObjectKind::TabPage => clone_copy!(self, integer),
492            ObjectKind::Float => clone_copy!(self, float),
493            ObjectKind::String => clone_drop!(self, string, NvimString),
494            ObjectKind::Array => clone_drop!(self, array, Array),
495            ObjectKind::Dictionary => {
496                clone_drop!(self, dictionary, Dictionary)
497            },
498            ObjectKind::LuaRef => clone_copy!(self, luaref),
499        }
500    }
501}
502
503impl Drop for Object {
504    fn drop(&mut self) {
505        match self.ty {
506            ObjectKind::String => unsafe {
507                ManuallyDrop::drop(&mut self.data.string)
508            },
509
510            ObjectKind::Array => unsafe {
511                ManuallyDrop::drop(&mut self.data.array)
512            },
513
514            ObjectKind::Dictionary => unsafe {
515                ManuallyDrop::drop(&mut self.data.dictionary)
516            },
517
518            _ => {},
519        }
520    }
521}
522
523impl PartialEq<Self> for Object {
524    #[inline]
525    fn eq(&self, other: &Self) -> bool {
526        if self.ty != other.ty {
527            return false;
528        };
529
530        let (lhs, rhs) = (&self.data, &other.data);
531
532        unsafe {
533            use ObjectKind::*;
534            match self.ty {
535                Nil => true,
536                Boolean => lhs.boolean == rhs.boolean,
537                Integer | Buffer | Window | TabPage => {
538                    lhs.integer == rhs.integer
539                },
540                Float => lhs.float == rhs.float,
541                String => lhs.string == rhs.string,
542                Array => lhs.array == rhs.array,
543                Dictionary => lhs.dictionary == rhs.dictionary,
544                LuaRef => lhs.luaref == rhs.luaref,
545            }
546        }
547    }
548}
549
550impl From<()> for Object {
551    fn from(_: ()) -> Self {
552        Self::nil()
553    }
554}
555
556// Implements `From<..>` for primitive `Copy` types.
557macro_rules! from_copy {
558    ($type:ident, $variant:ident, $data:ident) => {
559        impl From<$type> for Object {
560            #[inline(always)]
561            fn from($data: $type) -> Self {
562                Object { ty: ObjectKind::$variant, data: ObjectData { $data } }
563            }
564        }
565    };
566}
567
568from_copy!(Boolean, Boolean, boolean);
569from_copy!(Integer, Integer, integer);
570from_copy!(Float, Float, float);
571
572/// Implements `From<..>` for primitive `ManuallyDrop` types.
573macro_rules! from_man_drop {
574    ($type:ty, $variant:ident, $data:ident) => {
575        impl From<$type> for Object {
576            #[inline(always)]
577            fn from($data: $type) -> Self {
578                Object {
579                    ty: ObjectKind::$variant,
580                    data: ObjectData { $data: ManuallyDrop::new($data) },
581                }
582            }
583        }
584    };
585}
586
587from_man_drop!(NvimString, String, string);
588from_man_drop!(Array, Array, array);
589from_man_drop!(Dictionary, Dictionary, dictionary);
590
591impl<A, R> From<Function<A, R>> for Object {
592    fn from(fun: Function<A, R>) -> Self {
593        Self::from_luaref(fun.lua_ref)
594    }
595}
596
597/// Implements `From<..>` for integer types convertible to `Integer`.
598macro_rules! from_int {
599    ($type:ident) => {
600        impl From<$type> for Object {
601            #[inline(always)]
602            fn from(i: $type) -> Self {
603                Integer::from(i).into()
604            }
605        }
606    };
607}
608
609from_int!(i8);
610from_int!(u8);
611from_int!(i16);
612from_int!(u16);
613from_int!(i32);
614from_int!(u32);
615
616impl From<f32> for Object {
617    #[inline(always)]
618    fn from(n: f32) -> Self {
619        Float::from(n).into()
620    }
621}
622
623impl From<String> for Object {
624    #[inline(always)]
625    fn from(s: String) -> Self {
626        NvimString::from(s.as_str()).into()
627    }
628}
629
630impl From<&str> for Object {
631    #[inline(always)]
632    fn from(s: &str) -> Self {
633        NvimString::from(s).into()
634    }
635}
636
637impl From<char> for Object {
638    #[inline(always)]
639    fn from(ch: char) -> Self {
640        NvimString::from(ch).into()
641    }
642}
643
644impl<T> From<Option<T>> for Object
645where
646    Object: From<T>,
647{
648    #[inline(always)]
649    fn from(maybe: Option<T>) -> Self {
650        maybe.map(Into::into).unwrap_or_default()
651    }
652}
653
654impl<T> From<Box<T>> for Object
655where
656    Object: From<T>,
657{
658    #[inline(always)]
659    fn from(boxed: Box<T>) -> Self {
660        (*boxed).into()
661    }
662}
663
664impl<T> From<Cow<'_, T>> for Object
665where
666    T: Clone,
667    Object: From<T>,
668{
669    #[inline(always)]
670    fn from(moo: Cow<'_, T>) -> Self {
671        moo.into_owned().into()
672    }
673}
674
675impl From<Cow<'_, str>> for Object {
676    fn from(moo: Cow<'_, str>) -> Self {
677        NvimString::from(moo.as_ref()).into()
678    }
679}
680
681impl<T> FromIterator<T> for Object
682where
683    T: Into<Object>,
684{
685    #[inline(always)]
686    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
687        Array::from_iter(iter).into()
688    }
689}
690
691impl<K, V> FromIterator<(K, V)> for Object
692where
693    NvimString: From<K>,
694    Object: From<V>,
695{
696    #[inline(always)]
697    fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
698        Dictionary::from_iter(iter).into()
699    }
700}
701
702impl Pushable for Object {
703    unsafe fn push(self, lstate: *mut State) -> Result<c_int, lua::Error> {
704        match self.kind() {
705            ObjectKind::Nil => ().push(lstate),
706            ObjectKind::Boolean => self.as_boolean_unchecked().push(lstate),
707            ObjectKind::Integer
708            | ObjectKind::Buffer
709            | ObjectKind::Window
710            | ObjectKind::TabPage => self.as_integer_unchecked().push(lstate),
711            ObjectKind::Float => self.as_float_unchecked().push(lstate),
712            ObjectKind::String => self.into_string_unchecked().push(lstate),
713            ObjectKind::Array => self.into_array_unchecked().push(lstate),
714            ObjectKind::Dictionary => {
715                self.into_dictionary_unchecked().push(lstate)
716            },
717            ObjectKind::LuaRef => {
718                Function::<(), ()>::from_ref(self.as_luaref_unchecked())
719                    .push(lstate)
720            },
721        }
722    }
723}
724
725impl Poppable for Object {
726    unsafe fn pop(lstate: *mut State) -> Result<Self, lua::Error> {
727        if lua_gettop(lstate) == 0 {
728            return Ok(Self::nil());
729        }
730
731        match lua_type(lstate, -1) {
732            LUA_TNIL => <()>::pop(lstate).map(Into::into),
733
734            LUA_TBOOLEAN => bool::pop(lstate).map(Into::into),
735
736            LUA_TNUMBER => {
737                let n = Number::pop(lstate)?;
738
739                // This checks that the number is in the range (i32::MIN,
740                // i32::MAX) andd that it has no fractional component.
741                if n == (n as c_int) as Number {
742                    Ok(Object::from(n as c_int))
743                } else {
744                    Ok(Object::from(n))
745                }
746            },
747
748            LUA_TSTRING => NvimString::pop(lstate).map(Into::into),
749
750            LUA_TTABLE => {
751                if lua::utils::is_table_array(lstate, -1) {
752                    Array::pop(lstate).map(Into::into)
753                } else {
754                    Dictionary::pop(lstate).map(Into::into)
755                }
756            },
757
758            LUA_TFUNCTION => Function::<(), ()>::pop(lstate).map(Into::into),
759
760            LUA_TNONE => Err(lua::Error::PopEmptyStack),
761
762            LUA_TLIGHTUSERDATA | LUA_TUSERDATA | LUA_TTHREAD => {
763                let typename = lua::utils::debug_type(lstate, -1);
764                lua_pop(lstate, 1);
765
766                Err(lua::Error::pop_error(
767                    "Object",
768                    format!("unexpected value of type {typename}"),
769                ))
770            },
771
772            _ => unreachable!(),
773        }
774    }
775}
776
777#[cfg(feature = "serde")]
778mod serde {
779    use std::fmt;
780
781    use serde::de::{self, Deserialize};
782
783    use crate::{
784        Array,
785        Dictionary,
786        Integer,
787        LuaRef,
788        Object,
789        String as NvimString,
790    };
791
792    impl<'de> Deserialize<'de> for Object {
793        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
794        where
795            D: de::Deserializer<'de>,
796        {
797            struct ObjectVisitor;
798
799            macro_rules! visit_into {
800                ($fn_name:ident, $ty:ty) => {
801                    fn $fn_name<E>(self, value: $ty) -> Result<Self::Value, E>
802                    where
803                        E: de::Error,
804                    {
805                        Ok(Object::from(value))
806                    }
807                };
808            }
809
810            impl<'de> de::Visitor<'de> for ObjectVisitor {
811                type Value = Object;
812
813                fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
814                    f.write_str("either a string of a byte vector")
815                }
816
817                fn visit_unit<E>(self) -> Result<Self::Value, E>
818                where
819                    E: de::Error,
820                {
821                    Ok(Object::nil())
822                }
823
824                fn visit_bytes<E>(self, b: &[u8]) -> Result<Self::Value, E>
825                where
826                    E: de::Error,
827                {
828                    Ok(NvimString::from_bytes(b).into())
829                }
830
831                fn visit_u64<E>(self, n: u64) -> Result<Self::Value, E>
832                where
833                    E: de::Error,
834                {
835                    Integer::try_from(n).map(Object::from).map_err(E::custom)
836                }
837
838                fn visit_f32<E>(self, f: f32) -> Result<Self::Value, E>
839                where
840                    E: de::Error,
841                {
842                    Ok(Object::from_luaref(f as LuaRef))
843                }
844
845                fn visit_seq<A>(
846                    self,
847                    mut seq: A,
848                ) -> Result<Self::Value, A::Error>
849                where
850                    A: de::SeqAccess<'de>,
851                {
852                    let mut vec = Vec::<Object>::with_capacity(
853                        seq.size_hint().unwrap_or_default(),
854                    );
855
856                    while let Some(obj) = seq.next_element::<Object>()? {
857                        vec.push(obj);
858                    }
859
860                    Ok(vec.into_iter().collect::<Array>().into())
861                }
862
863                fn visit_map<A>(
864                    self,
865                    mut map: A,
866                ) -> Result<Self::Value, A::Error>
867                where
868                    A: de::MapAccess<'de>,
869                {
870                    let mut vec = Vec::<(NvimString, Object)>::with_capacity(
871                        map.size_hint().unwrap_or_default(),
872                    );
873
874                    while let Some(pair) =
875                        map.next_entry::<NvimString, Object>()?
876                    {
877                        vec.push(pair);
878                    }
879
880                    Ok(vec.into_iter().collect::<Dictionary>().into())
881                }
882
883                visit_into!(visit_bool, bool);
884                visit_into!(visit_i8, i8);
885                visit_into!(visit_u8, u8);
886                visit_into!(visit_i16, i16);
887                visit_into!(visit_u16, u16);
888                visit_into!(visit_i32, i32);
889                visit_into!(visit_u32, u32);
890                visit_into!(visit_i64, i64);
891                visit_into!(visit_f64, f64);
892                visit_into!(visit_str, &str);
893            }
894
895            deserializer.deserialize_any(ObjectVisitor)
896        }
897    }
898}
899
900#[cfg(test)]
901mod tests {
902    use super::*;
903    use crate::conversion::FromObject;
904
905    #[test]
906    fn debug_nil() {
907        assert_eq!(format!("{:?}", Object::nil()), "nil");
908    }
909
910    #[test]
911    fn std_string_to_obj_and_back() {
912        let str = String::from("foo");
913        let obj = Object::from(str.clone());
914        let str_again = String::from_object(obj);
915        assert!(str_again.is_ok());
916        assert_eq!(str, str_again.unwrap());
917    }
918}