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.
* A new internal feature `no_smartstring` to turn off `SmartString` for those rare cases that it is needed.
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"]
stdweb = ["instant/stdweb"]
# internal feature flags - volatile
no_smartstring = [] # Do not use SmartString
[profile.release]
lto = "fat"
codegen-units = 1

View File

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

View File

@ -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) => {

View File

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

View File

@ -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::<T>() == TypeId::of::<SmartString>() {
return <dyn Any>::downcast_ref::<SmartString>(&value)
.unwrap()
.clone()
.into();
}
if TypeId::of::<T>() == 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 {

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
@ -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())
};

View File

@ -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<Identifier> 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<ImmutableString> for FnPtr {
#[cfg(not(feature = "no_smartstring"))]
impl TryFrom<crate::ImmutableString> for FnPtr {
type Error = Box<EvalAltResult>;
#[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();
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
/// 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<T> = smallvec::SmallVec<[T; 4]>;
pub type StaticVec<T> = smallvec::SmallVec<[T; 4]>;
#[cfg(not(feature = "internals"))]
#[cfg(not(feature = "no_smartstring"))]
pub(crate) type SmartString = smartstring::SmartString<smartstring::Compact>;
#[cfg(feature = "no_smartstring")]
pub(crate) type SmartString = String;
#[cfg(feature = "internals")]
#[cfg(not(feature = "no_smartstring"))]
pub type SmartString = smartstring::SmartString<smartstring::Compact>;
// Compiler guards against mutually-exclusive feature flags

View File

@ -129,7 +129,7 @@ pub struct Module {
/// ID identifying the module.
id: Option<Identifier>,
/// Is this module internal?
internal: bool,
pub(crate) internal: bool,
/// Sub-modules.
modules: BTreeMap<Identifier, Shared<Module>>,
/// [`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<Shared<crate::ast::ScriptFnDef>>,
) -> u64 {
pub fn set_script_fn(&mut self, fn_def: impl Into<Shared<crate::ast::ScriptFnDef>>) -> u64 {
let fn_def = fn_def.into();
// None + function name + number of arguments.

View File

@ -198,6 +198,7 @@ impl From<String> for ImmutableString {
Self(Into::<SmartString>::into(value).into())
}
}
#[cfg(not(feature = "no_smartstring"))]
impl From<SmartString> for ImmutableString {
#[inline(always)]
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 {
#[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<Identifier>,
#[cfg(feature = "no_smartstring")] std::collections::BTreeSet<Identifier>,
);
impl IdentifierBuilder {
/// Get an identifier from a text string.
#[inline(always)]
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();
#[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());