luajit_bindings/
poppable.rs1use std::collections::HashMap;
2use std::hash::Hash;
3
4use crate::ffi::*;
5use crate::macros::count;
6use crate::Error;
7
8pub trait Poppable: Sized {
10 unsafe fn pop(lua_state: *mut lua_State) -> Result<Self, Error>;
12}
13
14impl Poppable for () {
15 unsafe fn pop(state: *mut lua_State) -> Result<Self, crate::Error> {
16 if lua_gettop(state) == 0 {
17 return Ok(());
18 }
19
20 match lua_type(state, -1) {
21 LUA_TNIL => {
22 lua_pop(state, 1);
23 Ok(())
24 },
25 other => Err(Error::pop_wrong_type::<Self>(LUA_TNIL, other)),
26 }
27 }
28}
29
30impl Poppable for bool {
31 unsafe fn pop(state: *mut lua_State) -> Result<Self, Error> {
32 if lua_gettop(state) == 0 {
33 return Err(Error::PopEmptyStack);
34 }
35
36 match lua_type(state, -1) {
37 LUA_TBOOLEAN => {
38 let b = lua_toboolean(state, -1) == 1;
39 lua_pop(state, 1);
40 Ok(b)
41 },
42 other => Err(Error::pop_wrong_type::<Self>(LUA_TBOOLEAN, other)),
43 }
44 }
45}
46
47impl Poppable for lua_Integer {
48 unsafe fn pop(state: *mut lua_State) -> Result<Self, crate::Error> {
49 if lua_gettop(state) == 0 {
50 return Err(Error::PopEmptyStack);
51 }
52
53 match lua_type(state, -1) {
54 LUA_TNUMBER => {
55 let n = lua_tointeger(state, -1);
56 lua_pop(state, 1);
57 Ok(n)
58 },
59 other => Err(Error::pop_wrong_type::<Self>(LUA_TNUMBER, other)),
60 }
61 }
62}
63
64macro_rules! pop_try_from_integer {
67 ($integer:ty) => {
68 impl Poppable for $integer {
69 unsafe fn pop(
70 lstate: *mut lua_State,
71 ) -> Result<Self, crate::Error> {
72 lua_Integer::pop(lstate)?
73 .try_into()
74 .map_err(Error::pop_error_from_err::<Self, _>)
75 }
76 }
77 };
78}
79
80pop_try_from_integer!(i8);
81pop_try_from_integer!(u8);
82pop_try_from_integer!(i16);
83pop_try_from_integer!(u16);
84pop_try_from_integer!(i32);
85pop_try_from_integer!(u32);
86pop_try_from_integer!(i64);
87pop_try_from_integer!(u64);
88pop_try_from_integer!(usize);
89
90impl Poppable for lua_Number {
91 unsafe fn pop(state: *mut lua_State) -> Result<Self, crate::Error> {
92 if lua_gettop(state) == 0 {
93 return Err(Error::PopEmptyStack);
94 }
95
96 match lua_type(state, -1) {
97 LUA_TNUMBER => {
98 let n = lua_tonumber(state, -1);
99 lua_pop(state, 1);
100 Ok(n)
101 },
102 other => Err(Error::pop_wrong_type::<Self>(LUA_TNUMBER, other)),
103 }
104 }
105}
106
107impl Poppable for f32 {
108 unsafe fn pop(state: *mut lua_State) -> Result<Self, crate::Error> {
109 lua_Number::pop(state).map(|n| n as f32)
110 }
111}
112
113impl Poppable for String {
114 unsafe fn pop(state: *mut lua_State) -> Result<Self, Error> {
115 if lua_gettop(state) == 0 {
116 return Err(Error::PopEmptyStack);
117 }
118
119 match lua_type(state, -1) {
120 LUA_TSTRING | LUA_TNUMBER => {
121 let mut len = 0;
122 let ptr = lua_tolstring(state, -1, &mut len);
123
124 assert!(!ptr.is_null());
127
128 let slice = std::slice::from_raw_parts(ptr as *const u8, len);
129 let str = String::from_utf8_lossy(slice).to_string();
130
131 lua_pop(state, 1);
132
133 Ok(str)
134 },
135 other => Err(Error::pop_wrong_type::<Self>(LUA_TSTRING, other)),
136 }
137 }
138}
139
140impl<T> Poppable for Option<T>
141where
142 T: Poppable,
143{
144 unsafe fn pop(state: *mut lua_State) -> Result<Self, Error> {
145 if lua_gettop(state) == 0 {
146 return Err(Error::PopEmptyStack);
147 }
148
149 match lua_type(state, -1) {
150 LUA_TNIL => {
151 lua_pop(state, 1);
152 Ok(None)
153 },
154 _ => T::pop(state).map(Some),
155 }
156 }
157}
158
159impl<T> Poppable for Vec<T>
160where
161 T: Poppable,
162{
163 unsafe fn pop(state: *mut lua_State) -> Result<Self, Error> {
164 if lua_gettop(state) == 0 {
165 return Err(Error::PopEmptyStack);
166 }
167
168 match lua_type(state, -1) {
169 LUA_TTABLE => {
170 let mut vec = Vec::with_capacity(lua_objlen(state, -1));
174
175 lua_pushnil(state);
176
177 while lua_next(state, -2) != 0 {
178 vec.push(T::pop(state)?);
179 }
180
181 lua_pop(state, 1);
183
184 Ok(vec)
185 },
186
187 other => Err(Error::pop_wrong_type::<Self>(LUA_TTABLE, other)),
188 }
189 }
190}
191
192impl<K, V> Poppable for HashMap<K, V>
193where
194 K: Poppable + Eq + Hash,
195 V: Poppable,
196{
197 unsafe fn pop(state: *mut lua_State) -> Result<Self, Error> {
198 if lua_gettop(state) == 0 {
199 return Err(Error::PopEmptyStack);
200 }
201
202 match lua_type(state, -1) {
203 LUA_TTABLE => {
204 let mut map = HashMap::with_capacity(lua_objlen(state, -1));
208
209 lua_pushnil(state);
210
211 while lua_next(state, -2) != 0 {
212 let value = V::pop(state)?;
213
214 lua_pushvalue(state, -1);
218
219 let key = K::pop(state)?;
220
221 map.insert(key, value);
222 }
223
224 lua_pop(state, 1);
226
227 Ok(map)
228 },
229
230 other => Err(Error::pop_wrong_type::<Self>(LUA_TTABLE, other)),
231 }
232 }
233}
234
235macro_rules! pop_tuple {
238 ($($name:ident)*) => (
239 impl<$($name,)*> Poppable for ($($name,)*)
240 where
241 $($name: Poppable,)*
242 {
243 #[allow(non_snake_case)]
244 unsafe fn pop(state: *mut lua_State) -> Result<Self, crate::Error> {
245 crate::utils::grow_stack(state, count!($($name)*));
246 pop_reverse!(state, $($name)*);
247 Ok(($($name,)*))
248 }
249 }
250 );
251}
252
253macro_rules! pop_reverse {
254 ($lua_state:expr, $x:ident $($xs:ident)*) => {
255 pop_reverse!($lua_state, $($xs)*);
256 let $x = $x::pop($lua_state)?;
257 };
258
259 ($lstate:expr,) => ();
260}
261
262pop_tuple!(A);
263pop_tuple!(A B);
264pop_tuple!(A B C);
265pop_tuple!(A B C D);
266pop_tuple!(A B C D E);
267pop_tuple!(A B C D E F);
268pop_tuple!(A B C D E F G);
269pop_tuple!(A B C D E F G H);
270pop_tuple!(A B C D E F G H I);
271pop_tuple!(A B C D E F G H I J);
272pop_tuple!(A B C D E F G H I J K);
273pop_tuple!(A B C D E F G H I J K L);
274pop_tuple!(A B C D E F G H I J K L M);
275pop_tuple!(A B C D E F G H I J K L M N);
276pop_tuple!(A B C D E F G H I J K L M N O);
277pop_tuple!(A B C D E F G H I J K L M N O P);