Build in operators between string and char.

This commit is contained in:
Stephen Chung
2021-02-25 13:29:49 +08:00
parent f03983a9ca
commit 3f4dba9dbc
8 changed files with 271 additions and 55 deletions

View File

@@ -17,7 +17,6 @@ use crate::stdlib::{
iter::{empty, once},
mem,
num::NonZeroU64,
ops::Deref,
string::ToString,
vec::Vec,
};
@@ -1470,28 +1469,60 @@ pub fn run_builtin_binary_op(
}
}
// char op string
if types_pair == (TypeId::of::<char>(), TypeId::of::<ImmutableString>()) {
let x = x.clone().cast::<char>();
let y = &*y.read_lock::<ImmutableString>().unwrap();
match op {
"+" => return Ok(Some(format!("{}{}", x, y).into())),
"==" | "!=" | ">" | ">=" | "<" | "<=" => {
let s1 = [x, '\0'];
let mut y = y.chars();
let s2 = [y.next().unwrap_or('\0'), y.next().unwrap_or('\0')];
match op {
"==" => return Ok(Some((s1 == s2).into())),
"!=" => return Ok(Some((s1 != s2).into())),
">" => return Ok(Some((s1 > s2).into())),
">=" => return Ok(Some((s1 >= s2).into())),
"<" => return Ok(Some((s1 < s2).into())),
"<=" => return Ok(Some((s1 <= s2).into())),
_ => unreachable!(),
}
}
_ => return Ok(None),
}
}
// string op char
if types_pair == (TypeId::of::<ImmutableString>(), TypeId::of::<char>()) {
let x = &*x.read_lock::<ImmutableString>().unwrap();
let y = y.clone().cast::<char>();
match op {
"+" => return Ok(Some((x + y).into())),
"-" => return Ok(Some((x - y).into())),
"==" | "!=" | ">" | ">=" | "<" | "<=" => {
let mut x = x.chars();
let s1 = [x.next().unwrap_or('\0'), x.next().unwrap_or('\0')];
let s2 = [y, '\0'];
match op {
"==" => return Ok(Some((s1 == s2).into())),
"!=" => return Ok(Some((s1 != s2).into())),
">" => return Ok(Some((s1 > s2).into())),
">=" => return Ok(Some((s1 >= s2).into())),
"<" => return Ok(Some((s1 < s2).into())),
"<=" => return Ok(Some((s1 <= s2).into())),
_ => unreachable!(),
}
}
_ => return Ok(None),
}
}
// Default comparison operators for different types
if type2 != type1 {
// char op string
if types_pair == (TypeId::of::<char>(), TypeId::of::<ImmutableString>()) {
let x = x.clone().cast::<char>();
let y = &*y.read_lock::<ImmutableString>().unwrap();
match op {
"+" => return Ok(Some(format!("{}{}", x, y).into())),
_ => return Ok(None),
}
}
// string op char
if types_pair == (TypeId::of::<ImmutableString>(), TypeId::of::<char>()) {
let x = &*x.read_lock::<ImmutableString>().unwrap();
let y = y.clone().cast::<char>();
match op {
"+" => return Ok(Some((x + y).into())),
_ => return Ok(None),
}
}
// Default comparison operators for different types
return Ok(match op {
"!=" => Some(Dynamic::TRUE),
"==" | ">" | ">=" | "<" | "<=" => Some(Dynamic::FALSE),
@@ -1567,6 +1598,7 @@ pub fn run_builtin_binary_op(
match op {
"+" => return Ok(Some((x + y).into())),
"-" => return Ok(Some((x - y).into())),
"==" => return Ok(Some((x == y).into())),
"!=" => return Ok(Some((x != y).into())),
">" => return Ok(Some((x > y).into())),
@@ -1673,17 +1705,34 @@ pub fn run_builtin_op_assignment(
}
}
if type2 != type1 {
if types_pair == (TypeId::of::<ImmutableString>(), TypeId::of::<char>()) {
let y = y.read_lock::<char>().unwrap().deref().clone();
let mut x = x.write_lock::<ImmutableString>().unwrap();
// string op= char
if types_pair == (TypeId::of::<ImmutableString>(), TypeId::of::<char>()) {
let y = y.clone().cast::<char>();
let mut x = x.write_lock::<ImmutableString>().unwrap();
match op {
"+=" => return Ok(Some(*x += y)),
_ => return Ok(None),
}
match op {
"+=" => return Ok(Some(*x += y)),
"-=" => return Ok(Some(*x -= y)),
_ => return Ok(None),
}
}
// char op= string
if types_pair == (TypeId::of::<char>(), TypeId::of::<ImmutableString>()) {
let y = y.read_lock::<ImmutableString>().unwrap();
let mut ch = x.read_lock::<char>().unwrap().to_string();
let mut x = x.write_lock::<Dynamic>().unwrap();
match op {
"+=" => {
ch.push_str(y.as_str());
return Ok(Some(*x = ch.into()));
}
_ => return Ok(None),
}
}
// No built-in op-assignments for different types.
if type2 != type1 {
return Ok(None);
}
@@ -1741,7 +1790,7 @@ pub fn run_builtin_op_assignment(
}
if type1 == TypeId::of::<char>() {
let y = y.read_lock::<char>().unwrap().deref().clone();
let y = y.clone().cast::<char>();
let mut x = x.write_lock::<Dynamic>().unwrap();
match op {
@@ -1751,11 +1800,12 @@ pub fn run_builtin_op_assignment(
}
if type1 == TypeId::of::<ImmutableString>() {
let y = y.read_lock::<ImmutableString>().unwrap().deref().clone();
let y = &*y.read_lock::<ImmutableString>().unwrap();
let mut x = x.write_lock::<ImmutableString>().unwrap();
match op {
"+=" => return Ok(Some(*x += y)),
"-=" => return Ok(Some(*x -= y)),
_ => return Ok(None),
}
}

View File

@@ -20,7 +20,7 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str
mod string_functions {
use crate::ImmutableString;
#[rhai_fn(name = "+")]
#[rhai_fn(name = "+", name = "append")]
pub fn add_append(string: &str, item: Dynamic) -> ImmutableString {
format!("{}{}", string, item).into()
}
@@ -42,6 +42,13 @@ mod string_functions {
pub fn len(string: &str) -> INT {
string.chars().count() as INT
}
pub fn remove(string: &mut ImmutableString, sub_string: ImmutableString) {
*string -= sub_string;
}
#[rhai_fn(name = "remove")]
pub fn remove_char(string: &mut ImmutableString, character: char) {
*string -= character;
}
pub fn clear(string: &mut ImmutableString) {
string.make_mut().clear();
}
@@ -64,15 +71,15 @@ mod string_functions {
}
#[rhai_fn(name = "contains")]
pub fn contains_char(string: &str, ch: char) -> bool {
string.contains(ch)
pub fn contains_char(string: &str, character: char) -> bool {
string.contains(character)
}
pub fn contains(string: &str, find_string: &str) -> bool {
string.contains(find_string)
}
#[rhai_fn(name = "index_of")]
pub fn index_of_char_starting_from(string: &str, ch: char, start: INT) -> INT {
pub fn index_of_char_starting_from(string: &str, character: char, start: INT) -> INT {
let start = if start < 0 {
0
} else if start as usize >= string.chars().count() {
@@ -86,14 +93,14 @@ mod string_functions {
};
string[start..]
.find(ch)
.find(character)
.map(|index| string[0..start + index].chars().count() as INT)
.unwrap_or(-1 as INT)
}
#[rhai_fn(name = "index_of")]
pub fn index_of_char(string: &str, ch: char) -> INT {
pub fn index_of_char(string: &str, character: char) -> INT {
string
.find(ch)
.find(character)
.map(|index| string[0..index].chars().count() as INT)
.unwrap_or(-1 as INT)
}
@@ -196,26 +203,33 @@ mod string_functions {
pub fn replace_string_with_char(
string: &mut ImmutableString,
find_string: &str,
substitute_char: char,
substitute_character: char,
) {
*string = string
.replace(find_string, &substitute_char.to_string())
.replace(find_string, &substitute_character.to_string())
.into();
}
#[rhai_fn(name = "replace")]
pub fn replace_char_with_string(
string: &mut ImmutableString,
find_char: char,
find_character: char,
substitute_string: &str,
) {
*string = string
.replace(&find_char.to_string(), substitute_string)
.replace(&find_character.to_string(), substitute_string)
.into();
}
#[rhai_fn(name = "replace")]
pub fn replace_char(string: &mut ImmutableString, find_char: char, substitute_char: char) {
pub fn replace_char(
string: &mut ImmutableString,
find_character: char,
substitute_character: char,
) {
*string = string
.replace(&find_char.to_string(), &substitute_char.to_string())
.replace(
&find_character.to_string(),
&substitute_character.to_string(),
)
.into();
}
@@ -224,7 +238,7 @@ mod string_functions {
_ctx: NativeCallContext,
string: &mut ImmutableString,
len: INT,
ch: char,
character: char,
) -> Result<Dynamic, Box<crate::EvalAltResult>> {
// Check if string will be over max size limit
#[cfg(not(feature = "unchecked"))]
@@ -243,7 +257,7 @@ mod string_functions {
let p = string.make_mut();
for _ in 0..(len as usize - orig_len) {
p.push(ch);
p.push(character);
}
#[cfg(not(feature = "unchecked"))]

View File

@@ -12,7 +12,7 @@ use crate::stdlib::{
hash::{BuildHasher, Hash, Hasher},
iter::{empty, FromIterator},
num::NonZeroU64,
ops::{Add, AddAssign, Deref, DerefMut},
ops::{Add, AddAssign, Deref, DerefMut, Sub, SubAssign},
str::FromStr,
string::{String, ToString},
vec::Vec,
@@ -468,6 +468,13 @@ impl Add<String> for &ImmutableString {
}
}
impl AddAssign<String> for ImmutableString {
#[inline(always)]
fn add_assign(&mut self, rhs: String) {
self.make_mut().push_str(&rhs);
}
}
impl Add<char> for ImmutableString {
type Output = Self;
@@ -496,6 +503,124 @@ impl AddAssign<char> for ImmutableString {
}
}
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 {
#[inline(always)]
fn eq(&self, other: &S) -> bool {