From 209d1a174ccd1db366e01f91381ab83956c4ac75 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sat, 15 Aug 2020 00:04:10 +0800 Subject: [PATCH] Yet more packages into plugins. --- src/module.rs | 12 + src/packages/array_basic.rs | 19 +- src/packages/map_basic.rs | 136 +++++----- src/packages/math_basic.rs | 64 ++++- src/packages/string_more.rs | 505 ++++++++++++++++++++---------------- src/packages/time_basic.rs | 2 +- tests/macro_register.rs | 1 - tests/macro_unroll.rs | 2 +- 8 files changed, 425 insertions(+), 316 deletions(-) diff --git a/src/module.rs b/src/module.rs index dbb416a2..28c64ff0 100644 --- a/src/module.rs +++ b/src/module.rs @@ -928,6 +928,18 @@ impl Module { self.all_functions.get(&hash_qualified_fn) } + /// Combine another module into this module. + /// The other module is consumed to merge into this module. + pub fn combine(&mut self, other: Self) -> &mut Self { + self.variables.extend(other.variables.into_iter()); + self.functions.extend(other.functions.into_iter()); + self.type_iterators.extend(other.type_iterators.into_iter()); + self.all_functions.clear(); + self.all_variables.clear(); + self.indexed = false; + self + } + /// Merge another module into this module. pub fn merge(&mut self, other: &Self) -> &mut Self { self.merge_filtered(other, |_, _, _| true) diff --git a/src/packages/array_basic.rs b/src/packages/array_basic.rs index d173bcf2..a75fe369 100644 --- a/src/packages/array_basic.rs +++ b/src/packages/array_basic.rs @@ -3,7 +3,7 @@ use crate::any::{Dynamic, Variant}; use crate::def_package; -use crate::engine::{Array, Engine}; +use crate::engine::{make_getter, Array, Engine}; use crate::fn_native::FnPtr; use crate::parser::{ImmutableString, INT}; use crate::plugin::*; @@ -57,7 +57,7 @@ macro_rules! reg_pad { } def_package!(crate:BasicArrayPackage:"Basic array utilities.", lib, { - lib.merge(&exported_module!(array_functions)); + lib.combine(exported_module!(array_functions)); set_exported_fn!(lib, "+", append); set_exported_fn!(lib, "+", concat); @@ -84,7 +84,7 @@ def_package!(crate:BasicArrayPackage:"Basic array utilities.", lib, { } #[cfg(not(feature = "no_object"))] - lib.set_getter_fn("len", |list: &mut Array| Ok(list.len() as INT)); + set_exported_fn!(lib, make_getter("len"), array_funcs::len); // Register array iterator lib.set_iter( @@ -106,7 +106,7 @@ fn concat(mut x: Array, y: Array) -> Array { #[export_module] mod array_functions { pub fn len(list: &mut Array) -> INT { - list.len() as INT + array_funcs::len(list) } pub fn append(x: &mut Array, y: Array) { x.extend(y); @@ -140,6 +140,17 @@ mod array_functions { } } +mod array_funcs { + use crate::engine::Array; + use crate::parser::INT; + use crate::plugin::*; + + #[export_fn] + pub fn len(list: &mut Array) -> INT { + list.len() as INT + } +} + // Register array utility functions fn push(list: &mut Array, item: T) { list.push(Dynamic::from(item)); diff --git a/src/packages/map_basic.rs b/src/packages/map_basic.rs index 4e2e58ad..bb2f4f09 100644 --- a/src/packages/map_basic.rs +++ b/src/packages/map_basic.rs @@ -2,78 +2,80 @@ use crate::any::Dynamic; use crate::def_package; -use crate::engine::Map; -use crate::module::FuncReturn; +use crate::engine::{make_getter, Map}; use crate::parser::{ImmutableString, INT}; +use crate::plugin::*; use crate::stdlib::vec::Vec; -fn map_get_keys(map: &mut Map) -> FuncReturn> { - Ok(map.iter().map(|(k, _)| k.clone().into()).collect()) -} -fn map_get_values(map: &mut Map) -> FuncReturn> { - Ok(map.iter().map(|(_, v)| v.clone()).collect()) -} - def_package!(crate:BasicMapPackage:"Basic object map utilities.", lib, { - lib.set_fn_2_mut( - "has", - |map: &mut Map, prop: ImmutableString| Ok(map.contains_key(&prop)), - ); - lib.set_fn_1_mut("len", |map: &mut Map| Ok(map.len() as INT)); - lib.set_fn_1_mut("clear", |map: &mut Map| { - map.clear(); - Ok(()) - }); - lib.set_fn_2_mut( - "remove", - |x: &mut Map, name: ImmutableString| Ok(x.remove(&name).unwrap_or_else(|| ().into())), - ); - lib.set_fn_2_mut( - "mixin", - |map1: &mut Map, map2: Map| { - map2.into_iter().for_each(|(key, value)| { - map1.insert(key, value); - }); - Ok(()) - }, - ); - lib.set_fn_2_mut( - "fill_with", - |map1: &mut Map, map2: Map| { - map2.into_iter().for_each(|(key, value)| { - if !map1.contains_key(&key) { - map1.insert(key, value); - } - }); - Ok(()) - }, - ); - lib.set_fn_2_mut( - "+=", - |map1: &mut Map, map2: Map| { - map2.into_iter().for_each(|(key, value)| { - map1.insert(key, value); - }); - Ok(()) - }, - ); - lib.set_fn_2( - "+", - |mut map1: Map, map2: Map| { - map2.into_iter().for_each(|(key, value)| { - map1.insert(key, value); - }); - Ok(map1) - }, - ); + lib.combine(exported_module!(map_functions)); + set_exported_fn!(lib, make_getter("len"), map_funcs::len); + set_exported_fn!(lib, "+=", map_funcs::mixin); + set_exported_fn!(lib, "+", map_funcs::merge); // Register map access functions - if cfg!(not(feature = "no_index")) { - lib.set_fn_1_mut("keys", map_get_keys); - } - - if cfg!(not(feature = "no_index")) { - lib.set_fn_1_mut("values", map_get_values); - } + #[cfg(not(feature = "no_index"))] + lib.combine(exported_module!(index_functions)); }); + +#[export_module] +mod map_functions { + pub fn has(map: &mut Map, prop: ImmutableString) -> bool { + map.contains_key(&prop) + } + pub fn len(map: &mut Map) -> INT { + map_funcs::len(map) + } + pub fn clear(map: &mut Map) { + map.clear(); + } + pub fn remove(x: &mut Map, name: ImmutableString) -> Dynamic { + x.remove(&name).unwrap_or_else(|| ().into()) + } + pub fn mixin(map1: &mut Map, map2: Map) { + map_funcs::mixin(map1, map2); + } + pub fn fill_with(map1: &mut Map, map2: Map) { + map2.into_iter().for_each(|(key, value)| { + if !map1.contains_key(&key) { + map1.insert(key, value); + } + }); + } +} + +mod map_funcs { + use crate::engine::Map; + use crate::parser::INT; + use crate::plugin::*; + + #[export_fn] + pub fn len(map: &mut Map) -> INT { + map.len() as INT + } + #[export_fn] + pub fn mixin(map1: &mut Map, map2: Map) { + map2.into_iter().for_each(|(key, value)| { + map1.insert(key, value); + }); + } + #[export_fn] + pub fn merge(mut map1: Map, map2: Map) -> Map { + map2.into_iter().for_each(|(key, value)| { + map1.insert(key, value); + }); + map1 + } +} + +#[cfg(not(feature = "no_index"))] +#[export_module] +mod index_functions { + pub fn keys(map: &mut Map) -> Vec { + map.iter().map(|(k, _)| k.clone().into()).collect() + } + pub fn values(map: &mut Map) -> Vec { + map.iter().map(|(_, v)| v.clone()).collect() + } +} diff --git a/src/packages/math_basic.rs b/src/packages/math_basic.rs index 322626e7..e8b267fb 100644 --- a/src/packages/math_basic.rs +++ b/src/packages/math_basic.rs @@ -1,4 +1,5 @@ use crate::def_package; +use crate::engine::make_getter; use crate::parser::INT; use crate::plugin::*; @@ -26,23 +27,23 @@ def_package!(crate:BasicMathPackage:"Basic mathematic functions.", lib, { #[cfg(not(feature = "no_float"))] { // Floating point functions - lib.merge(&exported_module!(float)); + lib.combine(exported_module!(float_functions)); // Floating point properties #[cfg(not(feature = "no_object"))] { - lib.set_getter_fn("floor", |x: &mut FLOAT| Ok(x.floor())); - lib.set_getter_fn("ceiling", |x: &mut FLOAT| Ok(x.ceil())); - lib.set_getter_fn("round", |x: &mut FLOAT| Ok(x.ceil())); - lib.set_getter_fn("int", |x: &mut FLOAT| Ok(x.trunc())); - lib.set_getter_fn("fraction", |x: &mut FLOAT| Ok(x.fract())); - lib.set_getter_fn("is_nan", |x: &mut FLOAT| Ok(x.is_nan())); - lib.set_getter_fn("is_finite", |x: &mut FLOAT| Ok(x.is_finite())); - lib.set_getter_fn("is_infinite", |x: &mut FLOAT| Ok(x.is_infinite())); + set_exported_fn!(lib, make_getter("floor"), float_funcs::floor); + set_exported_fn!(lib, make_getter("ceiling"), float_funcs::ceiling); + set_exported_fn!(lib, make_getter("round"), float_funcs::round); + set_exported_fn!(lib, make_getter("int"), float_funcs::int); + set_exported_fn!(lib, make_getter("fraction"), float_funcs::fraction); + set_exported_fn!(lib, make_getter("is_nan"), float_funcs::is_nan); + set_exported_fn!(lib, make_getter("is_finite"), float_funcs::is_finite); + set_exported_fn!(lib, make_getter("is_infinite"), float_funcs::is_infinite); } // Trig functions - lib.merge(&exported_module!(trig)); + lib.combine(exported_module!(trig_functions)); // Register conversion functions lib.set_fn_1("to_float", |x: INT| Ok(x as FLOAT)); @@ -119,7 +120,7 @@ def_package!(crate:BasicMathPackage:"Basic mathematic functions.", lib, { #[cfg(not(feature = "no_float"))] #[export_module] -mod trig { +mod trig_functions { use crate::parser::FLOAT; pub fn sin(x: FLOAT) -> FLOAT { @@ -162,7 +163,7 @@ mod trig { #[cfg(not(feature = "no_float"))] #[export_module] -mod float { +mod float_functions { use crate::parser::FLOAT; pub fn sqrt(x: FLOAT) -> FLOAT { @@ -180,27 +181,66 @@ mod float { pub fn log10(x: FLOAT) -> FLOAT { x.log10() } + pub fn floor(x: FLOAT) -> FLOAT { + float_funcs::floor(x) + } + pub fn ceiling(x: FLOAT) -> FLOAT { + float_funcs::ceiling(x) + } + pub fn round(x: FLOAT) -> FLOAT { + float_funcs::round(x) + } + pub fn int(x: FLOAT) -> FLOAT { + float_funcs::int(x) + } + pub fn fraction(x: FLOAT) -> FLOAT { + float_funcs::fraction(x) + } + pub fn is_nan(x: FLOAT) -> bool { + float_funcs::is_nan(x) + } + pub fn is_finite(x: FLOAT) -> bool { + float_funcs::is_finite(x) + } + pub fn is_infinite(x: FLOAT) -> bool { + float_funcs::is_infinite(x) + } +} + +#[cfg(not(feature = "no_float"))] +mod float_funcs { + use crate::parser::FLOAT; + use crate::plugin::*; + + #[export_fn] pub fn floor(x: FLOAT) -> FLOAT { x.floor() } + #[export_fn] pub fn ceiling(x: FLOAT) -> FLOAT { x.ceil() } + #[export_fn] pub fn round(x: FLOAT) -> FLOAT { x.ceil() } + #[export_fn] pub fn int(x: FLOAT) -> FLOAT { x.trunc() } + #[export_fn] pub fn fraction(x: FLOAT) -> FLOAT { x.fract() } + #[export_fn] pub fn is_nan(x: FLOAT) -> bool { x.is_nan() } + #[export_fn] pub fn is_finite(x: FLOAT) -> bool { x.is_finite() } + #[export_fn] pub fn is_infinite(x: FLOAT) -> bool { x.is_infinite() } diff --git a/src/packages/string_more.rs b/src/packages/string_more.rs index 0b58c19d..56f3a1d7 100644 --- a/src/packages/string_more.rs +++ b/src/packages/string_more.rs @@ -1,9 +1,11 @@ +#![allow(non_snake_case)] + use crate::any::Dynamic; use crate::def_package; -use crate::engine::Engine; +use crate::engine::{make_getter, Engine}; use crate::fn_native::FnPtr; -use crate::module::{FuncReturn, Module}; use crate::parser::{ImmutableString, INT}; +use crate::plugin::*; use crate::utils::StaticVec; #[cfg(not(feature = "unchecked"))] @@ -13,220 +15,82 @@ use crate::{result::EvalAltResult, token::Position}; use crate::engine::Array; use crate::stdlib::{ - any::TypeId, - boxed::Box, - fmt::Display, - format, mem, - string::{String, ToString}, - vec::Vec, + any::TypeId, boxed::Box, fmt::Display, format, mem, string::ToString, vec::Vec, }; -fn prepend(x: T, y: ImmutableString) -> FuncReturn { - Ok(format!("{}{}", x, y).into()) -} -fn append(x: ImmutableString, y: T) -> FuncReturn { - Ok(format!("{}{}", x, y).into()) -} -fn sub_string(s: ImmutableString, start: INT, len: INT) -> FuncReturn { - let offset = if s.is_empty() || len <= 0 { - return Ok("".to_string().into()); - } else if start < 0 { - 0 - } else if (start as usize) >= s.chars().count() { - return Ok("".to_string().into()); - } else { - start as usize - }; +macro_rules! gen_concat_functions { + ($root:ident => $($arg_type:ident),+ ) => { + pub mod $root { $( + pub mod $arg_type { + use super::super::*; - let chars: StaticVec<_> = s.chars().collect(); + #[export_fn] + pub fn append_func(x: ImmutableString, y: $arg_type) -> String { + super::super::append(x, y) + } - let len = if offset + (len as usize) > chars.len() { - chars.len() - offset - } else { - len as usize - }; - - Ok(chars - .iter() - .skip(offset) - .take(len) - .cloned() - .collect::() - .into()) -} -fn crop_string(s: &mut ImmutableString, start: INT, len: INT) -> FuncReturn<()> { - let offset = if s.is_empty() || len <= 0 { - s.make_mut().clear(); - return Ok(()); - } else if start < 0 { - 0 - } else if (start as usize) >= s.chars().count() { - s.make_mut().clear(); - return Ok(()); - } else { - start as usize - }; - - let chars: StaticVec<_> = s.chars().collect(); - - let len = if offset + (len as usize) > chars.len() { - chars.len() - offset - } else { - len as usize - }; - - let copy = s.make_mut(); - copy.clear(); - copy.extend(chars.iter().skip(offset).take(len)); - - Ok(()) + #[export_fn] + pub fn prepend_func(x: $arg_type, y: ImmutableString) -> String { + super::super::prepend(x, y) + } + } + )* } + } } -macro_rules! reg_op { - ($lib:expr, $op:expr, $func:ident, $($par:ty),*) => { - $( $lib.set_fn_2($op, $func::<$par>); )* - }; +macro_rules! reg_functions { + ($mod_name:ident += $root:ident ; $($arg_type:ident),+) => { + $(set_exported_fn!($mod_name, "+", $root::$arg_type::append_func);)* + $(set_exported_fn!($mod_name, "+", $root::$arg_type::prepend_func);)* + } } def_package!(crate:MoreStringPackage:"Additional string utilities, including string building.", lib, { - reg_op!(lib, "+", append, INT, bool, char, FnPtr); - lib.set_fn_2( "+", |x: ImmutableString, _: ()| Ok(x)); + reg_functions!(lib += basic; INT, bool, char, FnPtr); + set_exported_fn!(lib, "+", string_funcs::append_unit); + set_exported_fn!(lib, "+", string_funcs::prepend_unit); - reg_op!(lib, "+", prepend, INT, bool, char, FnPtr); - lib.set_fn_2("+", |_: (), y: ImmutableString| Ok(y)); + #[cfg(not(feature = "only_i32"))] + #[cfg(not(feature = "only_i64"))] + { + reg_functions!(lib += numbers; i8, u8, i16, u16, i32, i64, u32, u64); - if cfg!(not(feature = "only_i32")) && cfg!(not(feature = "only_i64")) { - reg_op!(lib, "+", append, i8, u8, i16, u16, i32, i64, u32, u64); - reg_op!(lib, "+", prepend, i8, u8, i16, u16, i32, i64, u32, u64); - - if cfg!(not(target_arch = "wasm32")) { - reg_op!(lib, "+", append, i128, u128); - reg_op!(lib, "+", prepend, i128, u128); - } + #[cfg(not(target_arch = "wasm32"))] + reg_functions!(lib += num_128; i128, u128); } #[cfg(not(feature = "no_float"))] - { - reg_op!(lib, "+", append, f32, f64); - reg_op!(lib, "+", prepend, f32, f64); - } + reg_functions!(lib += float; f32, f64); #[cfg(not(feature = "no_index"))] { - lib.set_fn_2_mut("+", |x: &mut ImmutableString, y: Array| Ok(format!("{}{:?}", x, y))); - lib.set_fn_2_mut("+", |x: &mut Array, y: ImmutableString| Ok(format!("{:?}{}", x, y))); + set_exported_fn!(lib, "+", string_funcs::append_array); + set_exported_fn!(lib, "+", string_funcs::prepend_array); } - lib.set_fn_1_mut("len", |s: &mut ImmutableString| Ok(s.chars().count() as INT)); + lib.combine(exported_module!(string_functions)); + set_exported_fn!(lib, "contains", string_funcs::contains_char); + set_exported_fn!(lib, "contains", string_funcs::contains_string); + set_exported_fn!(lib, "index_of", string_funcs::index_of_char); + set_exported_fn!(lib, "index_of", string_funcs::index_of_char_starting_from); + set_exported_fn!(lib, "index_of", string_funcs::index_of_string); + set_exported_fn!(lib, "index_of", string_funcs::index_of_string_starting_from); + set_exported_fn!(lib, "append", string_funcs::append_char); + set_exported_fn!(lib, "append", string_funcs::append_string); + set_exported_fn!(lib, "sub_string", string_funcs::sub_string); + set_exported_fn!(lib, "sub_string", string_funcs::sub_string_starting_from); + set_exported_fn!(lib, "crop", string_funcs::crop_string); + set_exported_fn!(lib, "crop", string_funcs::crop_string_starting_from); + set_exported_fn!(lib, "replace", string_funcs::replace_string); + set_exported_fn!(lib, "replace", string_funcs::replace_char); + set_exported_fn!(lib, "replace", string_funcs::replace_string_with_char); + set_exported_fn!(lib, "replace", string_funcs::replace_char_with_string); - #[cfg(not(feature = "no_object"))] - lib.set_getter_fn("len", |s: &mut ImmutableString| Ok(s.chars().count() as INT)); - - lib.set_fn_2_mut( - "contains", - |s: &mut ImmutableString, ch: char| Ok(s.contains(ch)), - ); - lib.set_fn_2_mut( - "contains", - |s: &mut ImmutableString, find: ImmutableString| Ok(s.contains(find.as_str())), - ); - lib.set_fn_3_mut( - "index_of", - |s: &mut ImmutableString, ch: char, start: INT| { - let start = if start < 0 { - 0 - } else if (start as usize) >= s.chars().count() { - return Ok(-1 as INT); - } else { - s.chars().take(start as usize).collect::().len() - }; - - Ok(s[start..] - .find(ch) - .map(|index| s[0..start + index].chars().count() as INT) - .unwrap_or(-1 as INT)) - }, - ); - lib.set_fn_2_mut( - "index_of", - |s: &mut ImmutableString, ch: char| { - Ok(s.find(ch) - .map(|index| s[0..index].chars().count() as INT) - .unwrap_or(-1 as INT)) - }, - ); - lib.set_fn_3_mut( - "index_of", - |s: &mut ImmutableString, find: ImmutableString, start: INT| { - let start = if start < 0 { - 0 - } else if (start as usize) >= s.chars().count() { - return Ok(-1 as INT); - } else { - s.chars().take(start as usize).collect::().len() - }; - - Ok(s[start..] - .find(find.as_str()) - .map(|index| s[0..start + index].chars().count() as INT) - .unwrap_or(-1 as INT)) - }, - ); - lib.set_fn_2_mut( - "index_of", - |s: &mut ImmutableString, find: ImmutableString| { - Ok(s.find(find.as_str()) - .map(|index| s[0..index].chars().count() as INT) - .unwrap_or(-1 as INT)) - }, - ); - lib.set_fn_1_mut("clear", |s: &mut ImmutableString| { - s.make_mut().clear(); - Ok(()) - }); - lib.set_fn_2_mut("append", |s: &mut ImmutableString, ch: char| { - s.make_mut().push(ch); - Ok(()) - }); - lib.set_fn_2_mut( - "append", - |s: &mut ImmutableString, add: ImmutableString| { - s.make_mut().push_str(add.as_str()); - Ok(()) - } - ); - lib.set_fn_3("sub_string", sub_string); - lib.set_fn_2( - "sub_string", - |s: ImmutableString, start: INT| { - let len = s.len() as INT; - sub_string(s, start, len) - }, - ); - lib.set_fn_3_mut("crop", crop_string); - lib.set_fn_2_mut( - "crop", - |s: &mut ImmutableString, start: INT| crop_string(s, start, s.len() as INT), - ); - lib.set_fn_2_mut( - "truncate", - |s: &mut ImmutableString, len: INT| { - if len > 0 { - let chars: StaticVec<_> = s.chars().collect(); - let copy = s.make_mut(); - copy.clear(); - copy.extend(chars.into_iter().take(len as usize)); - } else { - s.make_mut().clear(); - } - Ok(()) - }, - ); lib.set_raw_fn( "pad", &[TypeId::of::(), TypeId::of::(), TypeId::of::()], |_engine: &Engine, _: &Module, args: &mut [&mut Dynamic]| { - let len = *args[1].read_lock::< INT>().unwrap(); + let len = *args[1].read_lock::().unwrap(); // Check if string will be over max size limit #[cfg(not(feature = "unchecked"))] @@ -267,45 +131,9 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str Ok(()) }, ); - lib.set_fn_3_mut( - "replace", - |s: &mut ImmutableString, find: ImmutableString, sub: ImmutableString| { - *s = s.replace(find.as_str(), sub.as_str()).into(); - Ok(()) - }, - ); - lib.set_fn_3_mut( - "replace", - |s: &mut ImmutableString, find: ImmutableString, sub: char| { - *s = s.replace(find.as_str(), &sub.to_string()).into(); - Ok(()) - }, - ); - lib.set_fn_3_mut( - "replace", - |s: &mut ImmutableString, find: char, sub: ImmutableString| { - *s = s.replace(&find.to_string(), sub.as_str()).into(); - Ok(()) - }, - ); - lib.set_fn_3_mut( - "replace", - |s: &mut ImmutableString, find: char, sub: char| { - *s = s.replace(&find.to_string(), &sub.to_string()).into(); - Ok(()) - }, - ); - lib.set_fn_1_mut( - "trim", - |s: &mut ImmutableString| { - let trimmed = s.trim(); - if trimmed.len() < s.len() { - *s = trimmed.to_string().into(); - } - Ok(()) - }, - ); + #[cfg(not(feature = "no_object"))] + set_exported_fn!(lib, make_getter("len"), string_funcs::len); // Register string iterator lib.set_iter( @@ -315,3 +143,220 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str ) as Box>, ); }); + +fn prepend(x: T, y: ImmutableString) -> String { + format!("{}{}", x, y) +} +fn append(x: ImmutableString, y: T) -> String { + format!("{}{}", x, y) +} + +gen_concat_functions!(basic => INT, bool, char, FnPtr); + +#[cfg(not(feature = "only_i32"))] +#[cfg(not(feature = "only_i64"))] +gen_concat_functions!(numbers => i8, u8, i16, u16, i32, i64, u32, u64); + +#[cfg(not(feature = "only_i32"))] +#[cfg(not(feature = "only_i64"))] +#[cfg(not(target_arch = "wasm32"))] +gen_concat_functions!(num_128 => i128, u128); + +#[cfg(not(feature = "no_float"))] +gen_concat_functions!(float => f32, f64); + +#[export_module] +mod string_functions { + pub fn len(s: &mut ImmutableString) -> INT { + string_funcs::len(s) + } + pub fn clear(s: &mut ImmutableString) { + s.make_mut().clear(); + } + pub fn truncate(s: &mut ImmutableString, len: INT) { + if len > 0 { + let chars: StaticVec<_> = s.chars().collect(); + let copy = s.make_mut(); + copy.clear(); + copy.extend(chars.into_iter().take(len as usize)); + } else { + s.make_mut().clear(); + } + } + pub fn trim(s: &mut ImmutableString) { + let trimmed = s.trim(); + + if trimmed.len() < s.len() { + *s = trimmed.to_string().into(); + } + } +} + +mod string_funcs { + use crate::engine::Array; + use crate::parser::INT; + use crate::plugin::*; + use crate::utils::{ImmutableString, StaticVec}; + + #[export_fn] + pub fn append_unit(s: ImmutableString, _x: ()) -> ImmutableString { + s + } + #[export_fn] + pub fn prepend_unit(_x: (), s: ImmutableString) -> ImmutableString { + s + } + #[export_fn] + pub fn append_array(x: &mut ImmutableString, y: Array) -> String { + format!("{}{:?}", x, y) + } + #[export_fn] + pub fn prepend_array(x: &mut Array, y: ImmutableString) -> String { + format!("{:?}{}", x, y) + } + #[export_fn] + pub fn len(s: &mut ImmutableString) -> INT { + s.chars().count() as INT + } + #[export_fn] + pub fn contains_char(s: &mut ImmutableString, ch: char) -> bool { + s.contains(ch) + } + #[export_fn] + pub fn contains_string(s: &mut ImmutableString, find: ImmutableString) -> bool { + s.contains(find.as_str()) + } + #[export_fn] + pub fn index_of_char_starting_from(s: &mut ImmutableString, ch: char, start: INT) -> INT { + let start = if start < 0 { + 0 + } else if (start as usize) >= s.chars().count() { + return -1 as INT; + } else { + s.chars().take(start as usize).collect::().len() + }; + + s[start..] + .find(ch) + .map(|index| s[0..start + index].chars().count() as INT) + .unwrap_or(-1 as INT) + } + #[export_fn] + pub fn index_of_char(s: &mut ImmutableString, ch: char) -> INT { + s.find(ch) + .map(|index| s[0..index].chars().count() as INT) + .unwrap_or(-1 as INT) + } + #[export_fn] + pub fn index_of_string_starting_from( + s: &mut ImmutableString, + find: ImmutableString, + start: INT, + ) -> INT { + let start = if start < 0 { + 0 + } else if (start as usize) >= s.chars().count() { + return -1 as INT; + } else { + s.chars().take(start as usize).collect::().len() + }; + + s[start..] + .find(find.as_str()) + .map(|index| s[0..start + index].chars().count() as INT) + .unwrap_or(-1 as INT) + } + #[export_fn] + pub fn index_of_string(s: &mut ImmutableString, find: ImmutableString) -> INT { + s.find(find.as_str()) + .map(|index| s[0..index].chars().count() as INT) + .unwrap_or(-1 as INT) + } + #[export_fn] + pub fn append_char(s: &mut ImmutableString, ch: char) { + s.make_mut().push(ch); + } + #[export_fn] + pub fn append_string(s: &mut ImmutableString, add: ImmutableString) { + s.make_mut().push_str(add.as_str()); + } + #[export_fn] + pub fn sub_string(s: ImmutableString, start: INT, len: INT) -> ImmutableString { + let offset = if s.is_empty() || len <= 0 { + return "".to_string().into(); + } else if start < 0 { + 0 + } else if (start as usize) >= s.chars().count() { + return "".to_string().into(); + } else { + start as usize + }; + + let chars: StaticVec<_> = s.chars().collect(); + + let len = if offset + (len as usize) > chars.len() { + chars.len() - offset + } else { + len as usize + }; + + chars + .iter() + .skip(offset) + .take(len) + .cloned() + .collect::() + .into() + } + #[export_fn] + pub fn sub_string_starting_from(s: ImmutableString, start: INT) -> ImmutableString { + let len = s.len() as INT; + sub_string(s, start, len) + } + #[export_fn] + fn crop_string(s: &mut ImmutableString, start: INT, len: INT) { + let offset = if s.is_empty() || len <= 0 { + s.make_mut().clear(); + return; + } else if start < 0 { + 0 + } else if (start as usize) >= s.chars().count() { + s.make_mut().clear(); + return; + } else { + start as usize + }; + + let chars: StaticVec<_> = s.chars().collect(); + + let len = if offset + (len as usize) > chars.len() { + chars.len() - offset + } else { + len as usize + }; + + let copy = s.make_mut(); + copy.clear(); + copy.extend(chars.iter().skip(offset).take(len)); + } + #[export_fn] + pub fn crop_string_starting_from(s: &mut ImmutableString, start: INT) { + crop_string(s, start, s.len() as INT); + } + #[export_fn] + pub fn replace_string(s: &mut ImmutableString, find: ImmutableString, sub: ImmutableString) { + *s = s.replace(find.as_str(), sub.as_str()).into(); + } + #[export_fn] + pub fn replace_string_with_char(s: &mut ImmutableString, find: ImmutableString, sub: char) { + *s = s.replace(find.as_str(), &sub.to_string()).into(); + } + #[export_fn] + pub fn replace_char_with_string(s: &mut ImmutableString, find: char, sub: ImmutableString) { + *s = s.replace(&find.to_string(), sub.as_str()).into(); + } + #[export_fn] + pub fn replace_char(s: &mut ImmutableString, find: char, sub: char) { + *s = s.replace(&find.to_string(), &sub.to_string()).into(); + } +} diff --git a/src/packages/time_basic.rs b/src/packages/time_basic.rs index 8a216b2d..ce0f9abf 100644 --- a/src/packages/time_basic.rs +++ b/src/packages/time_basic.rs @@ -35,7 +35,7 @@ def_package!(crate:BasicTimePackage:"Basic timing utilities.", lib, { set_exported_fn!(lib, "-", time_diff); - //lib.merge(&exported_module!(time_compare)); + //lib.combine(exported_module!(time_compare)); lib.set_fn_2("<", |x:Instant, y:Instant| Ok(x < y)); lib.set_fn_2("<=", |x:Instant, y:Instant| Ok(x <= y)); diff --git a/tests/macro_register.rs b/tests/macro_register.rs index 99e7fe22..525704c2 100644 --- a/tests/macro_register.rs +++ b/tests/macro_register.rs @@ -1,7 +1,6 @@ use rhai::plugin::*; use rhai::{Engine, EvalAltResult, INT}; - #[export_fn] pub fn add_together(x: INT, y: INT) -> INT { x + y diff --git a/tests/macro_unroll.rs b/tests/macro_unroll.rs index e994fa0e..c872381a 100644 --- a/tests/macro_unroll.rs +++ b/tests/macro_unroll.rs @@ -1,7 +1,7 @@ #![cfg(not(any(feature = "no_index", feature = "no_module")))] use rhai::plugin::*; -use rhai::{Engine, EvalAltResult, INT, Module}; +use rhai::{Engine, EvalAltResult, Module, INT}; pub fn add_generic>(x: T, y: T) -> T { x + y