Skip to content

Commit

Permalink
Stop relying on layout of TypeId
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Jun 9, 2023
1 parent 9163f79 commit 81fd666
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 11 deletions.
37 changes: 32 additions & 5 deletions crates/rune/src/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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::<u64>() == 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
Expand Down
11 changes: 5 additions & 6 deletions crates/rune/src/modules/any.rs
Original file line number Diff line number Diff line change
@@ -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<TypeId, VmError> {
Ok(TypeId(item.type_hash()?))
}

fn format_type_id(item: &TypeId, buf: &mut String) -> fmt::Result {
Expand Down

0 comments on commit 81fd666

Please sign in to comment.