From 04ba93137cfecf0960712eec78d85b526778a9a4 Mon Sep 17 00:00:00 2001 From: Alex Orlenko Date: Mon, 27 Jun 2022 14:56:31 +0100 Subject: [PATCH] Add `Table::to_pointer()` and `String::to_pointer()` functions --- src/serde/de.rs | 9 ++------- src/string.rs | 12 ++++++++++++ src/table.rs | 18 +++++++++++++++--- src/value.rs | 7 ++++--- 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/serde/de.rs b/src/serde/de.rs index 25ab9ec..20a9224 100644 --- a/src/serde/de.rs +++ b/src/serde/de.rs @@ -8,7 +8,6 @@ use rustc_hash::FxHashSet; use serde::de::{self, IntoDeserializer}; use crate::error::{Error, Result}; -use crate::ffi; use crate::table::{Table, TablePairs, TableSequence}; use crate::value::Value; @@ -563,9 +562,7 @@ impl RecursionGuard { #[inline] fn new(table: &Table, visited: &Rc>>) -> Self { let visited = Rc::clone(visited); - let lua = table.0.lua; - let ptr = - unsafe { lua.ref_thread_exec(|refthr| ffi::lua_topointer(refthr, table.0.index)) }; + let ptr = table.to_pointer(); visited.borrow_mut().insert(ptr); RecursionGuard { ptr, visited } } @@ -585,9 +582,7 @@ fn check_value_if_skip( ) -> Result { match value { Value::Table(table) => { - let lua = table.0.lua; - let ptr = - unsafe { lua.ref_thread_exec(|refthr| ffi::lua_topointer(refthr, table.0.index)) }; + let ptr = table.to_pointer(); if visited.borrow().contains(&ptr) { if options.deny_recursive_tables { return Err(de::Error::custom("recursive table detected")); diff --git a/src/string.rs b/src/string.rs index 87234f0..1093740 100644 --- a/src/string.rs +++ b/src/string.rs @@ -1,5 +1,6 @@ use std::borrow::{Borrow, Cow}; use std::hash::{Hash, Hasher}; +use std::os::raw::c_void; use std::string::String as StdString; use std::{slice, str}; @@ -112,6 +113,17 @@ impl<'lua> String<'lua> { slice::from_raw_parts(data as *const u8, size + 1) } } + + /// Converts the string to a generic C pointer. + /// + /// There is no way to convert the pointer back to its original value. + /// + /// Typically this function is used only for hashing and debug information. + #[inline] + pub fn to_pointer(&self) -> *const c_void { + let lua = self.0.lua; + unsafe { lua.ref_thread_exec(|refthr| ffi::lua_topointer(refthr, self.0.index)) } + } } impl<'lua> AsRef<[u8]> for String<'lua> { diff --git a/src/table.rs b/src/table.rs index db62912..5269cba 100644 --- a/src/table.rs +++ b/src/table.rs @@ -1,10 +1,11 @@ use std::marker::PhantomData; +use std::os::raw::c_void; #[cfg(feature = "serialize")] use { rustc_hash::FxHashSet, serde::ser::{self, Serialize, SerializeMap, SerializeSeq, Serializer}, - std::{cell::RefCell, os::raw::c_void, result::Result as StdResult}, + std::{cell::RefCell, result::Result as StdResult}, }; use crate::error::{Error, Result}; @@ -382,6 +383,18 @@ impl<'lua> Table<'lua> { unsafe { lua.ref_thread_exec(|refthr| ffi::lua_getreadonly(refthr, self.0.index) != 0) } } + /// Converts the table to a generic C pointer. + /// + /// Different tables will give different pointers. + /// There is no way to convert the pointer back to its original value. + /// + /// Typically this function is used only for hashing and debug information. + #[inline] + pub fn to_pointer(&self) -> *const c_void { + let lua = self.0.lua; + unsafe { lua.ref_thread_exec(|refthr| ffi::lua_topointer(refthr, self.0.index)) } + } + /// Consume this table and return an iterator over the pairs of the table. /// /// This works like the Lua `pairs` function, but does not invoke the `__pairs` metamethod. @@ -699,8 +712,7 @@ impl<'lua> Serialize for Table<'lua> { static VISITED: RefCell> = RefCell::new(FxHashSet::default()); } - let lua = self.0.lua; - let ptr = unsafe { lua.ref_thread_exec(|refthr| ffi::lua_topointer(refthr, self.0.index)) }; + let ptr = self.to_pointer(); let res = VISITED.with(|visited| { { let mut visited = visited.borrow_mut(); diff --git a/src/value.rs b/src/value.rs index 7fdc845..6e6367f 100644 --- a/src/value.rs +++ b/src/value.rs @@ -103,13 +103,14 @@ impl<'lua> Value<'lua> { /// There is no way to convert the pointer back to its original value. /// /// Typically this function is used only for hashing and debug information. + #[inline] pub fn to_pointer(&self) -> *const c_void { unsafe { match self { Value::LightUserData(ud) => ud.0, - Value::String(String(v)) - | Value::Table(Table(v)) - | Value::Function(Function(v)) + Value::Table(t) => t.to_pointer(), + Value::String(s) => s.to_pointer(), + Value::Function(Function(v)) | Value::Thread(Thread(v)) | Value::UserData(AnyUserData(v)) => v .lua