rhai/src/utils.rs

659 lines
16 KiB
Rust
Raw Normal View History

//! Module containing various utility types and functions.
2020-11-16 16:10:14 +01:00
use crate::fn_native::{shared_make_mut, shared_take};
use crate::stdlib::{
any::TypeId,
2020-05-26 08:14:03 +02:00
borrow::Borrow,
2020-05-26 17:05:44 +02:00
boxed::Box,
cmp::Ordering,
2021-01-05 11:37:07 +01:00
collections::HashMap,
2020-05-05 09:00:10 +02:00
fmt,
2021-01-05 11:37:07 +01:00
fmt::{Debug, Display},
hash::{BuildHasher, Hash, Hasher},
2021-03-08 08:30:32 +01:00
iter::FromIterator,
ops::{Add, AddAssign, Deref, DerefMut, Sub, SubAssign},
2020-05-26 08:14:03 +02:00
str::FromStr,
2020-05-26 17:05:44 +02:00
string::{String, ToString},
2021-01-06 11:22:45 +01:00
vec::Vec,
};
2020-11-16 16:10:14 +01:00
use crate::Shared;
2021-03-08 08:30:32 +01:00
/// A hasher that only takes one single [`u64`] and returns it as a hash key.
///
/// # Panics
///
2021-03-08 08:30:32 +01:00
/// Panics when hashing any data type other than a [`u64`].
2020-12-24 09:32:43 +01:00
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
2021-03-08 08:30:32 +01:00
pub struct StraightHasher(u64);
impl Hasher for StraightHasher {
2020-10-08 16:25:50 +02:00
#[inline(always)]
fn finish(&self) -> u64 {
2021-03-08 08:30:32 +01:00
self.0
}
2020-10-08 16:25:50 +02:00
#[inline(always)]
fn write(&mut self, bytes: &[u8]) {
assert_eq!(bytes.len(), 8, "StraightHasher can only hash u64 values");
let mut key = [0_u8; 8];
key.copy_from_slice(bytes);
2020-12-24 11:43:04 +01:00
2021-03-08 08:30:32 +01:00
self.0 = u64::from_ne_bytes(key);
}
}
/// A hash builder for `StraightHasher`.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
pub struct StraightHasherBuilder;
impl BuildHasher for StraightHasherBuilder {
type Hasher = StraightHasher;
2020-10-08 16:25:50 +02:00
#[inline(always)]
fn build_hasher(&self) -> Self::Hasher {
2021-03-08 08:30:32 +01:00
StraightHasher(42)
}
}
2020-12-24 11:43:04 +01:00
/// Create an instance of the default hasher.
2020-12-29 03:41:20 +01:00
#[inline(always)]
pub fn get_hasher() -> ahash::AHasher {
Default::default()
2020-12-24 11:43:04 +01:00
}
2021-03-08 08:30:32 +01:00
/// _(INTERNALS)_ Calculate a [`u64`] hash key from a namespace-qualified function name
2020-11-10 16:26:50 +01:00
/// and the number of parameters, but no parameter types.
2020-10-28 15:18:44 +01:00
/// Exported under the `internals` feature only.
///
/// Module names are passed in via `&str` references from an iterator.
2020-11-20 09:52:28 +01:00
/// Parameter types are passed in via [`TypeId`] values from an iterator.
2020-10-28 15:18:44 +01:00
///
/// # Note
///
/// The first module name is skipped. Hashing starts from the _second_ module in the chain.
#[inline(always)]
2021-03-08 08:30:32 +01:00
pub fn calc_fn_hash<'a>(
2020-11-17 05:23:53 +01:00
mut modules: impl Iterator<Item = &'a str>,
2020-10-28 15:18:44 +01:00
fn_name: &str,
2021-03-08 08:30:32 +01:00
num: usize,
) -> u64 {
2020-11-13 11:32:18 +01:00
let s = &mut get_hasher();
2020-11-17 05:23:53 +01:00
// Hash a boolean indicating whether the hash is namespace-qualified.
modules.next().is_some().hash(s);
// We always skip the first module
2020-11-17 05:23:53 +01:00
modules.for_each(|m| m.hash(s));
2020-11-19 03:14:43 +01:00
fn_name.hash(s);
2021-03-08 08:30:32 +01:00
num.hash(s);
s.finish()
}
/// _(INTERNALS)_ Calculate a [`u64`] hash key from a list of parameter types.
/// Exported under the `internals` feature only.
///
/// Parameter types are passed in via [`TypeId`] values from an iterator.
#[inline(always)]
pub fn calc_fn_params_hash(params: impl Iterator<Item = TypeId>) -> u64 {
let s = &mut get_hasher();
let mut len = 0;
params.for_each(|t| {
t.hash(s);
len += 1;
});
len.hash(s);
s.finish()
2020-12-24 11:43:04 +01:00
}
2021-03-08 08:30:32 +01:00
/// Combine two [`u64`] hashes by taking the XOR of them.
2020-12-24 11:43:04 +01:00
#[inline(always)]
2021-03-08 08:30:32 +01:00
pub(crate) fn combine_hashes(a: u64, b: u64) -> u64 {
a ^ b
}
2021-01-05 11:37:07 +01:00
/// _(INTERNALS)_ A type that wraps a [`HashMap`] and implements [`Hash`].
/// Exported under the `internals` feature only.
#[derive(Clone, Default)]
pub struct HashableHashMap<K, T, H: BuildHasher>(HashMap<K, T, H>);
impl<K, T, H: BuildHasher> From<HashMap<K, T, H>> for HashableHashMap<K, T, H> {
#[inline(always)]
2021-01-05 11:37:07 +01:00
fn from(value: HashMap<K, T, H>) -> Self {
Self(value)
}
}
impl<K, T, H: BuildHasher> AsRef<HashMap<K, T, H>> for HashableHashMap<K, T, H> {
#[inline(always)]
2021-01-05 11:37:07 +01:00
fn as_ref(&self) -> &HashMap<K, T, H> {
&self.0
}
}
impl<K, T, H: BuildHasher> AsMut<HashMap<K, T, H>> for HashableHashMap<K, T, H> {
#[inline(always)]
2021-01-05 11:37:07 +01:00
fn as_mut(&mut self) -> &mut HashMap<K, T, H> {
&mut self.0
}
}
impl<K, T, H: BuildHasher> Deref for HashableHashMap<K, T, H> {
type Target = HashMap<K, T, H>;
#[inline(always)]
2021-01-05 11:37:07 +01:00
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<K, T, H: BuildHasher> DerefMut for HashableHashMap<K, T, H> {
#[inline(always)]
2021-01-05 11:37:07 +01:00
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<K: Debug, T: Debug, H: BuildHasher> Debug for HashableHashMap<K, T, H> {
#[inline(always)]
2021-01-05 11:37:07 +01:00
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl<K: Hash + Ord, T: Hash, H: BuildHasher> Hash for HashableHashMap<K, T, H> {
#[inline(always)]
2021-01-05 11:37:07 +01:00
fn hash<B: Hasher>(&self, state: &mut B) {
let mut keys: Vec<_> = self.0.keys().collect();
keys.sort();
keys.into_iter().for_each(|key| {
key.hash(state);
self.0.get(&key).unwrap().hash(state);
});
}
}
2020-05-26 08:14:03 +02:00
/// The system immutable string type.
///
2020-11-20 09:52:28 +01:00
/// An [`ImmutableString`] wraps an [`Rc`][std::rc::Rc]`<`[`String`]`>`
/// (or [`Arc`][std::sync::Arc]`<`[`String`]`>` under the `sync` feature)
2020-05-26 08:14:03 +02:00
/// so that it can be simply shared and not cloned.
///
2020-10-27 04:30:38 +01:00
/// # Example
2020-05-26 08:14:03 +02:00
///
/// ```
/// use rhai::ImmutableString;
///
/// let s1: ImmutableString = "hello".into();
///
/// // No actual cloning of the string is involved below.
/// let s2 = s1.clone();
/// let s3 = s2.clone();
///
/// assert_eq!(s1, s2);
///
/// // Clones the underlying string (because it is already shared) and extracts it.
/// let mut s: String = s1.into_owned();
///
/// // Changing the clone has no impact on the previously shared version.
/// s.push_str(", world!");
///
/// // The old version still exists.
/// assert_eq!(s2, s3);
/// assert_eq!(s2.as_str(), "hello");
///
/// // Not equals!
/// assert_ne!(s2.as_str(), s.as_str());
/// assert_eq!(s, "hello, world!");
/// ```
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
pub struct ImmutableString(Shared<String>);
impl Deref for ImmutableString {
type Target = String;
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-05-26 08:14:03 +02:00
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl AsRef<String> for ImmutableString {
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-05-26 08:14:03 +02:00
fn as_ref(&self) -> &String {
&self.0
}
}
impl Borrow<String> for ImmutableString {
2020-10-08 16:25:50 +02:00
#[inline(always)]
fn borrow(&self) -> &String {
&self.0
}
}
2020-05-26 08:14:03 +02:00
impl Borrow<str> for ImmutableString {
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-05-26 08:14:03 +02:00
fn borrow(&self) -> &str {
self.0.as_str()
}
}
impl From<&str> for ImmutableString {
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-05-26 08:14:03 +02:00
fn from(value: &str) -> Self {
Self(value.to_string().into())
}
}
2020-12-30 14:12:51 +01:00
impl From<&String> for ImmutableString {
#[inline(always)]
fn from(value: &String) -> Self {
Self(value.to_string().into())
}
}
2020-05-26 08:14:03 +02:00
impl From<String> for ImmutableString {
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-05-26 08:14:03 +02:00
fn from(value: String) -> Self {
Self(value.into())
}
}
impl From<Box<String>> for ImmutableString {
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-05-26 08:14:03 +02:00
fn from(value: Box<String>) -> Self {
Self(value.into())
}
}
impl From<ImmutableString> for String {
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-05-26 08:14:03 +02:00
fn from(value: ImmutableString) -> Self {
value.into_owned()
}
}
impl FromStr for ImmutableString {
type Err = ();
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-05-26 08:14:03 +02:00
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(s.to_string().into()))
}
}
impl FromIterator<char> for ImmutableString {
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-05-26 08:14:03 +02:00
fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
Self(iter.into_iter().collect::<String>().into())
}
}
impl<'a> FromIterator<&'a char> for ImmutableString {
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-05-26 08:14:03 +02:00
fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> Self {
Self(iter.into_iter().cloned().collect::<String>().into())
}
}
impl<'a> FromIterator<&'a str> for ImmutableString {
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-05-26 08:14:03 +02:00
fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
Self(iter.into_iter().collect::<String>().into())
}
}
impl<'a> FromIterator<String> for ImmutableString {
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-05-26 08:14:03 +02:00
fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
Self(iter.into_iter().collect::<String>().into())
}
}
2021-01-05 11:37:07 +01:00
impl Display for ImmutableString {
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-05-26 08:14:03 +02:00
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2021-01-05 11:37:07 +01:00
Display::fmt(self.0.as_str(), f)
2020-05-26 08:14:03 +02:00
}
}
2021-01-05 11:37:07 +01:00
impl Debug for ImmutableString {
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-05-26 08:14:03 +02:00
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2021-01-05 11:37:07 +01:00
Debug::fmt(self.0.as_str(), f)
2020-05-26 08:14:03 +02:00
}
}
impl Add for ImmutableString {
type Output = Self;
2020-10-08 16:25:50 +02:00
#[inline]
2020-05-26 08:14:03 +02:00
fn add(mut self, rhs: Self) -> Self::Output {
if rhs.is_empty() {
self
} else if self.is_empty() {
rhs
} else {
self.make_mut().push_str(rhs.0.as_str());
self
}
}
}
impl Add for &ImmutableString {
type Output = ImmutableString;
2020-10-08 16:25:50 +02:00
#[inline]
2020-05-26 08:14:03 +02:00
fn add(self, rhs: Self) -> Self::Output {
if rhs.is_empty() {
self.clone()
} else if self.is_empty() {
rhs.clone()
} else {
let mut s = self.clone();
s.make_mut().push_str(rhs.0.as_str());
s
}
}
}
impl AddAssign<&ImmutableString> for ImmutableString {
2020-10-08 16:25:50 +02:00
#[inline]
2020-05-26 08:14:03 +02:00
fn add_assign(&mut self, rhs: &ImmutableString) {
if !rhs.is_empty() {
if self.is_empty() {
self.0 = rhs.0.clone();
} else {
self.make_mut().push_str(rhs.0.as_str());
}
}
}
}
impl AddAssign<ImmutableString> for ImmutableString {
2020-10-08 16:25:50 +02:00
#[inline]
fn add_assign(&mut self, rhs: ImmutableString) {
if !rhs.is_empty() {
if self.is_empty() {
self.0 = rhs.0;
} else {
self.make_mut().push_str(rhs.0.as_str());
}
}
}
}
2020-05-26 08:14:03 +02:00
impl Add<&str> for ImmutableString {
type Output = Self;
2020-10-08 16:25:50 +02:00
#[inline]
2020-05-26 08:14:03 +02:00
fn add(mut self, rhs: &str) -> Self::Output {
if rhs.is_empty() {
self
} else {
self.make_mut().push_str(rhs);
self
}
}
}
impl Add<&str> for &ImmutableString {
type Output = ImmutableString;
2020-10-08 16:25:50 +02:00
#[inline]
2020-05-26 08:14:03 +02:00
fn add(self, rhs: &str) -> Self::Output {
if rhs.is_empty() {
self.clone()
} else {
let mut s = self.clone();
s.make_mut().push_str(rhs);
s
}
}
}
impl AddAssign<&str> for ImmutableString {
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-05-26 08:14:03 +02:00
fn add_assign(&mut self, rhs: &str) {
if !rhs.is_empty() {
self.make_mut().push_str(rhs);
}
}
}
impl Add<String> for ImmutableString {
type Output = Self;
2020-10-08 16:25:50 +02:00
#[inline]
2020-05-26 08:14:03 +02:00
fn add(mut self, rhs: String) -> Self::Output {
if rhs.is_empty() {
self
} else if self.is_empty() {
rhs.into()
} else {
self.make_mut().push_str(&rhs);
self
}
}
}
impl Add<String> for &ImmutableString {
type Output = ImmutableString;
2020-10-08 16:25:50 +02:00
#[inline]
2020-05-26 08:14:03 +02:00
fn add(self, rhs: String) -> Self::Output {
if rhs.is_empty() {
self.clone()
} else if self.is_empty() {
rhs.into()
} else {
let mut s = self.clone();
s.make_mut().push_str(&rhs);
s
}
}
}
impl AddAssign<String> for ImmutableString {
#[inline(always)]
fn add_assign(&mut self, rhs: String) {
self.make_mut().push_str(&rhs);
}
}
2020-05-26 08:14:03 +02:00
impl Add<char> for ImmutableString {
type Output = Self;
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-05-26 08:14:03 +02:00
fn add(mut self, rhs: char) -> Self::Output {
self.make_mut().push(rhs);
self
}
}
impl Add<char> for &ImmutableString {
type Output = ImmutableString;
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-05-26 08:14:03 +02:00
fn add(self, rhs: char) -> Self::Output {
let mut s = self.clone();
s.make_mut().push(rhs);
s
}
}
impl AddAssign<char> for ImmutableString {
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-05-26 08:14:03 +02:00
fn add_assign(&mut self, rhs: char) {
self.make_mut().push(rhs);
}
}
impl Sub for ImmutableString {
type Output = Self;
#[inline]
fn sub(self, rhs: Self) -> Self::Output {
if rhs.is_empty() {
self
} else if self.is_empty() {
rhs
} else {
self.replace(rhs.as_str(), "").into()
}
}
}
impl Sub for &ImmutableString {
type Output = ImmutableString;
#[inline]
fn sub(self, rhs: Self) -> Self::Output {
if rhs.is_empty() {
self.clone()
} else if self.is_empty() {
rhs.clone()
} else {
self.replace(rhs.as_str(), "").into()
}
}
}
impl SubAssign<&ImmutableString> for ImmutableString {
#[inline]
fn sub_assign(&mut self, rhs: &ImmutableString) {
if !rhs.is_empty() {
if self.is_empty() {
self.0 = rhs.0.clone();
} else {
self.0 = self.replace(rhs.as_str(), "").into();
}
}
}
}
impl SubAssign<ImmutableString> for ImmutableString {
#[inline]
fn sub_assign(&mut self, rhs: ImmutableString) {
if !rhs.is_empty() {
if self.is_empty() {
self.0 = rhs.0;
} else {
self.0 = self.replace(rhs.as_str(), "").into();
}
}
}
}
impl Sub<String> for ImmutableString {
type Output = Self;
#[inline]
fn sub(self, rhs: String) -> Self::Output {
if rhs.is_empty() {
self
} else if self.is_empty() {
rhs.into()
} else {
self.replace(&rhs, "").into()
}
}
}
impl Sub<String> for &ImmutableString {
type Output = ImmutableString;
#[inline]
fn sub(self, rhs: String) -> Self::Output {
if rhs.is_empty() {
self.clone()
} else if self.is_empty() {
rhs.into()
} else {
self.replace(&rhs, "").into()
}
}
}
impl SubAssign<String> for ImmutableString {
#[inline(always)]
fn sub_assign(&mut self, rhs: String) {
self.0 = self.replace(&rhs, "").into();
}
}
impl Sub<char> for ImmutableString {
type Output = Self;
#[inline(always)]
fn sub(self, rhs: char) -> Self::Output {
self.replace(rhs, "").into()
}
}
impl Sub<char> for &ImmutableString {
type Output = ImmutableString;
#[inline(always)]
fn sub(self, rhs: char) -> Self::Output {
self.replace(rhs, "").into()
}
}
impl SubAssign<char> for ImmutableString {
#[inline(always)]
fn sub_assign(&mut self, rhs: char) {
self.0 = self.replace(rhs, "").into();
}
}
impl<S: AsRef<str>> PartialEq<S> for ImmutableString {
2020-10-08 16:25:50 +02:00
#[inline(always)]
fn eq(&self, other: &S) -> bool {
self.as_str().eq(other.as_ref())
}
}
impl PartialEq<ImmutableString> for str {
2020-10-08 16:25:50 +02:00
#[inline(always)]
fn eq(&self, other: &ImmutableString) -> bool {
self.eq(other.as_str())
}
}
impl PartialEq<ImmutableString> for String {
2020-10-08 16:25:50 +02:00
#[inline(always)]
fn eq(&self, other: &ImmutableString) -> bool {
self.eq(other.as_str())
}
}
impl<S: AsRef<str>> PartialOrd<S> for ImmutableString {
2020-10-08 16:25:50 +02:00
#[inline(always)]
fn partial_cmp(&self, other: &S) -> Option<Ordering> {
self.as_str().partial_cmp(other.as_ref())
}
}
impl PartialOrd<ImmutableString> for str {
2020-10-08 16:25:50 +02:00
#[inline(always)]
fn partial_cmp(&self, other: &ImmutableString) -> Option<Ordering> {
self.partial_cmp(other.as_str())
}
}
impl PartialOrd<ImmutableString> for String {
2020-10-08 16:25:50 +02:00
#[inline(always)]
fn partial_cmp(&self, other: &ImmutableString) -> Option<Ordering> {
self.as_str().partial_cmp(other.as_str())
}
}
2020-05-26 08:14:03 +02:00
impl ImmutableString {
2020-11-20 09:52:28 +01:00
/// Consume the [`ImmutableString`] and convert it into a [`String`].
2020-05-26 08:14:03 +02:00
/// If there are other references to the same string, a cloned copy is returned.
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-05-26 08:14:03 +02:00
pub fn into_owned(mut self) -> String {
self.make_mut(); // Make sure it is unique reference
shared_take(self.0) // Should succeed
}
2020-11-20 09:52:28 +01:00
/// Make sure that the [`ImmutableString`] is unique (i.e. no other outstanding references).
/// Then return a mutable reference to the [`String`].
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-05-26 08:14:03 +02:00
pub fn make_mut(&mut self) -> &mut String {
shared_make_mut(&mut self.0)
}
}