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