Use chars() to iterate strings.
This commit is contained in:
parent
859a18c6fd
commit
989cb702c0
@ -9,10 +9,16 @@ Bug fixes
|
||||
|
||||
* Fixed incorrect optimization regarding chain-indexing with non-numeric index.
|
||||
|
||||
Breaking changes
|
||||
----------------
|
||||
|
||||
* To keep the API consistent, strings are no longer iterable by default. Use the `chars` method to iterator the characters in a string.
|
||||
|
||||
New features
|
||||
------------
|
||||
|
||||
* An integer value can now be indexed to get/set a single bit.
|
||||
* The `bits` method of an integer can be used to iterate through its bits.
|
||||
|
||||
|
||||
Version 0.20.2
|
||||
|
@ -10,7 +10,7 @@ use num_traits::{CheckedAdd as Add, CheckedSub as Sub};
|
||||
#[cfg(feature = "unchecked")]
|
||||
use std::ops::{Add, Sub};
|
||||
|
||||
// Register range function with step
|
||||
// Range iterator with step
|
||||
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||
struct StepRange<T>(T, T, T)
|
||||
where
|
||||
@ -126,7 +126,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
// Register range function with step
|
||||
// Bit-field iterator with step
|
||||
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||
struct BitRange(INT, INT, usize);
|
||||
|
||||
@ -191,6 +191,64 @@ impl Iterator for BitRange {
|
||||
}
|
||||
}
|
||||
|
||||
// String iterator over characters
|
||||
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||
struct CharsStream(Vec<char>, usize);
|
||||
|
||||
impl CharsStream {
|
||||
pub fn new(string: &str, from: INT, len: INT) -> Self {
|
||||
if len <= 0 {
|
||||
return Self(Default::default(), 0);
|
||||
}
|
||||
if from >= 0 {
|
||||
return Self(
|
||||
string
|
||||
.chars()
|
||||
.skip(from as usize)
|
||||
.take(len as usize)
|
||||
.collect(),
|
||||
0,
|
||||
);
|
||||
}
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
return if let Some(abs_from) = from.checked_abs() {
|
||||
let num_chars = string.chars().count();
|
||||
let offset = if num_chars < (abs_from as usize) {
|
||||
0
|
||||
} else {
|
||||
num_chars - (abs_from as usize)
|
||||
};
|
||||
Self(string.chars().skip(offset).take(len as usize).collect(), 0)
|
||||
} else {
|
||||
Self(string.chars().skip(0).take(len as usize).collect(), 0)
|
||||
};
|
||||
|
||||
#[cfg(feature = "unchecked")]
|
||||
return Self(
|
||||
string
|
||||
.chars()
|
||||
.skip(from as usize)
|
||||
.take(len as usize)
|
||||
.collect,
|
||||
0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for CharsStream {
|
||||
type Item = char;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.1 >= self.0.len() {
|
||||
None
|
||||
} else {
|
||||
let ch = self.0[self.1];
|
||||
self.1 += 1;
|
||||
Some(ch)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! reg_range {
|
||||
($lib:ident | $x:expr => $( $y:ty ),*) => {
|
||||
$(
|
||||
@ -370,15 +428,31 @@ def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, {
|
||||
lib.update_fn_metadata(_hash, &["from: Decimal", "to: Decimal", "step: Decimal", "Iterator<Item=Decimal>"]);
|
||||
}
|
||||
|
||||
// Register string iterator
|
||||
lib.set_iterator::<CharsStream>();
|
||||
|
||||
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>"]);
|
||||
|
||||
let _hash = lib.set_native_fn("chars", |string, from| Ok(CharsStream::new(string, from, INT::MAX)));
|
||||
#[cfg(feature = "metadata")]
|
||||
lib.update_fn_metadata(_hash, &["string: &str", "from: INT", "Iterator<Item=char>"]);
|
||||
|
||||
let _hash = lib.set_native_fn("chars", |string| Ok(CharsStream::new(string, 0, INT::MAX)));
|
||||
#[cfg(feature = "metadata")]
|
||||
lib.update_fn_metadata(_hash, &["string: &str", "Iterator<Item=char>"]);
|
||||
|
||||
// Register bit-field iterator
|
||||
lib.set_iterator::<BitRange>();
|
||||
|
||||
let _hash = lib.set_native_fn("bits", |value, from, len| BitRange::new(value, from, len));
|
||||
#[cfg(feature = "metadata")]
|
||||
lib.update_fn_metadata(_hash, &["value: INT", "from: Decimal", "len: Decimal", "Iterator<Item=bool>"]);
|
||||
lib.update_fn_metadata(_hash, &["value: INT", "from: INT", "len: INT", "Iterator<Item=bool>"]);
|
||||
|
||||
let _hash = lib.set_native_fn("bits", |value, from| BitRange::new(value, from, INT::MAX));
|
||||
#[cfg(feature = "metadata")]
|
||||
lib.update_fn_metadata(_hash, &["value: INT", "from: Decimal", "Iterator<Item=bool>"]);
|
||||
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));
|
||||
#[cfg(feature = "metadata")]
|
||||
|
@ -1,7 +1,7 @@
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use crate::plugin::*;
|
||||
use crate::{def_package, Dynamic, ImmutableString, StaticVec, INT};
|
||||
use crate::{def_package, Dynamic, StaticVec, INT};
|
||||
#[cfg(feature = "no_std")]
|
||||
use std::prelude::v1::*;
|
||||
use std::{any::TypeId, mem};
|
||||
@ -10,12 +10,6 @@ use super::string_basic::{print_with_func, FUNC_TO_STRING};
|
||||
|
||||
def_package!(crate:MoreStringPackage:"Additional string utilities, including string building.", lib, {
|
||||
combine_with_exported_module!(lib, "string", string_functions);
|
||||
|
||||
// Register string iterator
|
||||
lib.set_iter(
|
||||
TypeId::of::<ImmutableString>(),
|
||||
|string| Box::new(string.cast::<ImmutableString>().chars().collect::<Vec<_>>().into_iter().map(Into::into))
|
||||
);
|
||||
});
|
||||
|
||||
#[export_module]
|
||||
|
@ -113,7 +113,7 @@ impl EvalAltResult {
|
||||
Self::ErrorStringBounds(0, _, _) => "Empty string has nothing to index",
|
||||
Self::ErrorStringBounds(_, _, _) => "String index out of bounds",
|
||||
Self::ErrorBitFieldBounds(_, _, _) => "Bit-field index out of bounds",
|
||||
Self::ErrorFor(_) => "For loop expects an array, object map, or range",
|
||||
Self::ErrorFor(_) => "For loop expects a type with an iterator defined",
|
||||
Self::ErrorVariableNotFound(_, _) => "Variable not found",
|
||||
Self::ErrorModuleNotFound(_, _) => "Module not found",
|
||||
Self::ErrorDataRace(_, _) => "Data race detected when accessing variable",
|
||||
|
@ -235,7 +235,7 @@ fn test_for_string() -> Result<(), Box<EvalAltResult>> {
|
||||
let s = "hello";
|
||||
let sum = 0;
|
||||
|
||||
for ch in s {
|
||||
for ch in s.chars() {
|
||||
sum += to_int(ch);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user