use crate::error::{Error, Result};
use crate::state::{Lua, LuaRef};
use crate::sync::{NotSync, XRc, NOT_SYNC};
use crate::traits::{FromLua, IntoLua};
use crate::value::Value;
#[derive(Clone)]
pub struct RegistryKey {
pub(crate) reference: XRc<LuaRef>,
pub(crate) _not_sync: NotSync,
}
impl RegistryKey {
pub(crate) fn from_ref(reference: LuaRef) -> RegistryKey {
RegistryKey {
reference: XRc::new(reference),
_not_sync: NOT_SYNC,
}
}
pub(crate) fn push(&self) {
self.reference.push();
}
}
impl std::fmt::Debug for RegistryKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "RegistryKey({})", self.reference.id())
}
}
impl PartialEq for RegistryKey {
fn eq(&self, other: &Self) -> bool {
self.reference.state() == other.reference.state()
&& self.reference.id() == other.reference.id()
}
}
impl Eq for RegistryKey {}
impl std::hash::Hash for RegistryKey {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
(self.reference.state() as usize).hash(state);
self.reference.id().hash(state);
}
}
impl Lua {
pub fn create_registry_value(&self, value: impl IntoLua) -> Result<RegistryKey> {
let v = value.into_lua(self)?;
self.push_value(&v)?;
Ok(RegistryKey::from_ref(self.pop_ref()))
}
pub fn registry_value<T: FromLua>(&self, key: &RegistryKey) -> Result<T> {
if !self.owns_registry_value(key) {
return Err(Error::MismatchedRegistryKey);
}
let state = self.state();
let value = unsafe {
key.push();
let v = self.value_from_stack(-1)?;
crate::sys::lua_pop(state, 1);
v
};
T::from_lua(value, self)
}
pub fn remove_registry_value(&self, key: RegistryKey) -> Result<()> {
if !self.owns_registry_value(&key) {
return Err(Error::MismatchedRegistryKey);
}
drop(key);
Ok(())
}
pub fn replace_registry_value(&self, key: &mut RegistryKey, value: impl IntoLua) -> Result<()> {
if !self.owns_registry_value(key) {
return Err(Error::MismatchedRegistryKey);
}
*key = self.create_registry_value(value)?;
Ok(())
}
pub fn owns_registry_value(&self, key: &RegistryKey) -> bool {
key.reference.state() == self.state()
}
pub fn expire_registry_values(&self) {}
pub fn set_named_registry_value(&self, name: &str, value: impl IntoLua) -> Result<()> {
let v = value.into_lua(self)?;
let state = self.state();
let cname = std::ffi::CString::new(name)
.map_err(|_| Error::runtime("registry name contains a NUL byte"))?;
unsafe {
self.push_value(&v)?;
crate::sys::lua_setfield(state, crate::sys::LUA_REGISTRYINDEX, cname.as_ptr());
}
Ok(())
}
pub fn named_registry_value<T: FromLua>(&self, name: &str) -> Result<T> {
let state = self.state();
let cname = std::ffi::CString::new(name)
.map_err(|_| Error::runtime("registry name contains a NUL byte"))?;
let value = unsafe {
crate::sys::lua_getfield(state, crate::sys::LUA_REGISTRYINDEX, cname.as_ptr());
let v = self.value_from_stack(-1)?;
crate::sys::lua_pop(state, 1);
v
};
T::from_lua(value, self)
}
pub fn unset_named_registry_value(&self, name: &str) -> Result<()> {
self.set_named_registry_value(name, Value::Nil)
}
}
impl IntoLua for RegistryKey {
fn into_lua(self, lua: &Lua) -> Result<Value> {
(&self).into_lua(lua)
}
}
impl IntoLua for &RegistryKey {
fn into_lua(self, lua: &Lua) -> Result<Value> {
if self.reference.state() != lua.state() {
return Err(Error::MismatchedRegistryKey);
}
let state = lua.state();
unsafe {
self.push();
let v = lua.value_from_stack(-1)?;
crate::sys::lua_pop(state, 1);
Ok(v)
}
}
}
impl FromLua for RegistryKey {
fn from_lua(value: Value, lua: &Lua) -> Result<Self> {
lua.create_registry_value(value)
}
}