Skip to main content

mlua/types/
registry_key.rs

1use std::hash::{Hash, Hasher};
2use std::os::raw::c_int;
3use std::sync::Arc;
4use std::{fmt, mem, ptr};
5
6use parking_lot::Mutex;
7
8/// An auto generated key into the Lua registry.
9///
10/// This is a handle to a value stored inside the Lua registry. It is not automatically
11/// garbage collected on Drop, but it can be removed with [`Lua::remove_registry_value`],
12/// and instances not manually removed can be garbage collected with
13/// [`Lua::expire_registry_values`].
14///
15/// Be warned, If you place this into Lua via a [`UserData`] type or a Rust callback, it is *easy*
16/// to accidentally cause reference cycles that the Lua garbage collector cannot resolve. Instead of
17/// placing a [`RegistryKey`] into a [`UserData`] type, consider to use
18/// [`AnyUserData::set_user_value`].
19///
20/// [`UserData`]: crate::UserData
21/// [`RegistryKey`]: crate::RegistryKey
22/// [`Lua::remove_registry_value`]: crate::Lua::remove_registry_value
23/// [`Lua::expire_registry_values`]: crate::Lua::expire_registry_values
24/// [`AnyUserData::set_user_value`]: crate::AnyUserData::set_user_value
25pub struct RegistryKey {
26    pub(crate) registry_id: i32,
27    pub(crate) unref_list: Arc<Mutex<Option<Vec<c_int>>>>,
28}
29
30impl fmt::Debug for RegistryKey {
31    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32        write!(f, "RegistryKey({})", self.id())
33    }
34}
35
36impl Hash for RegistryKey {
37    fn hash<H: Hasher>(&self, state: &mut H) {
38        self.id().hash(state)
39    }
40}
41
42impl PartialEq for RegistryKey {
43    fn eq(&self, other: &RegistryKey) -> bool {
44        self.id() == other.id() && Arc::ptr_eq(&self.unref_list, &other.unref_list)
45    }
46}
47
48impl Eq for RegistryKey {}
49
50impl Drop for RegistryKey {
51    fn drop(&mut self) {
52        let registry_id = self.id();
53        // We don't need to collect nil slot
54        if registry_id > ffi::LUA_REFNIL {
55            let mut unref_list = self.unref_list.lock();
56            if let Some(list) = unref_list.as_mut() {
57                list.push(registry_id);
58            }
59        }
60    }
61}
62
63impl RegistryKey {
64    /// Creates a new instance of `RegistryKey`
65    pub(crate) const fn new(id: c_int, unref_list: Arc<Mutex<Option<Vec<c_int>>>>) -> Self {
66        RegistryKey {
67            registry_id: id,
68            unref_list,
69        }
70    }
71
72    /// Returns the underlying Lua reference of this `RegistryKey`
73    #[inline(always)]
74    pub fn id(&self) -> c_int {
75        self.registry_id
76    }
77
78    /// Sets the unique Lua reference key of this `RegistryKey`
79    #[inline(always)]
80    pub(crate) fn set_id(&mut self, id: c_int) {
81        self.registry_id = id;
82    }
83
84    /// Destroys the `RegistryKey` without adding to the unref list
85    pub(crate) fn take(self) -> i32 {
86        let registry_id = self.id();
87        unsafe {
88            ptr::read(&self.unref_list);
89            mem::forget(self);
90        }
91        registry_id
92    }
93}
94
95#[cfg(test)]
96mod assertions {
97    use super::*;
98
99    static_assertions::assert_impl_all!(RegistryKey: Send, Sync);
100}