From 81fd666b1db77b144a0346a79bdf39044325215f Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Fri, 9 Jun 2023 08:30:42 +0200 Subject: [PATCH] Stop relying on layout of TypeId --- crates/rune/src/hash.rs | 37 +++++++++++++++++++++++++++++----- crates/rune/src/modules/any.rs | 11 +++++----- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/crates/rune/src/hash.rs b/crates/rune/src/hash.rs index c5c6e9232..3021eb3a6 100644 --- a/crates/rune/src/hash.rs +++ b/crates/rune/src/hash.rs @@ -5,7 +5,6 @@ use serde::{Deserialize, Serialize}; use std::any; use std::fmt; use std::hash::{self, BuildHasher, BuildHasherDefault, Hash as _, Hasher}; -use std::mem; use twox_hash::XxHash64; const SEP: u64 = 0x4bc94d6bd06053ad; @@ -62,10 +61,38 @@ impl Hash { } /// Construct a hash from a type id. - pub const fn from_type_id(type_id: any::TypeId) -> Self { - // Safety: a type id is exactly a 64-bit unsigned integer. - // And has an identical bit pattern to `Hash`. - unsafe { mem::transmute(type_id) } + pub fn from_type_id(type_id: any::TypeId) -> Self { + // Note: we need to stop relying on the size of TypeId: + // https://github.com/rust-lang/rust/pull/109953 + struct Capture(u64); + + impl Hasher for Capture { + #[inline(always)] + fn finish(&self) -> u64 { + self.0 + } + + #[inline] + fn write_u64(&mut self, value: u64) { + self.0 ^= value; + } + + #[inline] + fn write(&mut self, bytes: &[u8]) { + assert!( + bytes.len() % core::mem::size_of::() == 0, + "TypeId does not hash 64-bit aligned values" + ); + + for chunk in bytes.chunks_exact(8) { + self.0 ^= u64::from_ne_bytes(core::array::from_fn(|n| chunk[n])); + } + } + } + + let mut hasher = Capture(0); + type_id.hash(&mut hasher); + Self(hasher.finish()) } /// Construct a hash to an instance function, where the instance is a diff --git a/crates/rune/src/modules/any.rs b/crates/rune/src/modules/any.rs index e661d17cf..ee93da573 100644 --- a/crates/rune/src/modules/any.rs +++ b/crates/rune/src/modules/any.rs @@ -1,18 +1,17 @@ //! `std::any` module. -use crate::runtime::{Protocol, Value}; -use crate::{Any, ContextError, Module}; -use std::any::TypeId as StdTypeId; +use crate::runtime::{Protocol, Value, VmError}; +use crate::{Any, ContextError, Hash, Module}; use std::fmt; use std::fmt::Write; #[derive(Any, Debug)] #[rune(module = "crate")] #[repr(transparent)] -struct TypeId(StdTypeId); +struct TypeId(Hash); -fn type_id_of_val(item: Value) -> TypeId { - unsafe { std::mem::transmute(item.type_hash().expect("no type known for item!")) } +fn type_id_of_val(item: Value) -> Result { + Ok(TypeId(item.type_hash()?)) } fn format_type_id(item: &TypeId, buf: &mut String) -> fmt::Result {