Fix Dynamic hashing.

This commit is contained in:
Stephen Chung 2021-06-06 14:47:32 +08:00
parent c02d702081
commit 859a18c6fd
2 changed files with 63 additions and 16 deletions

View File

@ -33,6 +33,8 @@ use fmt::Debug;
#[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
use instant::Instant; use instant::Instant;
const CHECKED: &str = "never fails because the type was checked";
mod private { mod private {
use crate::fn_native::SendSync; use crate::fn_native::SendSync;
use std::any::Any; use std::any::Any;
@ -471,29 +473,27 @@ impl Dynamic {
} }
impl Hash for Dynamic { impl Hash for Dynamic {
/// Hash the [`Dynamic`] value.
///
/// # Panics
///
/// Panics if the [`Dynamic`] value contains an unrecognized trait object.
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
std::mem::discriminant(&self.0).hash(state);
match &self.0 { match &self.0 {
Union::Unit(_, _, _) => ().hash(state), Union::Unit(_, _, _) => ().hash(state),
Union::Bool(value, _, _) => value.hash(state), Union::Bool(b, _, _) => b.hash(state),
Union::Str(s, _, _) => s.hash(state), Union::Str(s, _, _) => s.hash(state),
Union::Char(ch, _, _) => ch.hash(state), Union::Char(c, _, _) => c.hash(state),
Union::Int(i, _, _) => i.hash(state), Union::Int(i, _, _) => i.hash(state),
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
Union::Float(f, _, _) => f.hash(state), Union::Float(f, _, _) => f.hash(state),
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
Union::Array(a, _, _) => a.as_ref().hash(state), Union::Array(a, _, _) => a.as_ref().hash(state),
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Union::Map(m, _, _) => m.iter().for_each(|(key, value)| { Union::Map(m, _, _) => m.as_ref().hash(state),
key.hash(state); Union::FnPtr(f, _, _) => f.hash(state),
value.hash(state);
}),
Union::FnPtr(f, _, _) if f.is_curried() => {
unimplemented!(
"{} with curried arguments cannot be hashed",
self.type_name()
)
}
Union::FnPtr(f, _, _) => f.fn_name().hash(state),
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Union::Shared(cell, _, _) => { Union::Shared(cell, _, _) => {
@ -505,6 +505,55 @@ impl Hash for Dynamic {
(*value).hash(state) (*value).hash(state)
} }
#[cfg(not(feature = "only_i32"))]
#[cfg(not(feature = "only_i64"))]
Union::Variant(value, _, _) => {
let value = value.as_ref().as_ref();
let _type_id = value.type_id();
let _value_any = value.as_any();
if _type_id == TypeId::of::<u8>() {
TypeId::of::<u8>().hash(state);
_value_any.downcast_ref::<u8>().expect(CHECKED).hash(state);
} else if _type_id == TypeId::of::<u16>() {
TypeId::of::<u16>().hash(state);
_value_any.downcast_ref::<u16>().expect(CHECKED).hash(state);
} else if _type_id == TypeId::of::<u32>() {
TypeId::of::<u32>().hash(state);
_value_any.downcast_ref::<u32>().expect(CHECKED).hash(state);
} else if _type_id == TypeId::of::<u64>() {
TypeId::of::<u64>().hash(state);
_value_any.downcast_ref::<u64>().expect(CHECKED).hash(state);
} else if _type_id == TypeId::of::<i8>() {
TypeId::of::<i8>().hash(state);
_value_any.downcast_ref::<i8>().expect(CHECKED).hash(state);
} else if _type_id == TypeId::of::<i16>() {
TypeId::of::<i16>().hash(state);
_value_any.downcast_ref::<i16>().expect(CHECKED).hash(state);
} else if _type_id == TypeId::of::<i32>() {
TypeId::of::<i32>().hash(state);
_value_any.downcast_ref::<i32>().expect(CHECKED).hash(state);
} else if _type_id == TypeId::of::<i64>() {
TypeId::of::<i64>().hash(state);
_value_any.downcast_ref::<i64>().expect(CHECKED).hash(state);
}
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
if _type_id == TypeId::of::<u128>() {
TypeId::of::<u128>().hash(state);
_value_any
.downcast_ref::<u128>()
.expect(CHECKED)
.hash(state);
} else if _type_id == TypeId::of::<i128>() {
TypeId::of::<i128>().hash(state);
_value_any
.downcast_ref::<i128>()
.expect(CHECKED)
.hash(state);
}
}
_ => unimplemented!("{} cannot be hashed", self.type_name()), _ => unimplemented!("{} cannot be hashed", self.type_name()),
} }
} }
@ -573,8 +622,6 @@ impl fmt::Display for Dynamic {
let _type_id = value.type_id(); let _type_id = value.type_id();
let _value_any = value.as_any(); let _value_any = value.as_any();
const CHECKED: &str = "never fails because the type was checked";
#[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i32"))]
#[cfg(not(feature = "only_i64"))] #[cfg(not(feature = "only_i64"))]
if _type_id == TypeId::of::<u8>() { if _type_id == TypeId::of::<u8>() {

View File

@ -263,7 +263,7 @@ pub type FnCallArgs<'a> = [&'a mut Dynamic];
/// A general function pointer, which may carry additional (i.e. curried) argument values /// A general function pointer, which may carry additional (i.e. curried) argument values
/// to be passed onto a function during a call. /// to be passed onto a function during a call.
#[derive(Debug, Clone)] #[derive(Debug, Clone, Hash)]
pub struct FnPtr(Identifier, StaticVec<Dynamic>); pub struct FnPtr(Identifier, StaticVec<Dynamic>);
impl FnPtr { impl FnPtr {