From cc98e82ea17b9df5aefa3fe22a14414a9a1cd9cd Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 6 Dec 2021 11:12:54 +0800 Subject: [PATCH] Include hashes in JSON output. --- CHANGELOG.md | 1 + src/module/mod.rs | 48 +++++++++++++++++---------------------- src/serde/metadata.rs | 52 +++++++++++++++++-------------------------- 3 files changed, 41 insertions(+), 60 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e8c0fb7..4bcba46a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ Enhancements * Added `into_array` and `into_typed_array` for `Dynamic`. * Added `FnPtr::call` and `FnPtr::call_within_context` to simplify calling a function pointer. * BLob's can now be deserialized (using `from_dynamic`) into `Vec` via [`serde_bytes`](https://crates.io/crates/serde_bytes). +* A function's hashes are included in its JSON metadata to assist in debugging. Each function's `hashBase` field in the JSON object should map directly to the pre-calculated hash in the function call. Deprecated and Gated API's -------------------------- diff --git a/src/module/mod.rs b/src/module/mod.rs index 7cc982d6..144beb3d 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -106,7 +106,7 @@ impl FuncInfo { /// /// The first module name is skipped. Hashing starts from the _second_ module in the chain. #[inline] -fn calc_native_fn_hash( +pub fn calc_native_fn_hash( modules: impl Iterator>, fn_name: impl AsRef, params: &[TypeId], @@ -179,8 +179,7 @@ impl fmt::Debug for Module { d.field( "functions", &self - .functions - .values() + .iter_fn() .map(|f| f.func.to_string()) .collect::>(), ); @@ -358,9 +357,8 @@ impl Module { #[cfg(feature = "metadata")] #[inline] pub fn gen_fn_signatures(&self) -> impl Iterator + '_ { - self.functions - .values() - .filter(|f| match f.access { + self.iter_fn() + .filter(|&f| match f.access { FnAccess::Public => true, FnAccess::Private => false, }) @@ -501,8 +499,7 @@ impl Module { } else { let name = name.as_ref(); - self.functions - .values() + self.iter_fn() .find(|f| f.params == num_params && f.name == name) .and_then(|f| f.func.get_script_fn_def()) } @@ -1232,7 +1229,7 @@ impl Module { other .functions .iter() - .filter(|(_, f)| { + .filter(|&(_, f)| { _filter( f.namespace, f.access, @@ -1331,18 +1328,15 @@ impl Module { &Shared, ), > + '_ { - self.functions - .values() - .filter(|f| f.func.is_script()) - .map(|f| { - ( - f.namespace, - f.access, - f.name.as_str(), - f.params, - f.func.get_script_fn_def().expect("scripted function"), - ) - }) + self.iter_fn().filter(|&f| f.func.is_script()).map(|f| { + ( + f.namespace, + f.access, + f.name.as_str(), + f.params, + f.func.get_script_fn_def().expect("scripted function"), + ) + }) } /// Get an iterator over all script-defined functions in the [`Module`]. @@ -1358,9 +1352,8 @@ impl Module { pub fn iter_script_fn_info( &self, ) -> impl Iterator { - self.functions - .values() - .filter(|f| f.func.is_script()) + self.iter_fn() + .filter(|&f| f.func.is_script()) .map(|f| (f.namespace, f.access, f.name.as_str(), f.params)) } @@ -1461,13 +1454,12 @@ impl Module { #[cfg(not(feature = "no_function"))] if ast.has_functions() { ast.shared_lib() - .functions - .values() - .filter(|f| match f.access { + .iter_fn() + .filter(|&f| match f.access { FnAccess::Public => true, FnAccess::Private => false, }) - .filter(|f| f.func.is_script()) + .filter(|&f| f.func.is_script()) .for_each(|f| { // Encapsulate AST environment let mut func = f diff --git a/src/serde/metadata.rs b/src/serde/metadata.rs index ef67b4e2..0f79d941 100644 --- a/src/serde/metadata.rs +++ b/src/serde/metadata.rs @@ -1,8 +1,9 @@ -use crate::{Engine, AST}; +use crate::module::calc_native_fn_hash; +use crate::{calc_fn_hash, Engine, AST}; use serde::{Deserialize, Serialize}; #[cfg(feature = "no_std")] use std::prelude::v1::*; -use std::{cmp::Ordering, collections::BTreeMap}; +use std::{cmp::Ordering, collections::BTreeMap, iter::empty}; #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -83,6 +84,8 @@ impl Ord for FnParam { #[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] struct FnMetadata { + pub base_hash: u64, + pub full_hash: u64, pub namespace: FnNamespace, pub access: FnAccess, pub name: String, @@ -118,15 +121,23 @@ impl Ord for FnMetadata { impl From<&crate::module::FuncInfo> for FnMetadata { fn from(info: &crate::module::FuncInfo) -> Self { + let base_hash = calc_fn_hash(&info.name, info.params); + let (typ, full_hash) = if info.func.is_script() { + (FnType::Script, base_hash) + } else { + ( + FnType::Native, + calc_native_fn_hash(empty::<&str>(), &info.name, &info.param_types), + ) + }; + Self { + base_hash, + full_hash, namespace: info.namespace.into(), access: info.access.into(), name: info.name.to_string(), - typ: if info.func.is_script() { - FnType::Script - } else { - FnType::Native - }, + typ, num_params: info.params, params: info .param_names @@ -169,30 +180,6 @@ impl From<&crate::module::FuncInfo> for FnMetadata { } } -#[cfg(not(feature = "no_function"))] -impl From> for FnMetadata { - fn from(info: crate::ast::ScriptFnMetadata) -> Self { - Self { - namespace: FnNamespace::Global, - access: info.access.into(), - name: info.name.to_string(), - typ: FnType::Script, - num_params: info.params.len(), - params: info - .params - .iter() - .map(|&s| FnParam { - name: s.into(), - typ: Some("Dynamic".into()), - }) - .collect(), - return_type: Some("Dynamic".into()), - signature: info.to_string(), - doc_comments: info.comments.iter().map(|&s| s.into()).collect(), - } - } -} - #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "camelCase")] struct ModuleMetadata { @@ -263,7 +250,8 @@ impl Engine { .for_each(|f| global.functions.push(f.into())); #[cfg(not(feature = "no_function"))] - _ast.iter_functions() + _ast.shared_lib() + .iter_fn() .for_each(|f| global.functions.push(f.into())); global.functions.sort();