diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ee8849d..247b0044 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ New features ------------ * Each `Dynamic` value can now contain arbitrary data (type `i16`) in the form of a _tag_. This is to use up otherwise wasted space in the `Dynamic` type. +* A new internal feature `no_smartstring` to turn off `SmartString` for those rare cases that it is needed. Version 0.20.1 diff --git a/Cargo.toml b/Cargo.toml index 89f98f7c..28a6511d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,6 +48,9 @@ no_std = ["no-std-compat", "num-traits/libm", "core-error", "libm", "ahash/compi wasm-bindgen = ["instant/wasm-bindgen"] stdweb = ["instant/stdweb"] +# internal feature flags - volatile +no_smartstring = [] # Do not use SmartString + [profile.release] lto = "fat" codegen-units = 1 diff --git a/src/ast.rs b/src/ast.rs index 83072539..f4fa30ec 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -2096,7 +2096,10 @@ mod tests { assert_eq!(size_of::>(), 16); assert_eq!(size_of::(), 32); assert_eq!(size_of::>(), 32); + #[cfg(not(feature = "no_smartstring"))] assert_eq!(size_of::(), 96); + #[cfg(feature = "no_smartstring")] + assert_eq!(size_of::(), 80); assert_eq!(size_of::(), 288); assert_eq!(size_of::(), 56); assert_eq!( diff --git a/src/bin/rhai-repl.rs b/src/bin/rhai-repl.rs index 7f4f87d0..a4af261f 100644 --- a/src/bin/rhai-repl.rs +++ b/src/bin/rhai-repl.rs @@ -106,7 +106,7 @@ fn main() { .compile(&contents) .map_err(|err| err.into()) .and_then(|mut ast| { - ast.set_source(filename.to_string_lossy()); + ast.set_source(filename.to_string_lossy().to_string()); Module::eval_ast_as_new(Default::default(), &ast, &engine) }) { Err(err) => { diff --git a/src/bin/rhai-run.rs b/src/bin/rhai-run.rs index bdef6b64..887cffc4 100644 --- a/src/bin/rhai-run.rs +++ b/src/bin/rhai-run.rs @@ -85,7 +85,7 @@ fn main() { .compile(contents) .map_err(|err| Box::new(err.into()) as Box) .and_then(|mut ast| { - ast.set_source(filename.to_string_lossy()); + ast.set_source(filename.to_string_lossy().to_string()); engine.consume_ast(&ast) }) { diff --git a/src/dynamic.rs b/src/dynamic.rs index b5ea5475..e1cb2568 100644 --- a/src/dynamic.rs +++ b/src/dynamic.rs @@ -2,7 +2,7 @@ use crate::fn_native::SendSync; use crate::r#unsafe::{unsafe_cast_box, unsafe_try_cast}; -use crate::{FnPtr, ImmutableString, SmartString, INT}; +use crate::{FnPtr, ImmutableString, INT}; #[cfg(feature = "no_std")] use std::prelude::v1::*; use std::{ @@ -973,12 +973,6 @@ impl Dynamic { .deref() .into(); } - if TypeId::of::() == TypeId::of::() { - return ::downcast_ref::(&value) - .unwrap() - .clone() - .into(); - } if TypeId::of::() == TypeId::of::<()>() { return ().into(); } @@ -1803,7 +1797,7 @@ impl From<&ImmutableString> for Dynamic { value.clone().into() } } -#[cfg(not(feature = "no_smartstring_for_identifier"))] +#[cfg(not(feature = "no_smartstring"))] impl From<&crate::Identifier> for Dynamic { #[inline(always)] fn from(value: &crate::Identifier) -> Self { diff --git a/src/engine.rs b/src/engine.rs index 93b667a1..3f3031d3 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -923,7 +923,7 @@ impl Engine { }, }; - engine.global_namespace.set_internal(true); + engine.global_namespace.internal = true; engine.register_global_module(StandardPackage::new().as_shared_module()); engine @@ -980,7 +980,7 @@ impl Engine { }, }; - engine.global_namespace.set_internal(true); + engine.global_namespace.internal = true; engine } @@ -2610,18 +2610,15 @@ impl Engine { #[cfg(not(feature = "no_function"))] if entry_type == AccessMode::ReadOnly && lib.iter().any(|&m| !m.is_empty()) { let global = if let Some(index) = mods.find(KEYWORD_GLOBAL) { - let global = mods.get_mut(index).unwrap(); - - if !global.is_internal() { - None - } else { - Some(global) + match mods.get_mut(index).unwrap() { + m if m.internal => Some(m), + _ => None, } } else { // Create automatic global module let mut global = Module::new(); - global.set_internal(true); - mods.push(crate::engine::KEYWORD_GLOBAL, global); + global.internal = true; + mods.push(KEYWORD_GLOBAL, global); Some(mods.get_mut(mods.len() - 1).unwrap()) }; diff --git a/src/fn_native.rs b/src/fn_native.rs index a72d79b0..48ae8077 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -5,8 +5,8 @@ use crate::engine::Imports; use crate::plugin::PluginFunction; use crate::token::is_valid_identifier; use crate::{ - calc_fn_hash, Dynamic, Engine, EvalAltResult, EvalContext, Identifier, ImmutableString, Module, - Position, RhaiResult, StaticVec, + calc_fn_hash, Dynamic, Engine, EvalAltResult, EvalContext, Identifier, Module, Position, + RhaiResult, StaticVec, }; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -367,16 +367,17 @@ impl TryFrom for FnPtr { if is_valid_identifier(value.chars()) { Ok(Self(value, Default::default())) } else { - EvalAltResult::ErrorFunctionNotFound(value.into(), Position::NONE).into() + EvalAltResult::ErrorFunctionNotFound(value.to_string(), Position::NONE).into() } } } -impl TryFrom for FnPtr { +#[cfg(not(feature = "no_smartstring"))] +impl TryFrom for FnPtr { type Error = Box; #[inline(always)] - fn try_from(value: ImmutableString) -> Result { + fn try_from(value: crate::ImmutableString) -> Result { let s: Identifier = value.into(); Self::try_from(s) } diff --git a/src/lib.rs b/src/lib.rs index 4b8633bd..1c722720 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -140,11 +140,11 @@ pub use utils::ImmutableString; /// An identifier in Rhai. [`SmartString`](https://crates.io/crates/smartstring) is used because most /// identifiers are ASCII and short, fewer than 23 characters, so they can be stored inline. -#[cfg(not(feature = "no_smartstring_for_identifier"))] +#[cfg(not(feature = "no_smartstring"))] pub type Identifier = SmartString; /// An identifier in Rhai. -#[cfg(feature = "no_smartstring_for_identifier")] +#[cfg(feature = "no_smartstring")] pub type Identifier = ImmutableString; /// A trait to enable registering Rust functions. @@ -306,9 +306,14 @@ type StaticVec = smallvec::SmallVec<[T; 4]>; pub type StaticVec = smallvec::SmallVec<[T; 4]>; #[cfg(not(feature = "internals"))] +#[cfg(not(feature = "no_smartstring"))] pub(crate) type SmartString = smartstring::SmartString; +#[cfg(feature = "no_smartstring")] +pub(crate) type SmartString = String; + #[cfg(feature = "internals")] +#[cfg(not(feature = "no_smartstring"))] pub type SmartString = smartstring::SmartString; // Compiler guards against mutually-exclusive feature flags diff --git a/src/module/mod.rs b/src/module/mod.rs index 1fbfaca1..16c93374 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -129,7 +129,7 @@ pub struct Module { /// ID identifying the module. id: Option, /// Is this module internal? - internal: bool, + pub(crate) internal: bool, /// Sub-modules. modules: BTreeMap>, /// [`Module`] variables. @@ -309,20 +309,6 @@ impl Module { self } - /// Is the [`Module`] internal? - #[allow(dead_code)] - #[inline(always)] - pub(crate) fn is_internal(&self) -> bool { - self.internal - } - - /// Set the internal status of the [`Module`]. - #[inline(always)] - pub(crate) fn set_internal(&mut self, value: bool) -> &mut Self { - self.internal = value; - self - } - /// Is the [`Module`] empty? /// /// # Example @@ -476,10 +462,7 @@ impl Module { /// If there is an existing function of the same name and number of arguments, it is replaced. #[cfg(not(feature = "no_function"))] #[inline] - pub(crate) fn set_script_fn( - &mut self, - fn_def: impl Into>, - ) -> u64 { + pub fn set_script_fn(&mut self, fn_def: impl Into>) -> u64 { let fn_def = fn_def.into(); // None + function name + number of arguments. diff --git a/src/utils.rs b/src/utils.rs index 234ad303..ab998c5d 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -198,6 +198,7 @@ impl From for ImmutableString { Self(Into::::into(value).into()) } } +#[cfg(not(feature = "no_smartstring"))] impl From for ImmutableString { #[inline(always)] fn from(value: SmartString) -> Self { @@ -248,6 +249,14 @@ impl<'a> FromIterator for ImmutableString { } } +#[cfg(not(feature = "no_smartstring"))] +impl<'a> FromIterator for ImmutableString { + #[inline(always)] + fn from_iter>(iter: T) -> Self { + Self(iter.into_iter().collect::().into()) + } +} + impl fmt::Display for ImmutableString { #[inline(always)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -618,17 +627,17 @@ impl ImmutableString { /// yet interned. #[derive(Debug, Clone, Default, Hash)] pub struct IdentifierBuilder( - #[cfg(feature = "no_smartstring_for_identifier")] std::collections::BTreeSet, + #[cfg(feature = "no_smartstring")] std::collections::BTreeSet, ); impl IdentifierBuilder { /// Get an identifier from a text string. #[inline(always)] pub fn get(&mut self, text: impl AsRef + Into) -> Identifier { - #[cfg(not(feature = "no_smartstring_for_identifier"))] + #[cfg(not(feature = "no_smartstring"))] return text.as_ref().into(); - #[cfg(feature = "no_smartstring_for_identifier")] + #[cfg(feature = "no_smartstring")] return self.0.get(text.as_ref()).cloned().unwrap_or_else(|| { let s: Identifier = text.into(); self.0.insert(s.clone());