hlua_badtouch/
userdata.rs1use std::any::{Any, TypeId};
2use std::marker::PhantomData;
3use std::ops::{Deref, DerefMut};
4use std::mem;
5use std::ptr;
6
7use ffi;
8use libc;
9
10use AsLua;
11use AsMutLua;
12use Push;
13use PushGuard;
14use LuaContext;
15use LuaRead;
16
17use InsideCallback;
18use LuaTable;
19
20#[inline]
22extern "C" fn destructor_wrapper<T>(lua: *mut ffi::lua_State) -> libc::c_int {
23 unsafe {
24 let obj = ffi::lua_touserdata(lua, -1);
25 ptr::drop_in_place(obj as *mut TypeId);
26 ptr::drop_in_place((obj as *mut u8).offset(mem::size_of::<TypeId>() as isize) as *mut T);
27 0
28 }
29}
30
31#[inline]
55pub fn push_userdata<'lua, L, T, F>(data: T, mut lua: L, metatable: F) -> PushGuard<L>
56 where F: FnOnce(LuaTable<&mut PushGuard<&mut L>>),
57 L: AsMutLua<'lua>,
58 T: Send + 'static + Any
59{
60 unsafe {
61 let typeid = TypeId::of::<T>();
62
63 let lua_data = {
64 let tot_size = mem::size_of_val(&typeid) + mem::size_of_val(&data);
65 ffi::lua_newuserdata(lua.as_mut_lua().0, tot_size as libc::size_t)
66 };
67
68 debug_assert_eq!(lua_data as usize % mem::align_of_val(&data), 0);
70 debug_assert_eq!(mem::size_of_val(&typeid) % mem::align_of_val(&data), 0);
73
74 ptr::write(lua_data as *mut TypeId, typeid);
76 let data_loc = (lua_data as *const u8).offset(mem::size_of_val(&typeid) as isize);
77 ptr::write(data_loc as *mut _, data);
78
79 let lua_raw = lua.as_mut_lua();
80
81 ffi::lua_newtable(lua.as_mut_lua().0);
83
84 {
90 match "__gc".push_to_lua(&mut lua) {
91 Ok(p) => p.forget(),
92 Err(_) => unreachable!(),
93 };
94
95 ffi::lua_pushcfunction(lua.as_mut_lua().0, destructor_wrapper::<T>);
96 ffi::lua_settable(lua.as_mut_lua().0, -3);
97 }
98
99 {
101 let raw_lua = lua.as_lua();
102 let mut guard = PushGuard {
103 lua: &mut lua,
104 size: 1,
105 raw_lua: raw_lua,
106 };
107 metatable(LuaRead::lua_read(&mut guard).ok().unwrap());
108 guard.forget();
109 }
110
111 ffi::lua_setmetatable(lua_raw.0, -2);
112 }
113
114 let raw_lua = lua.as_lua();
115 PushGuard {
116 lua: lua,
117 size: 1,
118 raw_lua: raw_lua,
119 }
120}
121
122#[inline]
124pub fn read_userdata<'t, 'c, T>(lua: &'c mut InsideCallback,
125 index: i32)
126 -> Result<&'t mut T, &'c mut InsideCallback>
127 where T: 'static + Any
128{
129 unsafe {
130 let data_ptr = ffi::lua_touserdata(lua.as_lua().0, index);
131 if data_ptr.is_null() {
132 return Err(lua);
133 }
134
135 let actual_typeid = data_ptr as *const TypeId;
136 if *actual_typeid != TypeId::of::<T>() {
137 return Err(lua);
138 }
139
140 let data = (data_ptr as *const u8).offset(mem::size_of::<TypeId>() as isize);
141 Ok(&mut *(data as *mut T))
142 }
143}
144
145#[derive(Debug)]
147pub struct UserdataOnStack<T, L> {
148 variable: L,
149 index: i32,
150 marker: PhantomData<T>,
151}
152
153impl<'lua, T, L> LuaRead<L> for UserdataOnStack<T, L>
154 where L: AsMutLua<'lua>,
155 T: 'lua + Any
156{
157 #[inline]
158 fn lua_read_at_position(lua: L, index: i32) -> Result<UserdataOnStack<T, L>, L> {
159 unsafe {
160 let data_ptr = ffi::lua_touserdata(lua.as_lua().0, index);
161 if data_ptr.is_null() {
162 return Err(lua);
163 }
164
165 let actual_typeid = data_ptr as *const TypeId;
166 if *actual_typeid != TypeId::of::<T>() {
167 return Err(lua);
168 }
169
170 Ok(UserdataOnStack {
171 variable: lua,
172 index: index,
173 marker: PhantomData,
174 })
175 }
176 }
177}
178
179unsafe impl<'lua, T, L> AsLua<'lua> for UserdataOnStack<T, L>
180 where L: AsLua<'lua>,
181 T: 'lua + Any
182{
183 #[inline]
184 fn as_lua(&self) -> LuaContext {
185 self.variable.as_lua()
186 }
187}
188
189unsafe impl<'lua, T, L> AsMutLua<'lua> for UserdataOnStack<T, L>
190 where L: AsMutLua<'lua>,
191 T: 'lua + Any
192{
193 #[inline]
194 fn as_mut_lua(&mut self) -> LuaContext {
195 self.variable.as_mut_lua()
196 }
197}
198
199impl<'lua, T, L> Deref for UserdataOnStack<T, L>
200 where L: AsLua<'lua>,
201 T: 'lua + Any
202{
203 type Target = T;
204
205 #[inline]
206 fn deref(&self) -> &T {
207 unsafe {
208 let base = ffi::lua_touserdata(self.variable.as_lua().0, self.index);
209 let data = (base as *const u8).offset(mem::size_of::<TypeId>() as isize);
210 &*(data as *const T)
211 }
212 }
213}
214
215impl<'lua, T, L> DerefMut for UserdataOnStack<T, L>
216 where L: AsMutLua<'lua>,
217 T: 'lua + Any
218{
219 #[inline]
220 fn deref_mut(&mut self) -> &mut T {
221 unsafe {
222 let base = ffi::lua_touserdata(self.variable.as_mut_lua().0, self.index);
223 let data = (base as *const u8).offset(mem::size_of::<TypeId>() as isize);
224 &mut *(data as *mut T)
225 }
226 }
227}