1use std::marker::PhantomData;
2
3use libc;
4
5use td_clua::{self, lua_State};
6use LuaGuard;
7use LuaPush;
8use LuaRead;
9pub struct LuaTable {
13 table: *mut lua_State,
14 pop: i32,
15 index: i32,
16}
17
18impl LuaRead for LuaTable {
19 fn lua_read_with_pop(lua: *mut lua_State, index: i32, pop: i32) -> Option<LuaTable> {
20 if unsafe { td_clua::lua_istable(lua, index) } {
21 for _ in 0..pop {
22 unsafe {
23 td_clua::lua_pushnil(lua);
24 }
25 }
26 Some(LuaTable {
27 table: lua,
28 pop: pop,
29 index: index,
30 })
31 } else {
32 None
33 }
34 }
35}
36
37impl Drop for LuaTable {
38 fn drop(&mut self) {
39 if self.pop != 0 {
40 unsafe {
41 td_clua::lua_pop(self.table, self.pop);
42 };
43 self.pop = 0;
44 }
45 }
46}
47
48pub struct LuaTableIterator<'t, K, V> {
51 table: &'t mut LuaTable,
52 finished: bool, marker: PhantomData<(K, V)>,
54}
55
56impl LuaTable {
57 pub fn into_inner(self) -> *mut lua_State {
59 self.table
60 }
61
62 pub fn iter<K, V>(&mut self) -> LuaTableIterator<K, V> {
64 unsafe { td_clua::lua_pushnil(self.table) };
65
66 LuaTableIterator {
67 table: self,
68 finished: false,
69 marker: PhantomData,
70 }
71 }
72
73 pub fn query<'a, R, I>(&'a mut self, index: I) -> Option<R>
75 where
76 R: LuaRead,
77 I: LuaPush,
78 {
79 index.push_to_lua(self.table);
80 unsafe {
81 td_clua::lua_gettable(
82 self.table,
83 if self.index > 0 {
84 self.index
85 } else {
86 self.index - 1
87 },
88 );
89 }
90 let _guard = LuaGuard::new(self.table, 1);
91 LuaRead::lua_read_with_pop(self.table, -1, 1)
92 }
93
94 pub fn set<I, V>(&mut self, index: I, value: V)
96 where
97 I: LuaPush,
98 V: LuaPush,
99 {
100 index.push_to_lua(self.table);
101 value.push_to_lua(self.table);
102 unsafe {
103 td_clua::lua_settable(
104 self.table,
105 if self.index > 0 {
106 self.index
107 } else {
108 self.index - 2
109 },
110 );
111 }
112 }
113
114 pub fn register<I>(&mut self, index: I, func: extern "C" fn(*mut lua_State) -> libc::c_int)
116 where
117 I: LuaPush,
118 {
119 index.push_to_lua(self.table);
120 unsafe {
121 td_clua::lua_pushcfunction(self.table, func);
122 td_clua::lua_settable(
123 self.table,
124 if self.index > 0 {
125 self.index
126 } else {
127 self.index - 2
128 },
129 );
130 }
131 }
132
133 pub fn empty_table<I>(&mut self, index: I) -> LuaTable
135 where
136 I: LuaPush + Clone,
137 {
138 index.clone().push_to_lua(self.table);
139 unsafe {
140 td_clua::lua_newtable(self.table);
141 td_clua::lua_settable(
142 self.table,
143 if self.index > 0 {
144 self.index
145 } else {
146 self.index - 2
147 },
148 );
149 }
150 self.query(index).unwrap()
151 }
152
153 pub fn table_len(&mut self) -> usize {
154 unsafe { td_clua::lua_rawlen(self.table, self.index) }
155 }
156
157 pub fn get_or_create_metatable(&mut self) -> LuaTable {
159 let result = unsafe { td_clua::lua_getmetatable(self.table, self.index) };
160
161 if result == 0 {
162 unsafe {
163 td_clua::lua_newtable(self.table);
164 td_clua::lua_setmetatable(self.table, -2);
165 let r = td_clua::lua_getmetatable(self.table, self.index);
166 assert!(r != 0);
167 }
168 }
169
170 LuaTable {
171 table: self.table,
172 pop: 1,
173 index: -1,
174 }
175 }
176}
177
178impl<'t, K, V> Iterator for LuaTableIterator<'t, K, V>
179where
180 K: LuaRead + 'static,
181 V: LuaRead + 'static,
182{
183 type Item = Option<(K, V)>;
184
185 fn next(&mut self) -> Option<Option<(K, V)>> {
186 if self.finished {
187 return None;
188 }
189 let state = self.table.table;
190 if unsafe { !td_clua::lua_istable(state, -2) || td_clua::lua_next(state, -2) == 0 } {
192 self.finished = true;
193 return None;
194 }
195
196 let key = LuaRead::lua_read_at_position(state, -2);
197 let value = LuaRead::lua_read_at_position(state, -1);
198 unsafe { td_clua::lua_pop(state, 1) };
200
201 if key.is_none() || value.is_none() {
202 Some(None)
203 } else {
204 Some(Some((key.unwrap(), value.unwrap())))
205 }
206 }
207}
208
209impl<'t, K, V> Drop for LuaTableIterator<'t, K, V> {
210 fn drop(&mut self) {
211 if !self.finished {
212 unsafe { td_clua::lua_pop(self.table.table, 1) }
213 }
214 }
215}