Add ranges.

This commit is contained in:
Stephen Chung
2021-12-15 12:06:17 +08:00
parent 7251f34bce
commit ef14079c61
35 changed files with 1206 additions and 269 deletions

View File

@@ -121,12 +121,15 @@ macro_rules! gen_arithmetic_functions {
pub fn binary_xor(x: $arg_type, y: $arg_type) -> $arg_type {
x ^ y
}
#[rhai_fn(get = "is_zero", name = "is_zero")]
pub fn is_zero(x: $arg_type) -> bool {
x == 0
}
#[rhai_fn(get = "is_odd", name = "is_odd")]
pub fn is_odd(x: $arg_type) -> bool {
x % 2 != 0
}
#[rhai_fn(get = "is_even", name = "is_even")]
pub fn is_even(x: $arg_type) -> bool {
x % 2 == 0
}
@@ -209,12 +212,15 @@ def_package!(crate:ArithmeticPackage:"Basic arithmetic", lib, {
#[export_module]
mod int_functions {
#[rhai_fn(get = "is_zero", name = "is_zero")]
pub fn is_zero(x: INT) -> bool {
x == 0
}
#[rhai_fn(get = "is_odd", name = "is_odd")]
pub fn is_odd(x: INT) -> bool {
x % 2 != 0
}
#[rhai_fn(get = "is_even", name = "is_even")]
pub fn is_even(x: INT) -> bool {
x % 2 == 0
}
@@ -335,6 +341,7 @@ mod f32_functions {
x => Ok(x as INT),
}
}
#[rhai_fn(get = "is_zero", name = "is_zero")]
pub fn is_zero(x: f32) -> bool {
x == 0.0
}
@@ -442,6 +449,7 @@ mod f64_functions {
x => Ok(x as INT),
}
}
#[rhai_fn(get = "is_zero", name = "is_zero")]
pub fn is_zero(x: f64) -> bool {
x == 0.0
}
@@ -536,6 +544,7 @@ pub mod decimal_functions {
1
}
}
#[rhai_fn(get = "is_zero", name = "is_zero")]
pub fn is_zero(x: Decimal) -> bool {
x.is_zero()
}

View File

@@ -3,7 +3,10 @@
use crate::engine::OP_EQUALS;
use crate::plugin::*;
use crate::{def_package, Array, Dynamic, EvalAltResult, FnPtr, NativeCallContext, Position, INT};
use crate::{
def_package, Array, Dynamic, EvalAltResult, ExclusiveRange, FnPtr, InclusiveRange,
NativeCallContext, Position, INT,
};
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
use std::{any::TypeId, cmp::Ordering, mem};
@@ -145,6 +148,18 @@ mod array_functions {
array.reverse();
}
}
#[rhai_fn(name = "splice")]
pub fn splice_range(array: &mut Array, range: ExclusiveRange, replace: Array) {
let start = INT::max(range.start, 0);
let end = INT::max(range.end, start);
splice(array, start, end - start, replace)
}
#[rhai_fn(name = "splice")]
pub fn splice_inclusive_range(array: &mut Array, range: InclusiveRange, replace: Array) {
let start = INT::max(*range.start(), 0);
let end = INT::max(*range.end(), start);
splice(array, start, end - start + 1, replace)
}
pub fn splice(array: &mut Array, start: INT, len: INT, replace: Array) {
if array.is_empty() {
*array = replace;
@@ -173,6 +188,18 @@ mod array_functions {
array.splice(start..start + len, replace.into_iter());
}
#[rhai_fn(name = "extract")]
pub fn extract_range(array: &mut Array, range: ExclusiveRange) -> Array {
let start = INT::max(range.start, 0);
let end = INT::max(range.end, start);
extract(array, start, end - start)
}
#[rhai_fn(name = "extract")]
pub fn extract_inclusive_range(array: &mut Array, range: InclusiveRange) -> Array {
let start = INT::max(*range.start(), 0);
let end = INT::max(*range.end(), start);
extract(array, start, end - start + 1)
}
pub fn extract(array: &mut Array, start: INT, len: INT) -> Array {
if array.is_empty() || len <= 0 {
return Array::new();
@@ -911,6 +938,18 @@ mod array_functions {
drain(ctx, array, FnPtr::new(filter)?)
}
#[rhai_fn(name = "drain")]
pub fn drain_exclusive_range(array: &mut Array, range: ExclusiveRange) -> Array {
let start = INT::max(range.start, 0);
let end = INT::max(range.end, start);
drain_range(array, start, end - start)
}
#[rhai_fn(name = "drain")]
pub fn drain_inclusive_range(array: &mut Array, range: InclusiveRange) -> Array {
let start = INT::max(*range.start(), 0);
let end = INT::max(*range.end(), start);
drain_range(array, start, end - start + 1)
}
#[rhai_fn(name = "drain")]
pub fn drain_range(array: &mut Array, start: INT, len: INT) -> Array {
if array.is_empty() || len <= 0 {
return Array::new();
@@ -993,6 +1032,18 @@ mod array_functions {
retain(ctx, array, FnPtr::new(filter)?)
}
#[rhai_fn(name = "retain")]
pub fn retain_exclusive_range(array: &mut Array, range: ExclusiveRange) -> Array {
let start = INT::max(range.start, 0);
let end = INT::max(range.end, start);
retain_range(array, start, end - start)
}
#[rhai_fn(name = "retain")]
pub fn retain_inclusive_range(array: &mut Array, range: InclusiveRange) -> Array {
let start = INT::max(*range.start(), 0);
let end = INT::max(*range.end(), start);
retain_range(array, start, end - start + 1)
}
#[rhai_fn(name = "retain")]
pub fn retain_range(array: &mut Array, start: INT, len: INT) -> Array {
if array.is_empty() || len <= 0 {
return Array::new();

View File

@@ -2,7 +2,10 @@
#![allow(non_snake_case)]
use crate::plugin::*;
use crate::{def_package, Blob, Dynamic, EvalAltResult, NativeCallContext, Position, INT};
use crate::{
def_package, Blob, Dynamic, EvalAltResult, ExclusiveRange, InclusiveRange, NativeCallContext,
Position, INT,
};
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
use std::{any::TypeId, mem};
@@ -184,6 +187,18 @@ mod blob_functions {
blob.reverse();
}
}
#[rhai_fn(name = "splice")]
pub fn splice_range(blob: &mut Blob, range: ExclusiveRange, replace: Blob) {
let start = INT::max(range.start, 0);
let end = INT::max(range.end, start);
splice(blob, start, end - start, replace)
}
#[rhai_fn(name = "splice")]
pub fn splice_range_inclusive(blob: &mut Blob, range: InclusiveRange, replace: Blob) {
let start = INT::max(*range.start(), 0);
let end = INT::max(*range.end(), start);
splice(blob, start, end - start + 1, replace)
}
pub fn splice(blob: &mut Blob, start: INT, len: INT, replace: Blob) {
if blob.is_empty() {
*blob = replace;
@@ -212,6 +227,18 @@ mod blob_functions {
blob.splice(start..start + len, replace.into_iter());
}
#[rhai_fn(name = "extract")]
pub fn extract_range(blob: &mut Blob, range: ExclusiveRange) -> Blob {
let start = INT::max(range.start, 0);
let end = INT::max(range.end, start);
extract(blob, start, end - start)
}
#[rhai_fn(name = "extract")]
pub fn extract_range_inclusive(blob: &mut Blob, range: InclusiveRange) -> Blob {
let start = INT::max(*range.start(), 0);
let end = INT::max(*range.end(), start);
extract(blob, start, end - start + 1)
}
pub fn extract(blob: &mut Blob, start: INT, len: INT) -> Blob {
if blob.is_empty() || len <= 0 {
return Blob::new();
@@ -264,6 +291,18 @@ mod blob_functions {
result
}
}
#[rhai_fn(name = "drain")]
pub fn drain_range(blob: &mut Blob, range: ExclusiveRange) -> Blob {
let start = INT::max(range.start, 0);
let end = INT::max(range.end, start);
drain(blob, start, end - start)
}
#[rhai_fn(name = "drain")]
pub fn drain_range_inclusive(blob: &mut Blob, range: InclusiveRange) -> Blob {
let start = INT::max(*range.start(), 0);
let end = INT::max(*range.end(), start);
drain(blob, start, end - start + 1)
}
pub fn drain(blob: &mut Blob, start: INT, len: INT) -> Blob {
if blob.is_empty() || len <= 0 {
return Blob::new();
@@ -288,6 +327,18 @@ mod blob_functions {
blob.drain(start..start + len).collect()
}
#[rhai_fn(name = "retain")]
pub fn retain_range(blob: &mut Blob, range: ExclusiveRange) -> Blob {
let start = INT::max(range.start, 0);
let end = INT::max(range.end, start);
retain(blob, start, end - start)
}
#[rhai_fn(name = "retain")]
pub fn retain_range_inclusive(blob: &mut Blob, range: InclusiveRange) -> Blob {
let start = INT::max(*range.start(), 0);
let end = INT::max(*range.end(), start);
retain(blob, start, end - start + 1)
}
pub fn retain(blob: &mut Blob, start: INT, len: INT) -> Blob {
if blob.is_empty() || len <= 0 {
return Blob::new();
@@ -374,9 +425,33 @@ mod blob_functions {
}
}
#[rhai_fn(name = "parse_le_int")]
pub fn parse_le_int_range(blob: &mut Blob, range: ExclusiveRange) -> INT {
let start = INT::max(range.start, 0);
let end = INT::max(range.end, start);
parse_le_int(blob, start, end - start)
}
#[rhai_fn(name = "parse_le_int")]
pub fn parse_le_int_range_inclusive(blob: &mut Blob, range: InclusiveRange) -> INT {
let start = INT::max(*range.start(), 0);
let end = INT::max(*range.end(), start);
parse_le_int(blob, start, end - start + 1)
}
pub fn parse_le_int(blob: &mut Blob, start: INT, len: INT) -> INT {
parse_int(blob, start, len, true)
}
#[rhai_fn(name = "parse_be_int")]
pub fn parse_be_int_range(blob: &mut Blob, range: ExclusiveRange) -> INT {
let start = INT::max(range.start, 0);
let end = INT::max(range.end, start);
parse_be_int(blob, start, end - start)
}
#[rhai_fn(name = "parse_be_int")]
pub fn parse_be_int_range_inclusive(blob: &mut Blob, range: InclusiveRange) -> INT {
let start = INT::max(*range.start(), 0);
let end = INT::max(*range.end(), start);
parse_be_int(blob, start, end - start + 1)
}
pub fn parse_be_int(blob: &mut Blob, start: INT, len: INT) -> INT {
parse_int(blob, start, len, false)
}
@@ -418,11 +493,35 @@ mod blob_functions {
blob[start..][..len].copy_from_slice(&buf[..len]);
}
#[rhai_fn(name = "write_le_int")]
pub fn write_le_int_range(blob: &mut Blob, range: ExclusiveRange, value: INT) {
let start = INT::max(range.start, 0);
let end = INT::max(range.end, start);
write_le_int(blob, start, end - start, value)
}
#[rhai_fn(name = "write_le_int")]
pub fn write_le_int_range_inclusive(blob: &mut Blob, range: InclusiveRange, value: INT) {
let start = INT::max(*range.start(), 0);
let end = INT::max(*range.end(), start);
write_le_int(blob, start, end - start + 1, value)
}
#[rhai_fn(name = "write_le")]
pub fn write_le_int(blob: &mut Blob, start: INT, len: INT, value: INT) {
write_int(blob, start, len, value, true)
}
#[rhai_fn(name = "write_be")]
pub fn write_be_int_range(blob: &mut Blob, range: ExclusiveRange, value: INT) {
let start = INT::max(range.start, 0);
let end = INT::max(range.end, start);
write_be_int(blob, start, end - start, value)
}
#[rhai_fn(name = "write_be")]
pub fn write_be_int_range_inclusive(blob: &mut Blob, range: InclusiveRange, value: INT) {
let start = INT::max(*range.start(), 0);
let end = INT::max(*range.end(), start);
write_be_int(blob, start, end - start + 1, value)
}
#[rhai_fn(name = "write_be")]
pub fn write_be_int(blob: &mut Blob, start: INT, len: INT, value: INT) {
write_int(blob, start, len, value, false)
}
@@ -466,11 +565,39 @@ mod blob_functions {
}
}
#[cfg(not(feature = "no_float"))]
#[rhai_fn(name = "parse_le_float")]
pub fn parse_le_float_range(blob: &mut Blob, range: ExclusiveRange) -> FLOAT {
let start = INT::max(range.start, 0);
let end = INT::max(range.end, start);
parse_le_float(blob, start, end - start)
}
#[cfg(not(feature = "no_float"))]
#[rhai_fn(name = "parse_le_float")]
pub fn parse_le_float_range_inclusive(blob: &mut Blob, range: InclusiveRange) -> FLOAT {
let start = INT::max(*range.start(), 0);
let end = INT::max(*range.end(), start);
parse_le_float(blob, start, end - start + 1)
}
#[cfg(not(feature = "no_float"))]
pub fn parse_le_float(blob: &mut Blob, start: INT, len: INT) -> FLOAT {
parse_float(blob, start, len, true)
}
#[cfg(not(feature = "no_float"))]
#[rhai_fn(name = "parse_be_float")]
pub fn parse_be_float_range(blob: &mut Blob, range: ExclusiveRange) -> FLOAT {
let start = INT::max(range.start, 0);
let end = INT::max(range.end, start);
parse_be_float(blob, start, end - start)
}
#[cfg(not(feature = "no_float"))]
#[rhai_fn(name = "parse_be_float")]
pub fn parse_be_float_range_inclusive(blob: &mut Blob, range: InclusiveRange) -> FLOAT {
let start = INT::max(*range.start(), 0);
let end = INT::max(*range.end(), start);
parse_be_float(blob, start, end - start + 1)
}
#[cfg(not(feature = "no_float"))]
pub fn parse_be_float(blob: &mut Blob, start: INT, len: INT) -> FLOAT {
parse_float(blob, start, len, false)
}
@@ -514,12 +641,40 @@ mod blob_functions {
blob[start..][..len].copy_from_slice(&buf[..len]);
}
#[cfg(not(feature = "no_float"))]
#[rhai_fn(name = "write_le_float")]
pub fn write_le_float_range(blob: &mut Blob, range: ExclusiveRange, value: FLOAT) {
let start = INT::max(range.start, 0);
let end = INT::max(range.end, start);
write_le_float(blob, start, end - start, value)
}
#[cfg(not(feature = "no_float"))]
#[rhai_fn(name = "write_le_float")]
pub fn write_le_float_range_inclusive(blob: &mut Blob, range: InclusiveRange, value: FLOAT) {
let start = INT::max(*range.start(), 0);
let end = INT::max(*range.end(), start);
write_le_float(blob, start, end - start + 1, value)
}
#[cfg(not(feature = "no_float"))]
#[rhai_fn(name = "write_le")]
pub fn write_le_float(blob: &mut Blob, start: INT, len: INT, value: FLOAT) {
write_float(blob, start, len, value, true)
}
#[cfg(not(feature = "no_float"))]
#[rhai_fn(name = "write_be")]
pub fn write_be_float_range(blob: &mut Blob, range: ExclusiveRange, value: FLOAT) {
let start = INT::max(range.start, 0);
let end = INT::max(range.end, start);
write_be_float(blob, start, end - start, value)
}
#[cfg(not(feature = "no_float"))]
#[rhai_fn(name = "write_be")]
pub fn write_be_float_range_inclusive(blob: &mut Blob, range: InclusiveRange, value: FLOAT) {
let start = INT::max(*range.start(), 0);
let end = INT::max(*range.end(), start);
write_be_float(blob, start, end - start + 1, value)
}
#[cfg(not(feature = "no_float"))]
#[rhai_fn(name = "write_be")]
pub fn write_be_float(blob: &mut Blob, start: INT, len: INT, value: FLOAT) {
write_float(blob, start, len, value, false)
}

View File

@@ -1,7 +1,8 @@
use crate::plugin::*;
use crate::types::dynamic::Variant;
use crate::{def_package, EvalAltResult, INT};
use crate::{def_package, EvalAltResult, ExclusiveRange, InclusiveRange, INT};
use std::iter::{ExactSizeIterator, FusedIterator};
use std::ops::Range;
use std::ops::{Range, RangeInclusive};
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
@@ -271,6 +272,7 @@ macro_rules! reg_range {
($lib:ident | $x:expr => $( $y:ty ),*) => {
$(
$lib.set_iterator::<Range<$y>>();
$lib.set_iterator::<RangeInclusive<$y>>();
let _hash = $lib.set_native_fn($x, |from: $y, to: $y| Ok(from..to));
#[cfg(feature = "metadata")]
@@ -449,6 +451,22 @@ def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, {
// Register string iterator
lib.set_iterator::<CharsStream>();
let _hash = lib.set_native_fn("chars", |string, range: ExclusiveRange| {
let from = INT::max(range.start, 0);
let to = INT::max(range.end, from);
Ok(CharsStream::new(string, from, to - from))
});
#[cfg(feature = "metadata")]
lib.update_fn_metadata(_hash, &["string: &str", "range: Range", "Iterator<Item=char>"]);
let _hash = lib.set_native_fn("chars", |string, range: InclusiveRange| {
let from = INT::max(*range.start(), 0);
let to = INT::max(*range.end(), from - 1);
Ok(CharsStream::new(string, from, to-from + 1))
});
#[cfg(feature = "metadata")]
lib.update_fn_metadata(_hash, &["string: &str", "range: RangeInclusive", "Iterator<Item=char>"]);
let _hash = lib.set_native_fn("chars", |string, from, len| Ok(CharsStream::new(string, from, len)));
#[cfg(feature = "metadata")]
lib.update_fn_metadata(_hash, &["string: &str", "from: INT", "len: INT", "Iterator<Item=char>"]);
@@ -461,9 +479,29 @@ def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, {
#[cfg(feature = "metadata")]
lib.update_fn_metadata(_hash, &["string: &str", "Iterator<Item=char>"]);
let _hash = lib.set_getter_fn("chars", |string: &mut ImmutableString| Ok(CharsStream::new(string, 0, INT::MAX)));
#[cfg(feature = "metadata")]
lib.update_fn_metadata(_hash, &["string: &mut ImmutableString", "Iterator<Item=char>"]);
// Register bit-field iterator
lib.set_iterator::<BitRange>();
let _hash = lib.set_native_fn("bits", |value, range: ExclusiveRange| {
let from = INT::max(range.start, 0);
let to = INT::max(range.end, from);
BitRange::new(value, from, to - from)
});
#[cfg(feature = "metadata")]
lib.update_fn_metadata(_hash, &["value: INT", "range: Range", "Iterator<Item=bool>"]);
let _hash = lib.set_native_fn("bits", |value, range: InclusiveRange| {
let from = INT::max(*range.start(), 0);
let to = INT::max(*range.end(), from - 1);
BitRange::new(value, from, to - from + 1)
});
#[cfg(feature = "metadata")]
lib.update_fn_metadata(_hash, &["value: INT", "range: RangeInclusive", "Iterator<Item=bool>"]);
let _hash = lib.set_native_fn("bits", BitRange::new);
#[cfg(feature = "metadata")]
lib.update_fn_metadata(_hash, &["value: INT", "from: INT", "len: INT", "Iterator<Item=bool>"]);
@@ -472,7 +510,51 @@ def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, {
#[cfg(feature = "metadata")]
lib.update_fn_metadata(_hash, &["value: INT", "from: INT", "Iterator<Item=bool>"]);
let _hash = lib.set_native_fn("bits", |value| BitRange::new(value, 0, INT::MAX));
let _hash = lib.set_native_fn("bits", |value| BitRange::new(value, 0, INT::MAX) );
#[cfg(feature = "metadata")]
lib.update_fn_metadata(_hash, &["value: INT", "Iterator<Item=bool>"]);
let _hash = lib.set_getter_fn("bits", |value: &mut INT| BitRange::new(*value, 0, INT::MAX) );
#[cfg(feature = "metadata")]
lib.update_fn_metadata(_hash, &["value: &mut INT", "range: Range", "Iterator<Item=bool>"]);
combine_with_exported_module!(lib, "range", range_functions);
});
#[export_module]
mod range_functions {
#[rhai_fn(get = "start", name = "start", pure)]
pub fn range_start(range: &mut ExclusiveRange) -> INT {
range.start
}
#[rhai_fn(get = "end", name = "end", pure)]
pub fn range_end(range: &mut ExclusiveRange) -> INT {
range.end
}
#[rhai_fn(name = "contains", pure)]
pub fn range_contains(range: &mut ExclusiveRange, value: INT) -> bool {
range.contains(&value)
}
#[rhai_fn(get = "is_inclusive", name = "is_inclusive", pure)]
pub fn range_is_inclusive(range: &mut ExclusiveRange) -> bool {
let _range = range;
false
}
#[rhai_fn(get = "start", name = "start", pure)]
pub fn range_inclusive_start(range: &mut InclusiveRange) -> INT {
*range.start()
}
#[rhai_fn(get = "end", name = "end", pure)]
pub fn range_inclusive_end(range: &mut InclusiveRange) -> INT {
*range.end()
}
#[rhai_fn(name = "contains", pure)]
pub fn range_inclusive_contains(range: &mut InclusiveRange, value: INT) -> bool {
range.contains(&value)
}
#[rhai_fn(get = "is_inclusive", name = "is_inclusive", pure)]
pub fn range_inclusive_is_inclusive(range: &mut InclusiveRange) -> bool {
let _range = range;
true
}
}

View File

@@ -1,7 +1,7 @@
#![allow(non_snake_case)]
use crate::plugin::*;
use crate::{def_package, EvalAltResult, INT};
use crate::{def_package, EvalAltResult, ExclusiveRange, InclusiveRange, INT};
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
@@ -256,6 +256,21 @@ mod bit_field_functions {
Err(EvalAltResult::ErrorBitFieldBounds(BITS, index, Position::NONE).into())
}
}
#[rhai_fn(name = "get_bits", return_raw)]
pub fn get_bits_range(value: INT, range: ExclusiveRange) -> Result<INT, Box<EvalAltResult>> {
let from = INT::max(range.start, 0);
let to = INT::max(range.end, from);
get_bits(value, from, to - from)
}
#[rhai_fn(name = "get_bits", return_raw)]
pub fn get_bits_range_inclusive(
value: INT,
range: InclusiveRange,
) -> Result<INT, Box<EvalAltResult>> {
let from = INT::max(*range.start(), 0);
let to = INT::max(*range.end(), from - 1);
get_bits(value, from, to - from + 1)
}
#[rhai_fn(return_raw)]
pub fn get_bits(value: INT, index: INT, bits: INT) -> Result<INT, Box<EvalAltResult>> {
if bits < 1 {
@@ -298,6 +313,26 @@ mod bit_field_functions {
Ok(((value & (mask << index)) >> index) & mask)
}
#[rhai_fn(name = "set_bits", return_raw)]
pub fn set_bits_range(
value: &mut INT,
range: ExclusiveRange,
new_value: INT,
) -> Result<(), Box<EvalAltResult>> {
let from = INT::max(range.start, 0);
let to = INT::max(range.end, from);
set_bits(value, from, to - from, new_value)
}
#[rhai_fn(name = "set_bits", return_raw)]
pub fn set_bits_range_inclusive(
value: &mut INT,
range: InclusiveRange,
new_value: INT,
) -> Result<(), Box<EvalAltResult>> {
let from = INT::max(*range.start(), 0);
let to = INT::max(*range.end(), from - 1);
set_bits(value, from, to - from + 1, new_value)
}
#[rhai_fn(return_raw)]
pub fn set_bits(
value: &mut INT,

View File

@@ -1,7 +1,7 @@
#![allow(non_snake_case)]
use crate::plugin::*;
use crate::{def_package, Dynamic, StaticVec, INT};
use crate::{def_package, Dynamic, ExclusiveRange, InclusiveRange, StaticVec, INT};
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
use std::{any::TypeId, mem};
@@ -302,6 +302,26 @@ mod string_functions {
}
}
#[rhai_fn(name = "sub_string")]
pub fn sub_string_range(
ctx: NativeCallContext,
string: &str,
range: ExclusiveRange,
) -> ImmutableString {
let start = INT::max(range.start, 0);
let end = INT::max(range.end, start);
sub_string(ctx, string, start, end - start)
}
#[rhai_fn(name = "sub_string")]
pub fn sub_string_inclusive_range(
ctx: NativeCallContext,
string: &str,
range: InclusiveRange,
) -> ImmutableString {
let start = INT::max(*range.start(), 0);
let end = INT::max(*range.end(), start);
sub_string(ctx, string, start, end - start + 1)
}
pub fn sub_string(
ctx: NativeCallContext,
string: &str,
@@ -365,6 +385,18 @@ mod string_functions {
}
}
#[rhai_fn(name = "crop")]
pub fn crop_range(string: &mut ImmutableString, range: ExclusiveRange) {
let start = INT::max(range.start, 0);
let end = INT::max(range.end, start);
crop(string, start, end - start)
}
#[rhai_fn(name = "crop")]
pub fn crop_inclusive_range(string: &mut ImmutableString, range: InclusiveRange) {
let start = INT::max(*range.start(), 0);
let end = INT::max(*range.end(), start);
crop(string, start, end - start + 1)
}
#[rhai_fn(name = "crop")]
pub fn crop(string: &mut ImmutableString, start: INT, len: INT) {
if string.is_empty() {