From 859a18c6fdf35b34c03395700b977ec070be1ec1 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sun, 6 Jun 2021 14:47:32 +0800 Subject: [PATCH] Fix Dynamic hashing. --- src/dynamic.rs | 77 ++++++++++++++++++++++++++++++++++++++---------- src/fn_native.rs | 2 +- 2 files changed, 63 insertions(+), 16 deletions(-) diff --git a/src/dynamic.rs b/src/dynamic.rs index 0508dbcb..66c01668 100644 --- a/src/dynamic.rs +++ b/src/dynamic.rs @@ -33,6 +33,8 @@ use fmt::Debug; #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] use instant::Instant; +const CHECKED: &str = "never fails because the type was checked"; + mod private { use crate::fn_native::SendSync; use std::any::Any; @@ -471,29 +473,27 @@ impl Dynamic { } impl Hash for Dynamic { + /// Hash the [`Dynamic`] value. + /// + /// # Panics + /// + /// Panics if the [`Dynamic`] value contains an unrecognized trait object. fn hash(&self, state: &mut H) { + std::mem::discriminant(&self.0).hash(state); + match &self.0 { Union::Unit(_, _, _) => ().hash(state), - Union::Bool(value, _, _) => value.hash(state), + Union::Bool(b, _, _) => b.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), #[cfg(not(feature = "no_float"))] Union::Float(f, _, _) => f.hash(state), #[cfg(not(feature = "no_index"))] Union::Array(a, _, _) => a.as_ref().hash(state), #[cfg(not(feature = "no_object"))] - Union::Map(m, _, _) => m.iter().for_each(|(key, value)| { - key.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), + Union::Map(m, _, _) => m.as_ref().hash(state), + Union::FnPtr(f, _, _) => f.hash(state), #[cfg(not(feature = "no_closure"))] Union::Shared(cell, _, _) => { @@ -505,6 +505,55 @@ impl Hash for Dynamic { (*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::() { + TypeId::of::().hash(state); + _value_any.downcast_ref::().expect(CHECKED).hash(state); + } else if _type_id == TypeId::of::() { + TypeId::of::().hash(state); + _value_any.downcast_ref::().expect(CHECKED).hash(state); + } else if _type_id == TypeId::of::() { + TypeId::of::().hash(state); + _value_any.downcast_ref::().expect(CHECKED).hash(state); + } else if _type_id == TypeId::of::() { + TypeId::of::().hash(state); + _value_any.downcast_ref::().expect(CHECKED).hash(state); + } else if _type_id == TypeId::of::() { + TypeId::of::().hash(state); + _value_any.downcast_ref::().expect(CHECKED).hash(state); + } else if _type_id == TypeId::of::() { + TypeId::of::().hash(state); + _value_any.downcast_ref::().expect(CHECKED).hash(state); + } else if _type_id == TypeId::of::() { + TypeId::of::().hash(state); + _value_any.downcast_ref::().expect(CHECKED).hash(state); + } else if _type_id == TypeId::of::() { + TypeId::of::().hash(state); + _value_any.downcast_ref::().expect(CHECKED).hash(state); + } + + #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] + if _type_id == TypeId::of::() { + TypeId::of::().hash(state); + _value_any + .downcast_ref::() + .expect(CHECKED) + .hash(state); + } else if _type_id == TypeId::of::() { + TypeId::of::().hash(state); + _value_any + .downcast_ref::() + .expect(CHECKED) + .hash(state); + } + } + _ => unimplemented!("{} cannot be hashed", self.type_name()), } } @@ -573,8 +622,6 @@ impl fmt::Display for Dynamic { let _type_id = value.type_id(); 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_i64"))] if _type_id == TypeId::of::() { diff --git a/src/fn_native.rs b/src/fn_native.rs index 964488d0..06dccf38 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -263,7 +263,7 @@ pub type FnCallArgs<'a> = [&'a mut Dynamic]; /// A general function pointer, which may carry additional (i.e. curried) argument values /// to be passed onto a function during a call. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Hash)] pub struct FnPtr(Identifier, StaticVec); impl FnPtr {