Something went wrong. Try again.
Personal fork of prime agent. Mirror of: https://mnemosyne.sigilzero.dev/sigilzero/prime-agent
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680#![allow(clippy::await_holding_refcell_ref, clippy::await_holding_lock)]
use std::any::TypeId;use std::cell::RefCell;use std::marker::PhantomData;use std::os::raw::c_void;use std::string::String as StdString;
use crate::error::{Error, Result};use crate::state::{Lua, LuaGuard};use crate::traits::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti};use crate::types::{Callback, MaybeSend};use crate::userdata::{ borrow_userdata_scoped, borrow_userdata_scoped_mut, AnyUserData, MetaMethod, TypeIdHints, UserData, UserDataFields, UserDataMethods, UserDataStorage,};use crate::util::short_type_name;use crate::value::Value;
#[cfg(feature = "async")]use { crate::types::AsyncCallback, crate::userdata::{UserDataRef, UserDataRefMut}, std::future::{self, Future},};
#[derive(Clone, Copy)]enum UserDataType { Shared(TypeIdHints), Unique(*mut c_void),}
/// Handle to registry for userdata methods and metamethods.pub struct UserDataRegistry<T> { lua: LuaGuard, raw: RawUserDataRegistry, r#type: UserDataType, _phantom: PhantomData<T>,}
pub(crate) struct RawUserDataRegistry { // Fields pub(crate) fields: Vec<(String, Result<Value>)>, pub(crate) field_getters: Vec<(String, Callback)>, pub(crate) field_setters: Vec<(String, Callback)>, pub(crate) meta_fields: Vec<(String, Result<Value>)>,
// Methods pub(crate) methods: Vec<(String, Callback)>, #[cfg(feature = "async")] pub(crate) async_methods: Vec<(String, AsyncCallback)>, pub(crate) meta_methods: Vec<(String, Callback)>, #[cfg(feature = "async")] pub(crate) async_meta_methods: Vec<(String, AsyncCallback)>,
pub(crate) destructor: ffi::lua_CFunction, pub(crate) type_id: Option<TypeId>, pub(crate) type_name: StdString,
#[cfg(feature = "luau")] pub(crate) enable_namecall: bool,}
impl UserDataType { #[inline] pub(crate) fn type_id(&self) -> Option<TypeId> { match self { UserDataType::Shared(hints) => Some(hints.type_id()), UserDataType::Unique(_) => None, } }}
#[cfg(feature = "send")]unsafe impl Send for UserDataType {}
impl<T: 'static> UserDataRegistry<T> { #[inline(always)] pub(crate) fn new(lua: &Lua) -> Self { Self::with_type(lua, UserDataType::Shared(TypeIdHints::new::<T>())) }}
impl<T> UserDataRegistry<T> { #[inline(always)] pub(crate) fn new_unique(lua: &Lua, ud_ptr: *mut c_void) -> Self { Self::with_type(lua, UserDataType::Unique(ud_ptr)) }
#[inline(always)] fn with_type(lua: &Lua, r#type: UserDataType) -> Self { let raw = RawUserDataRegistry { fields: Vec::new(), field_getters: Vec::new(), field_setters: Vec::new(), meta_fields: Vec::new(), methods: Vec::new(), #[cfg(feature = "async")] async_methods: Vec::new(), meta_methods: Vec::new(), #[cfg(feature = "async")] async_meta_methods: Vec::new(), destructor: super::util::destroy_userdata_storage::<T>, type_id: r#type.type_id(), type_name: short_type_name::<T>(), #[cfg(feature = "luau")] enable_namecall: false, };
UserDataRegistry { lua: lua.lock_arc(), raw, r#type, _phantom: PhantomData, } }
/// Enables support for the namecall optimization in Luau. /// /// This enables methods resolution optimization in Luau for complex userdata types with methods /// and field getters. When enabled, Luau will use a faster lookup path for method calls when a /// specific syntax is used (e.g. `obj:method()`. /// /// This optimization does not play well with async methods, custom `__index` metamethod and /// field getters as functions. So, it is disabled by default. /// /// Use with caution. #[doc(hidden)] #[cfg(feature = "luau")] #[cfg_attr(docsrs, doc(cfg(feature = "luau")))] pub fn enable_namecall(&mut self) { self.raw.enable_namecall = true; }
fn box_method<M, A, R>(&self, name: &str, method: M) -> Callback where M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static, A: FromLuaMulti, R: IntoLuaMulti, { let name = get_function_name::<T>(name); macro_rules! try_self_arg { ($res:expr) => { $res.map_err(|err| Error::bad_self_argument(&name, err))? }; }
let target_type = self.r#type; Box::new(move |rawlua, nargs| unsafe { if nargs == 0 { let err = Error::from_lua_conversion("missing argument", "userdata", None); try_self_arg!(Err(err)); } let state = rawlua.state(); // Find absolute "self" index before processing args let self_index = ffi::lua_absindex(state, -nargs); // Self was at position 1, so we pass 2 here let args = A::from_stack_args(nargs - 1, 2, Some(&name), rawlua);
match target_type { #[rustfmt::skip] UserDataType::Shared(type_hints) => { let type_id = try_self_arg!(rawlua.get_userdata_type_id::<T>(state, self_index)); try_self_arg!(borrow_userdata_scoped(state, self_index, type_id, type_hints, |ud| { method(rawlua.lua(), ud, args?)?.push_into_stack_multi(rawlua) })) } UserDataType::Unique(target_ptr) if ffi::lua_touserdata(state, self_index) == target_ptr => { let ud = target_ptr as *mut UserDataStorage<T>; try_self_arg!((*ud).try_borrow_scoped(|ud| { method(rawlua.lua(), ud, args?)?.push_into_stack_multi(rawlua) })) } UserDataType::Unique(_) => { try_self_arg!(rawlua.get_userdata_type_id::<T>(state, self_index)); Err(Error::bad_self_argument(&name, Error::UserDataTypeMismatch)) } } }) }
fn box_method_mut<M, A, R>(&self, name: &str, method: M) -> Callback where M: FnMut(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static, A: FromLuaMulti, R: IntoLuaMulti, { let name = get_function_name::<T>(name); macro_rules! try_self_arg { ($res:expr) => { $res.map_err(|err| Error::bad_self_argument(&name, err))? }; }
let method = RefCell::new(method); let target_type = self.r#type; Box::new(move |rawlua, nargs| unsafe { let mut method = method.try_borrow_mut().map_err(|_| Error::RecursiveMutCallback)?; if nargs == 0 { let err = Error::from_lua_conversion("missing argument", "userdata", None); try_self_arg!(Err(err)); } let state = rawlua.state(); // Find absolute "self" index before processing args let self_index = ffi::lua_absindex(state, -nargs); // Self was at position 1, so we pass 2 here let args = A::from_stack_args(nargs - 1, 2, Some(&name), rawlua);
match target_type { #[rustfmt::skip] UserDataType::Shared(type_hints) => { let type_id = try_self_arg!(rawlua.get_userdata_type_id::<T>(state, self_index)); try_self_arg!(borrow_userdata_scoped_mut(state, self_index, type_id, type_hints, |ud| { method(rawlua.lua(), ud, args?)?.push_into_stack_multi(rawlua) })) } UserDataType::Unique(target_ptr) if ffi::lua_touserdata(state, self_index) == target_ptr => { let ud = target_ptr as *mut UserDataStorage<T>; try_self_arg!((*ud).try_borrow_scoped_mut(|ud| { method(rawlua.lua(), ud, args?)?.push_into_stack_multi(rawlua) })) } UserDataType::Unique(_) => { try_self_arg!(rawlua.get_userdata_type_id::<T>(state, self_index)); Err(Error::bad_self_argument(&name, Error::UserDataTypeMismatch)) } } }) }
#[cfg(feature = "async")] fn box_async_method<M, A, MR, R>(&self, name: &str, method: M) -> AsyncCallback where T: 'static, M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static, A: FromLuaMulti, MR: Future<Output = Result<R>> + MaybeSend + 'static, R: IntoLuaMulti, { let name = get_function_name::<T>(name); macro_rules! try_self_arg { ($res:expr) => { match $res { Ok(res) => res, Err(err) => return Box::pin(future::ready(Err(Error::bad_self_argument(&name, err)))), } }; }
Box::new(move |rawlua, nargs| unsafe { if nargs == 0 { let err = Error::from_lua_conversion("missing argument", "userdata", None); try_self_arg!(Err(err)); } // Stack will be empty when polling the future, keep `self` on the ref thread let self_ud = try_self_arg!(AnyUserData::from_stack(-nargs, rawlua)); let args = A::from_stack_args(nargs - 1, 2, Some(&name), rawlua);
let self_ud = try_self_arg!(self_ud.borrow()); let args = match args { Ok(args) => args, Err(e) => return Box::pin(future::ready(Err(e))), }; let lua = rawlua.lua(); let fut = method(lua.clone(), self_ud, args); // Lua is locked when the future is polled Box::pin(async move { fut.await?.push_into_stack_multi(lua.raw_lua()) }) }) }
#[cfg(feature = "async")] fn box_async_method_mut<M, A, MR, R>(&self, name: &str, method: M) -> AsyncCallback where T: 'static, M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static, A: FromLuaMulti, MR: Future<Output = Result<R>> + MaybeSend + 'static, R: IntoLuaMulti, { let name = get_function_name::<T>(name); macro_rules! try_self_arg { ($res:expr) => { match $res { Ok(res) => res, Err(err) => return Box::pin(future::ready(Err(Error::bad_self_argument(&name, err)))), } }; }
Box::new(move |rawlua, nargs| unsafe { if nargs == 0 { let err = Error::from_lua_conversion("missing argument", "userdata", None); try_self_arg!(Err(err)); } // Stack will be empty when polling the future, keep `self` on the ref thread let self_ud = try_self_arg!(AnyUserData::from_stack(-nargs, rawlua)); let args = A::from_stack_args(nargs - 1, 2, Some(&name), rawlua);
let self_ud = try_self_arg!(self_ud.borrow_mut()); let args = match args { Ok(args) => args, Err(e) => return Box::pin(future::ready(Err(e))), }; let lua = rawlua.lua(); let fut = method(lua.clone(), self_ud, args); // Lua is locked when the future is polled Box::pin(async move { fut.await?.push_into_stack_multi(lua.raw_lua()) }) }) }
fn box_function<F, A, R>(&self, name: &str, function: F) -> Callback where F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static, A: FromLuaMulti, R: IntoLuaMulti, { let name = get_function_name::<T>(name); Box::new(move |lua, nargs| unsafe { let args = A::from_stack_args(nargs, 1, Some(&name), lua)?; function(lua.lua(), args)?.push_into_stack_multi(lua) }) }
fn box_function_mut<F, A, R>(&self, name: &str, function: F) -> Callback where F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static, A: FromLuaMulti, R: IntoLuaMulti, { let name = get_function_name::<T>(name); let function = RefCell::new(function); Box::new(move |lua, nargs| unsafe { let function = &mut *function .try_borrow_mut() .map_err(|_| Error::RecursiveMutCallback)?; let args = A::from_stack_args(nargs, 1, Some(&name), lua)?; function(lua.lua(), args)?.push_into_stack_multi(lua) }) }
#[cfg(feature = "async")] fn box_async_function<F, A, FR, R>(&self, name: &str, function: F) -> AsyncCallback where F: Fn(Lua, A) -> FR + MaybeSend + 'static, A: FromLuaMulti, FR: Future<Output = Result<R>> + MaybeSend + 'static, R: IntoLuaMulti, { let name = get_function_name::<T>(name); Box::new(move |rawlua, nargs| unsafe { let args = match A::from_stack_args(nargs, 1, Some(&name), rawlua) { Ok(args) => args, Err(e) => return Box::pin(future::ready(Err(e))), }; let lua = rawlua.lua(); let fut = function(lua.clone(), args); Box::pin(async move { fut.await?.push_into_stack_multi(lua.raw_lua()) }) }) }
pub(crate) fn check_meta_field(lua: &Lua, name: &str, value: impl IntoLua) -> Result<Value> { let value = value.into_lua(lua)?; if name == MetaMethod::Index || name == MetaMethod::NewIndex { match value { Value::Nil | Value::Table(_) | Value::Function(_) => {} _ => { return Err(Error::MetaMethodTypeError { method: name.to_string(), type_name: value.type_name(), message: Some("expected nil, table or function".to_string()), }) } } } value.into_lua(lua) }
#[inline(always)] pub(crate) fn into_raw(self) -> RawUserDataRegistry { self.raw }}
// Returns function name for the type `T`, without the module pathfn get_function_name<T>(name: &str) -> StdString { format!("{}.{name}", short_type_name::<T>())}
impl<T> UserDataFields<T> for UserDataRegistry<T> { fn add_field<V>(&mut self, name: impl Into<StdString>, value: V) where V: IntoLua + 'static, { let name = name.into(); self.raw.fields.push((name, value.into_lua(self.lua.lua()))); }
fn add_field_method_get<M, R>(&mut self, name: impl Into<StdString>, method: M) where M: Fn(&Lua, &T) -> Result<R> + MaybeSend + 'static, R: IntoLua, { let name = name.into(); let callback = self.box_method(&name, move |lua, data, ()| method(lua, data)); self.raw.field_getters.push((name, callback)); }
fn add_field_method_set<M, A>(&mut self, name: impl Into<StdString>, method: M) where M: FnMut(&Lua, &mut T, A) -> Result<()> + MaybeSend + 'static, A: FromLua, { let name = name.into(); let callback = self.box_method_mut(&name, method); self.raw.field_setters.push((name, callback)); }
fn add_field_function_get<F, R>(&mut self, name: impl Into<StdString>, function: F) where F: Fn(&Lua, AnyUserData) -> Result<R> + MaybeSend + 'static, R: IntoLua, { let name = name.into(); let callback = self.box_function(&name, function); self.raw.field_getters.push((name, callback)); }
fn add_field_function_set<F, A>(&mut self, name: impl Into<StdString>, mut function: F) where F: FnMut(&Lua, AnyUserData, A) -> Result<()> + MaybeSend + 'static, A: FromLua, { let name = name.into(); let callback = self.box_function_mut(&name, move |lua, (data, val)| function(lua, data, val)); self.raw.field_setters.push((name, callback)); }
fn add_meta_field<V>(&mut self, name: impl Into<StdString>, value: V) where V: IntoLua + 'static, { let lua = self.lua.lua(); let name = name.into(); let field = Self::check_meta_field(lua, &name, value).and_then(|v| v.into_lua(lua)); self.raw.meta_fields.push((name, field)); }
fn add_meta_field_with<F, R>(&mut self, name: impl Into<StdString>, f: F) where F: FnOnce(&Lua) -> Result<R> + 'static, R: IntoLua, { let lua = self.lua.lua(); let name = name.into(); let field = f(lua).and_then(|v| Self::check_meta_field(lua, &name, v).and_then(|v| v.into_lua(lua))); self.raw.meta_fields.push((name, field)); }}
impl<T> UserDataMethods<T> for UserDataRegistry<T> { fn add_method<M, A, R>(&mut self, name: impl Into<StdString>, method: M) where M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static, A: FromLuaMulti, R: IntoLuaMulti, { let name = name.into(); let callback = self.box_method(&name, method); self.raw.methods.push((name, callback)); }
fn add_method_mut<M, A, R>(&mut self, name: impl Into<StdString>, method: M) where M: FnMut(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static, A: FromLuaMulti, R: IntoLuaMulti, { let name = name.into(); let callback = self.box_method_mut(&name, method); self.raw.methods.push((name, callback)); }
#[cfg(feature = "async")] fn add_async_method<M, A, MR, R>(&mut self, name: impl Into<StdString>, method: M) where T: 'static, M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static, A: FromLuaMulti, MR: Future<Output = Result<R>> + MaybeSend + 'static, R: IntoLuaMulti, { let name = name.into(); let callback = self.box_async_method(&name, method); self.raw.async_methods.push((name, callback)); }
#[cfg(feature = "async")] fn add_async_method_mut<M, A, MR, R>(&mut self, name: impl Into<StdString>, method: M) where T: 'static, M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static, A: FromLuaMulti, MR: Future<Output = Result<R>> + MaybeSend + 'static, R: IntoLuaMulti, { let name = name.into(); let callback = self.box_async_method_mut(&name, method); self.raw.async_methods.push((name, callback)); }
fn add_function<F, A, R>(&mut self, name: impl Into<StdString>, function: F) where F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static, A: FromLuaMulti, R: IntoLuaMulti, { let name = name.into(); let callback = self.box_function(&name, function); self.raw.methods.push((name, callback)); }
fn add_function_mut<F, A, R>(&mut self, name: impl Into<StdString>, function: F) where F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static, A: FromLuaMulti, R: IntoLuaMulti, { let name = name.into(); let callback = self.box_function_mut(&name, function); self.raw.methods.push((name, callback)); }
#[cfg(feature = "async")] fn add_async_function<F, A, FR, R>(&mut self, name: impl Into<StdString>, function: F) where F: Fn(Lua, A) -> FR + MaybeSend + 'static, A: FromLuaMulti, FR: Future<Output = Result<R>> + MaybeSend + 'static, R: IntoLuaMulti, { let name = name.into(); let callback = self.box_async_function(&name, function); self.raw.async_methods.push((name, callback)); }
fn add_meta_method<M, A, R>(&mut self, name: impl Into<StdString>, method: M) where M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static, A: FromLuaMulti, R: IntoLuaMulti, { let name = name.into(); let callback = self.box_method(&name, method); self.raw.meta_methods.push((name, callback)); }
fn add_meta_method_mut<M, A, R>(&mut self, name: impl Into<StdString>, method: M) where M: FnMut(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static, A: FromLuaMulti, R: IntoLuaMulti, { let name = name.into(); let callback = self.box_method_mut(&name, method); self.raw.meta_methods.push((name, callback)); }
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))] fn add_async_meta_method<M, A, MR, R>(&mut self, name: impl Into<StdString>, method: M) where T: 'static, M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static, A: FromLuaMulti, MR: Future<Output = Result<R>> + MaybeSend + 'static, R: IntoLuaMulti, { let name = name.into(); let callback = self.box_async_method(&name, method); self.raw.async_meta_methods.push((name, callback)); }
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))] fn add_async_meta_method_mut<M, A, MR, R>(&mut self, name: impl Into<StdString>, method: M) where T: 'static, M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static, A: FromLuaMulti, MR: Future<Output = Result<R>> + MaybeSend + 'static, R: IntoLuaMulti, { let name = name.into(); let callback = self.box_async_method_mut(&name, method); self.raw.async_meta_methods.push((name, callback)); }
fn add_meta_function<F, A, R>(&mut self, name: impl Into<StdString>, function: F) where F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static, A: FromLuaMulti, R: IntoLuaMulti, { let name = name.into(); let callback = self.box_function(&name, function); self.raw.meta_methods.push((name, callback)); }
fn add_meta_function_mut<F, A, R>(&mut self, name: impl Into<StdString>, function: F) where F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static, A: FromLuaMulti, R: IntoLuaMulti, { let name = name.into(); let callback = self.box_function_mut(&name, function); self.raw.meta_methods.push((name, callback)); }
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))] fn add_async_meta_function<F, A, FR, R>(&mut self, name: impl Into<StdString>, function: F) where F: Fn(Lua, A) -> FR + MaybeSend + 'static, A: FromLuaMulti, FR: Future<Output = Result<R>> + MaybeSend + 'static, R: IntoLuaMulti, { let name = name.into(); let callback = self.box_async_function(&name, function); self.raw.async_meta_methods.push((name, callback)); }}
macro_rules! lua_userdata_impl { ($type:ty) => { impl<T: UserData + 'static> UserData for $type { fn register(registry: &mut UserDataRegistry<Self>) { let mut orig_registry = UserDataRegistry::new(registry.lua.lua()); T::register(&mut orig_registry);
// Copy all fields, methods, etc. from the original registry (registry.raw.fields).extend(orig_registry.raw.fields); (registry.raw.field_getters).extend(orig_registry.raw.field_getters); (registry.raw.field_setters).extend(orig_registry.raw.field_setters); (registry.raw.meta_fields).extend(orig_registry.raw.meta_fields); (registry.raw.methods).extend(orig_registry.raw.methods); #[cfg(feature = "async")] (registry.raw.async_methods).extend(orig_registry.raw.async_methods); (registry.raw.meta_methods).extend(orig_registry.raw.meta_methods); #[cfg(feature = "async")] (registry.raw.async_meta_methods).extend(orig_registry.raw.async_meta_methods); } } };}
// A special proxy object for UserDatapub(crate) struct UserDataProxy<T>(pub(crate) PhantomData<T>);
lua_userdata_impl!(UserDataProxy<T>);
#[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]lua_userdata_impl!(std::rc::Rc<T>);#[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]lua_userdata_impl!(std::rc::Rc<std::cell::RefCell<T>>);#[cfg(feature = "userdata-wrappers")]lua_userdata_impl!(std::sync::Arc<T>);#[cfg(feature = "userdata-wrappers")]lua_userdata_impl!(std::sync::Arc<std::sync::Mutex<T>>);#[cfg(feature = "userdata-wrappers")]lua_userdata_impl!(std::sync::Arc<std::sync::RwLock<T>>);#[cfg(feature = "userdata-wrappers")]lua_userdata_impl!(std::sync::Arc<parking_lot::Mutex<T>>);#[cfg(feature = "userdata-wrappers")]lua_userdata_impl!(std::sync::Arc<parking_lot::RwLock<T>>);
#[cfg(test)]mod assertions { #[cfg(feature = "send")] static_assertions::assert_impl_all!(super::RawUserDataRegistry: Send);}