luajit_bindings/
pushable.rs

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