factorio_mlua/
userdata_impl.rs

1use std::any::TypeId;
2use std::cell::{Ref, RefCell, RefMut};
3use std::marker::PhantomData;
4use std::sync::{Arc, Mutex, RwLock};
5
6use crate::error::{Error, Result};
7use crate::ffi;
8use crate::lua::Lua;
9use crate::types::{Callback, MaybeSend};
10use crate::userdata::{
11    AnyUserData, MetaMethod, UserData, UserDataCell, UserDataFields, UserDataMethods,
12};
13use crate::util::{check_stack, get_userdata, StackGuard};
14use crate::value::{FromLua, FromLuaMulti, ToLua, ToLuaMulti, Value};
15
16#[cfg(not(feature = "send"))]
17use std::rc::Rc;
18
19#[cfg(feature = "async")]
20use {
21    crate::types::AsyncCallback,
22    futures_core::future::Future,
23    futures_util::future::{self, TryFutureExt},
24};
25
26pub(crate) struct StaticUserDataMethods<'lua, T: 'static + UserData> {
27    pub(crate) methods: Vec<(Vec<u8>, Callback<'lua, 'static>)>,
28    #[cfg(feature = "async")]
29    pub(crate) async_methods: Vec<(Vec<u8>, AsyncCallback<'lua, 'static>)>,
30    pub(crate) meta_methods: Vec<(MetaMethod, Callback<'lua, 'static>)>,
31    #[cfg(feature = "async")]
32    pub(crate) async_meta_methods: Vec<(MetaMethod, AsyncCallback<'lua, 'static>)>,
33    _type: PhantomData<T>,
34}
35
36impl<'lua, T: 'static + UserData> Default for StaticUserDataMethods<'lua, T> {
37    fn default() -> StaticUserDataMethods<'lua, T> {
38        StaticUserDataMethods {
39            methods: Vec::new(),
40            #[cfg(feature = "async")]
41            async_methods: Vec::new(),
42            meta_methods: Vec::new(),
43            #[cfg(feature = "async")]
44            async_meta_methods: Vec::new(),
45            _type: PhantomData,
46        }
47    }
48}
49
50impl<'lua, T: 'static + UserData> UserDataMethods<'lua, T> for StaticUserDataMethods<'lua, T> {
51    fn add_method<S, A, R, M>(&mut self, name: &S, method: M)
52    where
53        S: AsRef<[u8]> + ?Sized,
54        A: FromLuaMulti<'lua>,
55        R: ToLuaMulti<'lua>,
56        M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>,
57    {
58        self.methods
59            .push((name.as_ref().to_vec(), Self::box_method(method)));
60    }
61
62    fn add_method_mut<S, A, R, M>(&mut self, name: &S, method: M)
63    where
64        S: AsRef<[u8]> + ?Sized,
65        A: FromLuaMulti<'lua>,
66        R: ToLuaMulti<'lua>,
67        M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
68    {
69        self.methods
70            .push((name.as_ref().to_vec(), Self::box_method_mut(method)));
71    }
72
73    #[cfg(feature = "async")]
74    fn add_async_method<S, A, R, M, MR>(&mut self, name: &S, method: M)
75    where
76        T: Clone,
77        S: AsRef<[u8]> + ?Sized,
78        A: FromLuaMulti<'lua>,
79        R: ToLuaMulti<'lua>,
80        M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
81        MR: 'lua + Future<Output = Result<R>>,
82    {
83        self.async_methods
84            .push((name.as_ref().to_vec(), Self::box_async_method(method)));
85    }
86
87    fn add_function<S, A, R, F>(&mut self, name: &S, function: F)
88    where
89        S: AsRef<[u8]> + ?Sized,
90        A: FromLuaMulti<'lua>,
91        R: ToLuaMulti<'lua>,
92        F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>,
93    {
94        self.methods
95            .push((name.as_ref().to_vec(), Self::box_function(function)));
96    }
97
98    fn add_function_mut<S, A, R, F>(&mut self, name: &S, function: F)
99    where
100        S: AsRef<[u8]> + ?Sized,
101        A: FromLuaMulti<'lua>,
102        R: ToLuaMulti<'lua>,
103        F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>,
104    {
105        self.methods
106            .push((name.as_ref().to_vec(), Self::box_function_mut(function)));
107    }
108
109    #[cfg(feature = "async")]
110    fn add_async_function<S, A, R, F, FR>(&mut self, name: &S, function: F)
111    where
112        S: AsRef<[u8]> + ?Sized,
113        A: FromLuaMulti<'lua>,
114        R: ToLuaMulti<'lua>,
115        F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
116        FR: 'lua + Future<Output = Result<R>>,
117    {
118        self.async_methods
119            .push((name.as_ref().to_vec(), Self::box_async_function(function)));
120    }
121
122    fn add_meta_method<S, A, R, M>(&mut self, meta: S, method: M)
123    where
124        S: Into<MetaMethod>,
125        A: FromLuaMulti<'lua>,
126        R: ToLuaMulti<'lua>,
127        M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>,
128    {
129        self.meta_methods
130            .push((meta.into(), Self::box_method(method)));
131    }
132
133    fn add_meta_method_mut<S, A, R, M>(&mut self, meta: S, method: M)
134    where
135        S: Into<MetaMethod>,
136        A: FromLuaMulti<'lua>,
137        R: ToLuaMulti<'lua>,
138        M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
139    {
140        self.meta_methods
141            .push((meta.into(), Self::box_method_mut(method)));
142    }
143
144    #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
145    fn add_async_meta_method<S, A, R, M, MR>(&mut self, meta: S, method: M)
146    where
147        T: Clone,
148        S: Into<MetaMethod>,
149        A: FromLuaMulti<'lua>,
150        R: ToLuaMulti<'lua>,
151        M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
152        MR: 'lua + Future<Output = Result<R>>,
153    {
154        self.async_meta_methods
155            .push((meta.into(), Self::box_async_method(method)));
156    }
157
158    fn add_meta_function<S, A, R, F>(&mut self, meta: S, function: F)
159    where
160        S: Into<MetaMethod>,
161        A: FromLuaMulti<'lua>,
162        R: ToLuaMulti<'lua>,
163        F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>,
164    {
165        self.meta_methods
166            .push((meta.into(), Self::box_function(function)));
167    }
168
169    fn add_meta_function_mut<S, A, R, F>(&mut self, meta: S, function: F)
170    where
171        S: Into<MetaMethod>,
172        A: FromLuaMulti<'lua>,
173        R: ToLuaMulti<'lua>,
174        F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>,
175    {
176        self.meta_methods
177            .push((meta.into(), Self::box_function_mut(function)));
178    }
179
180    #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
181    fn add_async_meta_function<S, A, R, F, FR>(&mut self, meta: S, function: F)
182    where
183        S: Into<MetaMethod>,
184        A: FromLuaMulti<'lua>,
185        R: ToLuaMulti<'lua>,
186        F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
187        FR: 'lua + Future<Output = Result<R>>,
188    {
189        self.async_meta_methods
190            .push((meta.into(), Self::box_async_function(function)));
191    }
192
193    // Below are internal methods used in generated code
194
195    fn add_callback(&mut self, name: Vec<u8>, callback: Callback<'lua, 'static>) {
196        self.methods.push((name, callback));
197    }
198
199    #[cfg(feature = "async")]
200    fn add_async_callback(&mut self, name: Vec<u8>, callback: AsyncCallback<'lua, 'static>) {
201        self.async_methods.push((name, callback));
202    }
203
204    fn add_meta_callback(&mut self, meta: MetaMethod, callback: Callback<'lua, 'static>) {
205        self.meta_methods.push((meta, callback));
206    }
207
208    #[cfg(feature = "async")]
209    fn add_async_meta_callback(
210        &mut self,
211        meta: MetaMethod,
212        callback: AsyncCallback<'lua, 'static>,
213    ) {
214        self.async_meta_methods.push((meta, callback))
215    }
216}
217
218impl<'lua, T: 'static + UserData> StaticUserDataMethods<'lua, T> {
219    fn box_method<A, R, M>(method: M) -> Callback<'lua, 'static>
220    where
221        A: FromLuaMulti<'lua>,
222        R: ToLuaMulti<'lua>,
223        M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>,
224    {
225        Box::new(move |lua, mut args| {
226            if let Some(front) = args.pop_front() {
227                let userdata = AnyUserData::from_lua(front, lua)?;
228                unsafe {
229                    let _sg = StackGuard::new(lua.state);
230                    check_stack(lua.state, 2)?;
231
232                    let type_id = lua.push_userdata_ref(&userdata.0)?;
233                    match type_id {
234                        Some(id) if id == TypeId::of::<T>() => {
235                            let ud = get_userdata_ref::<T>(lua.state)?;
236                            method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
237                        }
238                        #[cfg(not(feature = "send"))]
239                        Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => {
240                            let ud = get_userdata_ref::<Rc<RefCell<T>>>(lua.state)?;
241                            let ud = ud.try_borrow().map_err(|_| Error::UserDataBorrowError)?;
242                            method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
243                        }
244                        Some(id) if id == TypeId::of::<Arc<Mutex<T>>>() => {
245                            let ud = get_userdata_ref::<Arc<Mutex<T>>>(lua.state)?;
246                            let ud = ud.try_lock().map_err(|_| Error::UserDataBorrowError)?;
247                            method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
248                        }
249                        #[cfg(feature = "parking_lot")]
250                        Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => {
251                            let ud = get_userdata_ref::<Arc<parking_lot::Mutex<T>>>(lua.state)?;
252                            let ud = ud.try_lock().ok_or(Error::UserDataBorrowError)?;
253                            method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
254                        }
255                        Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => {
256                            let ud = get_userdata_ref::<Arc<RwLock<T>>>(lua.state)?;
257                            let ud = ud.try_read().map_err(|_| Error::UserDataBorrowError)?;
258                            method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
259                        }
260                        #[cfg(feature = "parking_lot")]
261                        Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => {
262                            let ud = get_userdata_ref::<Arc<parking_lot::RwLock<T>>>(lua.state)?;
263                            let ud = ud.try_read().ok_or(Error::UserDataBorrowError)?;
264                            method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
265                        }
266                        _ => Err(Error::UserDataTypeMismatch),
267                    }
268                }
269            } else {
270                Err(Error::FromLuaConversionError {
271                    from: "missing argument",
272                    to: "userdata",
273                    message: None,
274                })
275            }
276        })
277    }
278
279    fn box_method_mut<A, R, M>(method: M) -> Callback<'lua, 'static>
280    where
281        A: FromLuaMulti<'lua>,
282        R: ToLuaMulti<'lua>,
283        M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
284    {
285        let method = RefCell::new(method);
286        Box::new(move |lua, mut args| {
287            if let Some(front) = args.pop_front() {
288                let userdata = AnyUserData::from_lua(front, lua)?;
289                let mut method = method
290                    .try_borrow_mut()
291                    .map_err(|_| Error::RecursiveMutCallback)?;
292                unsafe {
293                    let _sg = StackGuard::new(lua.state);
294                    check_stack(lua.state, 2)?;
295
296                    let type_id = lua.push_userdata_ref(&userdata.0)?;
297                    match type_id {
298                        Some(id) if id == TypeId::of::<T>() => {
299                            let mut ud = get_userdata_mut::<T>(lua.state)?;
300                            method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
301                        }
302                        #[cfg(not(feature = "send"))]
303                        Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => {
304                            let ud = get_userdata_mut::<Rc<RefCell<T>>>(lua.state)?;
305                            let mut ud = ud
306                                .try_borrow_mut()
307                                .map_err(|_| Error::UserDataBorrowMutError)?;
308                            method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
309                        }
310                        Some(id) if id == TypeId::of::<Arc<Mutex<T>>>() => {
311                            let ud = get_userdata_mut::<Arc<Mutex<T>>>(lua.state)?;
312                            let mut ud =
313                                ud.try_lock().map_err(|_| Error::UserDataBorrowMutError)?;
314                            method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
315                        }
316                        #[cfg(feature = "parking_lot")]
317                        Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => {
318                            let ud = get_userdata_mut::<Arc<parking_lot::Mutex<T>>>(lua.state)?;
319                            let mut ud = ud.try_lock().ok_or(Error::UserDataBorrowMutError)?;
320                            method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
321                        }
322                        Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => {
323                            let ud = get_userdata_mut::<Arc<RwLock<T>>>(lua.state)?;
324                            let mut ud =
325                                ud.try_write().map_err(|_| Error::UserDataBorrowMutError)?;
326                            method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
327                        }
328                        #[cfg(feature = "parking_lot")]
329                        Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => {
330                            let ud = get_userdata_mut::<Arc<parking_lot::RwLock<T>>>(lua.state)?;
331                            let mut ud = ud.try_write().ok_or(Error::UserDataBorrowMutError)?;
332                            method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
333                        }
334                        _ => Err(Error::UserDataTypeMismatch),
335                    }
336                }
337            } else {
338                Err(Error::FromLuaConversionError {
339                    from: "missing argument",
340                    to: "userdata",
341                    message: None,
342                })
343            }
344        })
345    }
346
347    #[cfg(feature = "async")]
348    fn box_async_method<A, R, M, MR>(method: M) -> AsyncCallback<'lua, 'static>
349    where
350        T: Clone,
351        A: FromLuaMulti<'lua>,
352        R: ToLuaMulti<'lua>,
353        M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
354        MR: 'lua + Future<Output = Result<R>>,
355    {
356        Box::new(move |lua, mut args| {
357            let fut_res = || {
358                if let Some(front) = args.pop_front() {
359                    let userdata = AnyUserData::from_lua(front, lua)?;
360                    unsafe {
361                        let _sg = StackGuard::new(lua.state);
362                        check_stack(lua.state, 2)?;
363
364                        let type_id = lua.push_userdata_ref(&userdata.0)?;
365                        match type_id {
366                            Some(id) if id == TypeId::of::<T>() => {
367                                let ud = get_userdata_ref::<T>(lua.state)?;
368                                Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
369                            }
370                            #[cfg(not(feature = "send"))]
371                            Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => {
372                                let ud = get_userdata_ref::<Rc<RefCell<T>>>(lua.state)?;
373                                let ud = ud.try_borrow().map_err(|_| Error::UserDataBorrowError)?;
374                                Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
375                            }
376                            Some(id) if id == TypeId::of::<Arc<Mutex<T>>>() => {
377                                let ud = get_userdata_ref::<Arc<Mutex<T>>>(lua.state)?;
378                                let ud = ud.try_lock().map_err(|_| Error::UserDataBorrowError)?;
379                                Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
380                            }
381                            #[cfg(feature = "parking_lot")]
382                            Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => {
383                                let ud = get_userdata_ref::<Arc<parking_lot::Mutex<T>>>(lua.state)?;
384                                let ud = ud.try_lock().ok_or(Error::UserDataBorrowError)?;
385                                Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
386                            }
387                            Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => {
388                                let ud = get_userdata_ref::<Arc<RwLock<T>>>(lua.state)?;
389                                let ud = ud.try_read().map_err(|_| Error::UserDataBorrowError)?;
390                                Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
391                            }
392                            #[cfg(feature = "parking_lot")]
393                            Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => {
394                                let ud =
395                                    get_userdata_ref::<Arc<parking_lot::RwLock<T>>>(lua.state)?;
396                                let ud = ud.try_read().ok_or(Error::UserDataBorrowError)?;
397                                Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
398                            }
399                            _ => Err(Error::UserDataTypeMismatch),
400                        }
401                    }
402                } else {
403                    Err(Error::FromLuaConversionError {
404                        from: "missing argument",
405                        to: "userdata",
406                        message: None,
407                    })
408                }
409            };
410            match fut_res() {
411                Ok(fut) => Box::pin(fut.and_then(move |ret| future::ready(ret.to_lua_multi(lua)))),
412                Err(e) => Box::pin(future::err(e)),
413            }
414        })
415    }
416
417    fn box_function<A, R, F>(function: F) -> Callback<'lua, 'static>
418    where
419        A: FromLuaMulti<'lua>,
420        R: ToLuaMulti<'lua>,
421        F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>,
422    {
423        Box::new(move |lua, args| function(lua, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua))
424    }
425
426    fn box_function_mut<A, R, F>(function: F) -> Callback<'lua, 'static>
427    where
428        A: FromLuaMulti<'lua>,
429        R: ToLuaMulti<'lua>,
430        F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>,
431    {
432        let function = RefCell::new(function);
433        Box::new(move |lua, args| {
434            let function = &mut *function
435                .try_borrow_mut()
436                .map_err(|_| Error::RecursiveMutCallback)?;
437            function(lua, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
438        })
439    }
440
441    #[cfg(feature = "async")]
442    fn box_async_function<A, R, F, FR>(function: F) -> AsyncCallback<'lua, 'static>
443    where
444        A: FromLuaMulti<'lua>,
445        R: ToLuaMulti<'lua>,
446        F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
447        FR: 'lua + Future<Output = Result<R>>,
448    {
449        Box::new(move |lua, args| {
450            let args = match A::from_lua_multi(args, lua) {
451                Ok(args) => args,
452                Err(e) => return Box::pin(future::err(e)),
453            };
454            Box::pin(function(lua, args).and_then(move |ret| future::ready(ret.to_lua_multi(lua))))
455        })
456    }
457}
458
459pub(crate) struct StaticUserDataFields<'lua, T: 'static + UserData> {
460    pub(crate) field_getters: Vec<(Vec<u8>, Callback<'lua, 'static>)>,
461    pub(crate) field_setters: Vec<(Vec<u8>, Callback<'lua, 'static>)>,
462    #[allow(clippy::type_complexity)]
463    pub(crate) meta_fields: Vec<(
464        MetaMethod,
465        Box<dyn Fn(&'lua Lua) -> Result<Value<'lua>> + 'static>,
466    )>,
467    _type: PhantomData<T>,
468}
469
470impl<'lua, T: 'static + UserData> Default for StaticUserDataFields<'lua, T> {
471    fn default() -> StaticUserDataFields<'lua, T> {
472        StaticUserDataFields {
473            field_getters: Vec::new(),
474            field_setters: Vec::new(),
475            meta_fields: Vec::new(),
476            _type: PhantomData,
477        }
478    }
479}
480
481impl<'lua, T: 'static + UserData> UserDataFields<'lua, T> for StaticUserDataFields<'lua, T> {
482    fn add_field_method_get<S, R, M>(&mut self, name: &S, method: M)
483    where
484        S: AsRef<[u8]> + ?Sized,
485        R: ToLua<'lua>,
486        M: 'static + MaybeSend + Fn(&'lua Lua, &T) -> Result<R>,
487    {
488        self.field_getters.push((
489            name.as_ref().to_vec(),
490            StaticUserDataMethods::box_method(move |lua, data, ()| method(lua, data)),
491        ));
492    }
493
494    fn add_field_method_set<S, A, M>(&mut self, name: &S, method: M)
495    where
496        S: AsRef<[u8]> + ?Sized,
497        A: FromLua<'lua>,
498        M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<()>,
499    {
500        self.field_setters.push((
501            name.as_ref().to_vec(),
502            StaticUserDataMethods::box_method_mut(method),
503        ));
504    }
505
506    fn add_field_function_get<S, R, F>(&mut self, name: &S, function: F)
507    where
508        S: AsRef<[u8]> + ?Sized,
509        R: ToLua<'lua>,
510        F: 'static + MaybeSend + Fn(&'lua Lua, AnyUserData<'lua>) -> Result<R>,
511    {
512        self.field_getters.push((
513            name.as_ref().to_vec(),
514            StaticUserDataMethods::<T>::box_function(function),
515        ));
516    }
517
518    fn add_field_function_set<S, A, F>(&mut self, name: &S, mut function: F)
519    where
520        S: AsRef<[u8]> + ?Sized,
521        A: FromLua<'lua>,
522        F: 'static + MaybeSend + FnMut(&'lua Lua, AnyUserData<'lua>, A) -> Result<()>,
523    {
524        self.field_setters.push((
525            name.as_ref().to_vec(),
526            StaticUserDataMethods::<T>::box_function_mut(move |lua, (data, val)| {
527                function(lua, data, val)
528            }),
529        ));
530    }
531
532    fn add_meta_field_with<S, R, F>(&mut self, meta: S, f: F)
533    where
534        S: Into<MetaMethod>,
535        R: ToLua<'lua>,
536        F: 'static + MaybeSend + Fn(&'lua Lua) -> Result<R>,
537    {
538        let meta = meta.into();
539        self.meta_fields.push((
540            meta.clone(),
541            Box::new(move |lua| {
542                let value = f(lua)?.to_lua(lua)?;
543                if meta == MetaMethod::Index || meta == MetaMethod::NewIndex {
544                    match value {
545                        Value::Nil | Value::Table(_) | Value::Function(_) => {}
546                        _ => {
547                            return Err(Error::MetaMethodTypeError {
548                                method: meta.to_string(),
549                                type_name: value.type_name(),
550                                message: Some("expected nil, table or function".to_string()),
551                            })
552                        }
553                    }
554                }
555                Ok(value)
556            }),
557        ));
558    }
559
560    // Below are internal methods
561
562    fn add_field_getter(&mut self, name: Vec<u8>, callback: Callback<'lua, 'static>) {
563        self.field_getters.push((name, callback));
564    }
565
566    fn add_field_setter(&mut self, name: Vec<u8>, callback: Callback<'lua, 'static>) {
567        self.field_setters.push((name, callback));
568    }
569}
570
571#[inline]
572unsafe fn get_userdata_ref<'a, T>(state: *mut ffi::lua_State) -> Result<Ref<'a, T>> {
573    (*get_userdata::<UserDataCell<T>>(state, -1)).try_borrow()
574}
575
576#[inline]
577unsafe fn get_userdata_mut<'a, T>(state: *mut ffi::lua_State) -> Result<RefMut<'a, T>> {
578    (*get_userdata::<UserDataCell<T>>(state, -1)).try_borrow_mut()
579}
580
581macro_rules! lua_userdata_impl {
582    ($type:ty) => {
583        impl<T: 'static + UserData> UserData for $type {
584            fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {
585                let mut orig_fields = StaticUserDataFields::default();
586                T::add_fields(&mut orig_fields);
587                for (name, callback) in orig_fields.field_getters {
588                    fields.add_field_getter(name, callback);
589                }
590                for (name, callback) in orig_fields.field_setters {
591                    fields.add_field_setter(name, callback);
592                }
593            }
594
595            fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
596                let mut orig_methods = StaticUserDataMethods::default();
597                T::add_methods(&mut orig_methods);
598                for (name, callback) in orig_methods.methods {
599                    methods.add_callback(name, callback);
600                }
601                #[cfg(feature = "async")]
602                for (name, callback) in orig_methods.async_methods {
603                    methods.add_async_callback(name, callback);
604                }
605                for (meta, callback) in orig_methods.meta_methods {
606                    methods.add_meta_callback(meta, callback);
607                }
608                #[cfg(feature = "async")]
609                for (meta, callback) in orig_methods.async_meta_methods {
610                    methods.add_async_meta_callback(meta, callback);
611                }
612            }
613        }
614    };
615}
616
617#[cfg(not(feature = "send"))]
618lua_userdata_impl!(Rc<RefCell<T>>);
619lua_userdata_impl!(Arc<Mutex<T>>);
620lua_userdata_impl!(Arc<RwLock<T>>);
621#[cfg(feature = "parking_lot")]
622lua_userdata_impl!(Arc<parking_lot::Mutex<T>>);
623#[cfg(feature = "parking_lot")]
624lua_userdata_impl!(Arc<parking_lot::RwLock<T>>);