nvim_types/
object.rs

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// https://github.com/neovim/neovim/blob/master/src/nvim/api/private/defs.h#L109
21//
22/// Binding to a Neovim object.
23///
24/// Represents any valid Neovim type.
25#[repr(C)]
26pub struct Object {
27    ty: ObjectKind,
28    data: ObjectData,
29}
30
31// https://github.com/neovim/neovim/blob/master/src/nvim/api/private/defs.h#L94
32//
33/// Specifies the kind of a Neovim [`Object`].
34#[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// https://github.com/neovim/neovim/blob/master/src/nvim/api/private/defs.h#L111
63#[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    /// Returns a new nil object.
104    #[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    /// Make a non-owning version of this `Object`.
130    #[inline]
131    #[doc(hidden)]
132    pub fn non_owning(&self) -> NonOwning<'_, Self> {
133        // Using ptr::read, because can't copy the union.
134        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    /// Extracts the contained [`String`](crate::String) value without checking
158    /// that the object actually contains a [`String`](crate::String).
159    pub unsafe fn into_string_unchecked(self) -> crate::String {
160        let str = ManuallyDrop::new(self);
161        crate::String { ..*str.data.string }
162    }
163
164    /// Extracts the contained [`Array`] value without checking that the object
165    /// actually contains an [`Array`].
166    pub unsafe fn into_array_unchecked(self) -> Array {
167        let array = ManuallyDrop::new(self);
168        Array { ..*array.data.array }
169    }
170
171    /// Extracts the contained [`Dictionary`] value without checking that the
172    /// object actually contains a [`Dictionary`].
173    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
266// Implements `From<..>` for primitive `Copy` types.
267macro_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
282/// Implements `From<..>` for primitive `ManuallyDrop` types.
283macro_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
307/// Implements `From<..>` for integer types convertible to `Integer`.
308macro_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                // This checks that the number is in the range (i32::MIN,
441                // i32::MAX) andd that it has no fractional component.
442                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}