nvim_oxi_luajit/
poppable.rs1use core::hash::Hash;
2use std::collections::HashMap;
3
4use crate::Error;
5use crate::ffi::*;
6use crate::macros::count;
7
8pub trait Poppable: Sized {
10 unsafe fn pop(lua_state: *mut State) -> Result<Self, Error>;
12}
13
14impl Poppable for () {
15 #[inline(always)]
16 unsafe fn pop(state: *mut 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 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 Integer {
46 unsafe fn pop(state: *mut 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(lstate: *mut State) -> Result<Self, crate::Error> {
68 Integer::pop(lstate)?
69 .try_into()
70 .map_err(Error::pop_error_from_err::<Self, _>)
71 }
72 }
73 };
74}
75
76pop_try_from_integer!(i8);
77pop_try_from_integer!(u8);
78pop_try_from_integer!(i16);
79pop_try_from_integer!(u16);
80pop_try_from_integer!(i32);
81pop_try_from_integer!(u32);
82pop_try_from_integer!(i64);
83pop_try_from_integer!(u64);
84pop_try_from_integer!(usize);
85
86impl Poppable for Number {
87 unsafe fn pop(state: *mut State) -> Result<Self, crate::Error> {
88 if lua_gettop(state) == 0 {
89 return Err(Error::PopEmptyStack);
90 }
91
92 match lua_type(state, -1) {
93 LUA_TNUMBER => {
94 let n = lua_tonumber(state, -1);
95 lua_pop(state, 1);
96 Ok(n)
97 },
98 other => Err(Error::pop_wrong_type::<Self>(LUA_TNUMBER, other)),
99 }
100 }
101}
102
103impl Poppable for f32 {
104 unsafe fn pop(state: *mut State) -> Result<Self, crate::Error> {
105 Number::pop(state).map(|n| n as f32)
106 }
107}
108
109impl Poppable for String {
110 unsafe fn pop(state: *mut State) -> Result<Self, Error> {
111 if lua_gettop(state) == 0 {
112 return Err(Error::PopEmptyStack);
113 }
114
115 match lua_type(state, -1) {
116 LUA_TSTRING | LUA_TNUMBER => {
117 let mut len = 0;
118 let ptr = lua_tolstring(state, -1, &mut len);
119
120 assert!(!ptr.is_null());
123
124 let slice = std::slice::from_raw_parts(ptr as *const u8, len);
125 let str = String::from_utf8_lossy(slice).to_string();
126
127 lua_pop(state, 1);
128
129 Ok(str)
130 },
131 other => Err(Error::pop_wrong_type::<Self>(LUA_TSTRING, other)),
132 }
133 }
134}
135
136impl<T> Poppable for Option<T>
137where
138 T: Poppable,
139{
140 unsafe fn pop(state: *mut State) -> Result<Self, Error> {
141 if lua_gettop(state) == 0 {
142 return Ok(None);
143 }
144
145 match lua_type(state, -1) {
146 LUA_TNIL => {
147 lua_pop(state, 1);
148 Ok(None)
149 },
150 _ => T::pop(state).map(Some),
151 }
152 }
153}
154
155impl<T> Poppable for Vec<T>
156where
157 T: Poppable,
158{
159 unsafe fn pop(state: *mut State) -> Result<Self, Error> {
160 if lua_gettop(state) == 0 {
161 return Err(Error::PopEmptyStack);
162 }
163
164 match lua_type(state, -1) {
165 LUA_TTABLE => {
166 let mut vec = Vec::with_capacity(lua_objlen(state, -1));
170
171 lua_pushnil(state);
172
173 while lua_next(state, -2) != 0 {
174 vec.push(T::pop(state)?);
175 }
176
177 lua_pop(state, 1);
179
180 Ok(vec)
181 },
182
183 other => Err(Error::pop_wrong_type::<Self>(LUA_TTABLE, other)),
184 }
185 }
186}
187
188impl<K, V> Poppable for HashMap<K, V>
189where
190 K: Poppable + Eq + Hash,
191 V: Poppable,
192{
193 unsafe fn pop(state: *mut State) -> Result<Self, Error> {
194 if lua_gettop(state) == 0 {
195 return Err(Error::PopEmptyStack);
196 }
197
198 match lua_type(state, -1) {
199 LUA_TTABLE => {
200 let mut map = HashMap::with_capacity(lua_objlen(state, -1));
204
205 lua_pushnil(state);
206
207 while lua_next(state, -2) != 0 {
208 let value = V::pop(state)?;
209
210 lua_pushvalue(state, -1);
214
215 let key = K::pop(state)?;
216
217 map.insert(key, value);
218 }
219
220 lua_pop(state, 1);
222
223 Ok(map)
224 },
225
226 other => Err(Error::pop_wrong_type::<Self>(LUA_TTABLE, other)),
227 }
228 }
229}
230
231macro_rules! pop_tuple {
234 ($($name:ident)*) => (
235 impl<$($name,)*> Poppable for ($($name,)*)
236 where
237 $($name: Poppable,)*
238 {
239 #[allow(non_snake_case)]
240 unsafe fn pop(state: *mut State) -> Result<Self, crate::Error> {
241 crate::utils::grow_stack(state, count!($($name)*));
242 pop_reverse!(state, $($name)*);
243 Ok(($($name,)*))
244 }
245 }
246 );
247}
248
249macro_rules! pop_reverse {
250 ($lua_state:expr, $x:ident $($xs:ident)*) => {
251 pop_reverse!($lua_state, $($xs)*);
252 let $x = $x::pop($lua_state)?;
253 };
254
255 ($lstate:expr,) => ();
256}
257
258pop_tuple!(A);
259pop_tuple!(A B);
260pop_tuple!(A B C);
261pop_tuple!(A B C D);
262pop_tuple!(A B C D E);
263pop_tuple!(A B C D E F);
264pop_tuple!(A B C D E F G);
265pop_tuple!(A B C D E F G H);
266pop_tuple!(A B C D E F G H I);
267pop_tuple!(A B C D E F G H I J);
268pop_tuple!(A B C D E F G H I J K);
269pop_tuple!(A B C D E F G H I J K L);
270pop_tuple!(A B C D E F G H I J K L M);
271pop_tuple!(A B C D E F G H I J K L M N);
272pop_tuple!(A B C D E F G H I J K L M N O);
273pop_tuple!(A B C D E F G H I J K L M N O P);