nvim_oxi_luajit/
pushable.rs

1use core::ffi::{c_char, c_int};
2
3use crate::ffi::{self, Integer, Number, State};
4use crate::macros::count;
5use crate::utils;
6
7/// Trait implemented for types that can be pushed onto the Lua stack.
8pub trait Pushable {
9    /// Pushes all its values on the Lua stack, returning the number of values
10    /// that it pushed.
11    unsafe fn push(self, lstate: *mut State) -> Result<c_int, crate::Error>;
12}
13
14impl Pushable for () {
15    unsafe fn push(self, lstate: *mut State) -> Result<c_int, crate::Error> {
16        ffi::lua_pushnil(lstate);
17        Ok(1)
18    }
19}
20
21impl Pushable for bool {
22    unsafe fn push(self, lstate: *mut State) -> Result<c_int, crate::Error> {
23        ffi::lua_pushboolean(lstate, self as _);
24        Ok(1)
25    }
26}
27
28impl Pushable for Integer {
29    unsafe fn push(self, lstate: *mut State) -> Result<c_int, crate::Error> {
30        ffi::lua_pushinteger(lstate, self);
31        Ok(1)
32    }
33}
34
35/// Implements `LuaPushable` for an integer type that implements
36/// `Into<Integer>`.
37macro_rules! push_into_integer {
38    ($integer:ty) => {
39        impl Pushable for $integer {
40            unsafe fn push(
41                self,
42                lstate: *mut State,
43            ) -> Result<c_int, crate::Error> {
44                let n: Integer = self.into();
45                n.push(lstate)
46            }
47        }
48    };
49}
50
51/// Implements `LuaPushable` for an integer type that implements
52/// `TryInto<Integer>`.
53macro_rules! push_try_into_integer {
54    ($integer:ty) => {
55        impl Pushable for $integer {
56            unsafe fn push(
57                self,
58                lstate: *mut State,
59            ) -> Result<c_int, crate::Error> {
60                let n: Integer = self.try_into().map_err(
61                    |err: std::num::TryFromIntError| {
62                        crate::Error::push_error(
63                            std::any::type_name::<$integer>(),
64                            err.to_string(),
65                        )
66                    },
67                )?;
68                n.push(lstate)
69            }
70        }
71    };
72}
73
74push_into_integer!(i8);
75push_into_integer!(u8);
76push_into_integer!(i16);
77push_try_into_integer!(u16);
78push_try_into_integer!(i32);
79push_try_into_integer!(u32);
80push_try_into_integer!(i64);
81push_try_into_integer!(u64);
82push_try_into_integer!(usize);
83
84impl Pushable for Number {
85    unsafe fn push(self, lstate: *mut State) -> Result<c_int, crate::Error> {
86        ffi::lua_pushnumber(lstate, self);
87        Ok(1)
88    }
89}
90
91impl Pushable for f32 {
92    unsafe fn push(self, lstate: *mut State) -> Result<c_int, crate::Error> {
93        (self as Number).push(lstate)
94    }
95}
96
97impl Pushable for String {
98    unsafe fn push(self, lstate: *mut State) -> Result<c_int, crate::Error> {
99        ffi::lua_pushlstring(
100            lstate,
101            self.as_ptr() as *const c_char,
102            self.len(),
103        );
104        Ok(1)
105    }
106}
107
108impl<T> Pushable for Option<T>
109where
110    T: Pushable,
111{
112    unsafe fn push(self, lstate: *mut State) -> Result<c_int, crate::Error> {
113        match self {
114            Some(t) => t.push(lstate),
115            None => ().push(lstate),
116        }
117    }
118}
119
120impl<T> Pushable for Vec<T>
121where
122    T: Pushable,
123{
124    unsafe fn push(self, lstate: *mut State) -> Result<c_int, crate::Error> {
125        ffi::lua_createtable(lstate, self.len() as _, 0);
126
127        for (i, obj) in self.into_iter().enumerate() {
128            obj.push(lstate)?;
129            ffi::lua_rawseti(lstate, -2, (i + 1) as _);
130        }
131
132        Ok(1)
133    }
134}
135
136impl<T, E> Pushable for Result<T, E>
137where
138    T: Pushable,
139    E: core::fmt::Display,
140{
141    #[inline]
142    unsafe fn push(self, lstate: *mut State) -> Result<c_int, crate::Error> {
143        match self {
144            Ok(value) => value.push(lstate),
145            Err(err) => utils::push_error(&err, lstate),
146        }
147    }
148}
149/// Implements `LuaPushable` for a tuple `(a, b, c, ..)` where all the elements
150/// in the tuple implement `LuaPushable`.
151macro_rules! push_tuple {
152    ($($name:ident)*) => {
153        impl<$($name,)*> Pushable for ($($name,)*)
154        where
155            $($name: Pushable,)*
156        {
157            #[allow(non_snake_case)]
158            unsafe fn push(
159                self,
160                lstate: *mut State,
161            ) -> Result<c_int, crate::Error> {
162                let ($($name,)*) = self;
163                $($name.push(lstate)?;)*
164                Ok(count!($($name)*))
165            }
166        }
167    }
168}
169
170push_tuple!(A);
171push_tuple!(A B);
172push_tuple!(A B C);
173push_tuple!(A B C D);
174push_tuple!(A B C D E);
175push_tuple!(A B C D E F);
176push_tuple!(A B C D E F G);
177push_tuple!(A B C D E F G H);
178push_tuple!(A B C D E F G H I);
179push_tuple!(A B C D E F G H I J);
180push_tuple!(A B C D E F G H I J K);
181push_tuple!(A B C D E F G H I J K L);
182push_tuple!(A B C D E F G H I J K L M);
183push_tuple!(A B C D E F G H I J K L M N);
184push_tuple!(A B C D E F G H I J K L M N O);
185push_tuple!(A B C D E F G H I J K L M N O P);