Add no_smartstring to disable using SmartString.

This commit is contained in:
Stephen Chung 2021-05-08 22:59:33 +08:00
parent 2c0215ea3f
commit d230f448c0
11 changed files with 45 additions and 49 deletions

View File

@ -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. * 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 Version 0.20.1

View File

@ -48,6 +48,9 @@ no_std = ["no-std-compat", "num-traits/libm", "core-error", "libm", "ahash/compi
wasm-bindgen = ["instant/wasm-bindgen"] wasm-bindgen = ["instant/wasm-bindgen"]
stdweb = ["instant/stdweb"] stdweb = ["instant/stdweb"]
# internal feature flags - volatile
no_smartstring = [] # Do not use SmartString
[profile.release] [profile.release]
lto = "fat" lto = "fat"
codegen-units = 1 codegen-units = 1

View File

@ -2096,7 +2096,10 @@ mod tests {
assert_eq!(size_of::<Option<ast::Expr>>(), 16); assert_eq!(size_of::<Option<ast::Expr>>(), 16);
assert_eq!(size_of::<ast::Stmt>(), 32); assert_eq!(size_of::<ast::Stmt>(), 32);
assert_eq!(size_of::<Option<ast::Stmt>>(), 32); assert_eq!(size_of::<Option<ast::Stmt>>(), 32);
#[cfg(not(feature = "no_smartstring"))]
assert_eq!(size_of::<FnPtr>(), 96); assert_eq!(size_of::<FnPtr>(), 96);
#[cfg(feature = "no_smartstring")]
assert_eq!(size_of::<FnPtr>(), 80);
assert_eq!(size_of::<Scope>(), 288); assert_eq!(size_of::<Scope>(), 288);
assert_eq!(size_of::<LexError>(), 56); assert_eq!(size_of::<LexError>(), 56);
assert_eq!( assert_eq!(

View File

@ -106,7 +106,7 @@ fn main() {
.compile(&contents) .compile(&contents)
.map_err(|err| err.into()) .map_err(|err| err.into())
.and_then(|mut ast| { .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) Module::eval_ast_as_new(Default::default(), &ast, &engine)
}) { }) {
Err(err) => { Err(err) => {

View File

@ -85,7 +85,7 @@ fn main() {
.compile(contents) .compile(contents)
.map_err(|err| Box::new(err.into()) as Box<EvalAltResult>) .map_err(|err| Box::new(err.into()) as Box<EvalAltResult>)
.and_then(|mut ast| { .and_then(|mut ast| {
ast.set_source(filename.to_string_lossy()); ast.set_source(filename.to_string_lossy().to_string());
engine.consume_ast(&ast) engine.consume_ast(&ast)
}) })
{ {

View File

@ -2,7 +2,7 @@
use crate::fn_native::SendSync; use crate::fn_native::SendSync;
use crate::r#unsafe::{unsafe_cast_box, unsafe_try_cast}; 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")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
use std::{ use std::{
@ -973,12 +973,6 @@ impl Dynamic {
.deref() .deref()
.into(); .into();
} }
if TypeId::of::<T>() == TypeId::of::<SmartString>() {
return <dyn Any>::downcast_ref::<SmartString>(&value)
.unwrap()
.clone()
.into();
}
if TypeId::of::<T>() == TypeId::of::<()>() { if TypeId::of::<T>() == TypeId::of::<()>() {
return ().into(); return ().into();
} }
@ -1803,7 +1797,7 @@ impl From<&ImmutableString> for Dynamic {
value.clone().into() value.clone().into()
} }
} }
#[cfg(not(feature = "no_smartstring_for_identifier"))] #[cfg(not(feature = "no_smartstring"))]
impl From<&crate::Identifier> for Dynamic { impl From<&crate::Identifier> for Dynamic {
#[inline(always)] #[inline(always)]
fn from(value: &crate::Identifier) -> Self { fn from(value: &crate::Identifier) -> Self {

View File

@ -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.register_global_module(StandardPackage::new().as_shared_module());
engine engine
@ -980,7 +980,7 @@ impl Engine {
}, },
}; };
engine.global_namespace.set_internal(true); engine.global_namespace.internal = true;
engine engine
} }
@ -2610,18 +2610,15 @@ impl Engine {
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
if entry_type == AccessMode::ReadOnly && lib.iter().any(|&m| !m.is_empty()) { if entry_type == AccessMode::ReadOnly && lib.iter().any(|&m| !m.is_empty()) {
let global = if let Some(index) = mods.find(KEYWORD_GLOBAL) { let global = if let Some(index) = mods.find(KEYWORD_GLOBAL) {
let global = mods.get_mut(index).unwrap(); match mods.get_mut(index).unwrap() {
m if m.internal => Some(m),
if !global.is_internal() { _ => None,
None
} else {
Some(global)
} }
} else { } else {
// Create automatic global module // Create automatic global module
let mut global = Module::new(); let mut global = Module::new();
global.set_internal(true); global.internal = true;
mods.push(crate::engine::KEYWORD_GLOBAL, global); mods.push(KEYWORD_GLOBAL, global);
Some(mods.get_mut(mods.len() - 1).unwrap()) Some(mods.get_mut(mods.len() - 1).unwrap())
}; };

View File

@ -5,8 +5,8 @@ use crate::engine::Imports;
use crate::plugin::PluginFunction; use crate::plugin::PluginFunction;
use crate::token::is_valid_identifier; use crate::token::is_valid_identifier;
use crate::{ use crate::{
calc_fn_hash, Dynamic, Engine, EvalAltResult, EvalContext, Identifier, ImmutableString, Module, calc_fn_hash, Dynamic, Engine, EvalAltResult, EvalContext, Identifier, Module, Position,
Position, RhaiResult, StaticVec, RhaiResult, StaticVec,
}; };
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
@ -367,16 +367,17 @@ impl TryFrom<Identifier> for FnPtr {
if is_valid_identifier(value.chars()) { if is_valid_identifier(value.chars()) {
Ok(Self(value, Default::default())) Ok(Self(value, Default::default()))
} else { } else {
EvalAltResult::ErrorFunctionNotFound(value.into(), Position::NONE).into() EvalAltResult::ErrorFunctionNotFound(value.to_string(), Position::NONE).into()
} }
} }
} }
impl TryFrom<ImmutableString> for FnPtr { #[cfg(not(feature = "no_smartstring"))]
impl TryFrom<crate::ImmutableString> for FnPtr {
type Error = Box<EvalAltResult>; type Error = Box<EvalAltResult>;
#[inline(always)] #[inline(always)]
fn try_from(value: ImmutableString) -> Result<Self, Self::Error> { fn try_from(value: crate::ImmutableString) -> Result<Self, Self::Error> {
let s: Identifier = value.into(); let s: Identifier = value.into();
Self::try_from(s) Self::try_from(s)
} }

View File

@ -140,11 +140,11 @@ pub use utils::ImmutableString;
/// An identifier in Rhai. [`SmartString`](https://crates.io/crates/smartstring) is used because most /// 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. /// 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; pub type Identifier = SmartString;
/// An identifier in Rhai. /// An identifier in Rhai.
#[cfg(feature = "no_smartstring_for_identifier")] #[cfg(feature = "no_smartstring")]
pub type Identifier = ImmutableString; pub type Identifier = ImmutableString;
/// A trait to enable registering Rust functions. /// A trait to enable registering Rust functions.
@ -306,9 +306,14 @@ type StaticVec<T> = smallvec::SmallVec<[T; 4]>;
pub type StaticVec<T> = smallvec::SmallVec<[T; 4]>; pub type StaticVec<T> = smallvec::SmallVec<[T; 4]>;
#[cfg(not(feature = "internals"))] #[cfg(not(feature = "internals"))]
#[cfg(not(feature = "no_smartstring"))]
pub(crate) type SmartString = smartstring::SmartString<smartstring::Compact>; pub(crate) type SmartString = smartstring::SmartString<smartstring::Compact>;
#[cfg(feature = "no_smartstring")]
pub(crate) type SmartString = String;
#[cfg(feature = "internals")] #[cfg(feature = "internals")]
#[cfg(not(feature = "no_smartstring"))]
pub type SmartString = smartstring::SmartString<smartstring::Compact>; pub type SmartString = smartstring::SmartString<smartstring::Compact>;
// Compiler guards against mutually-exclusive feature flags // Compiler guards against mutually-exclusive feature flags

View File

@ -129,7 +129,7 @@ pub struct Module {
/// ID identifying the module. /// ID identifying the module.
id: Option<Identifier>, id: Option<Identifier>,
/// Is this module internal? /// Is this module internal?
internal: bool, pub(crate) internal: bool,
/// Sub-modules. /// Sub-modules.
modules: BTreeMap<Identifier, Shared<Module>>, modules: BTreeMap<Identifier, Shared<Module>>,
/// [`Module`] variables. /// [`Module`] variables.
@ -309,20 +309,6 @@ impl Module {
self 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? /// Is the [`Module`] empty?
/// ///
/// # Example /// # Example
@ -476,10 +462,7 @@ impl Module {
/// If there is an existing function of the same name and number of arguments, it is replaced. /// If there is an existing function of the same name and number of arguments, it is replaced.
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
#[inline] #[inline]
pub(crate) fn set_script_fn( pub fn set_script_fn(&mut self, fn_def: impl Into<Shared<crate::ast::ScriptFnDef>>) -> u64 {
&mut self,
fn_def: impl Into<Shared<crate::ast::ScriptFnDef>>,
) -> u64 {
let fn_def = fn_def.into(); let fn_def = fn_def.into();
// None + function name + number of arguments. // None + function name + number of arguments.

View File

@ -198,6 +198,7 @@ impl From<String> for ImmutableString {
Self(Into::<SmartString>::into(value).into()) Self(Into::<SmartString>::into(value).into())
} }
} }
#[cfg(not(feature = "no_smartstring"))]
impl From<SmartString> for ImmutableString { impl From<SmartString> for ImmutableString {
#[inline(always)] #[inline(always)]
fn from(value: SmartString) -> Self { fn from(value: SmartString) -> Self {
@ -248,6 +249,14 @@ impl<'a> FromIterator<String> for ImmutableString {
} }
} }
#[cfg(not(feature = "no_smartstring"))]
impl<'a> FromIterator<SmartString> for ImmutableString {
#[inline(always)]
fn from_iter<T: IntoIterator<Item = SmartString>>(iter: T) -> Self {
Self(iter.into_iter().collect::<SmartString>().into())
}
}
impl fmt::Display for ImmutableString { impl fmt::Display for ImmutableString {
#[inline(always)] #[inline(always)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@ -618,17 +627,17 @@ impl ImmutableString {
/// yet interned. /// yet interned.
#[derive(Debug, Clone, Default, Hash)] #[derive(Debug, Clone, Default, Hash)]
pub struct IdentifierBuilder( pub struct IdentifierBuilder(
#[cfg(feature = "no_smartstring_for_identifier")] std::collections::BTreeSet<Identifier>, #[cfg(feature = "no_smartstring")] std::collections::BTreeSet<Identifier>,
); );
impl IdentifierBuilder { impl IdentifierBuilder {
/// Get an identifier from a text string. /// Get an identifier from a text string.
#[inline(always)] #[inline(always)]
pub fn get(&mut self, text: impl AsRef<str> + Into<Identifier>) -> Identifier { pub fn get(&mut self, text: impl AsRef<str> + Into<Identifier>) -> Identifier {
#[cfg(not(feature = "no_smartstring_for_identifier"))] #[cfg(not(feature = "no_smartstring"))]
return text.as_ref().into(); 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(|| { return self.0.get(text.as_ref()).cloned().unwrap_or_else(|| {
let s: Identifier = text.into(); let s: Identifier = text.into();
self.0.insert(s.clone()); self.0.insert(s.clone());