From f70cea508cd30fa40770ea989fe2a19e715a357b Mon Sep 17 00:00:00 2001 From: Laurenz Date: Fri, 30 Dec 2022 15:13:28 +0100 Subject: Remove index syntax in favor of accessor methods --- src/model/str.rs | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) (limited to 'src/model/str.rs') diff --git a/src/model/str.rs b/src/model/str.rs index d1bf9d23..9196a35a 100644 --- a/src/model/str.rs +++ b/src/model/str.rs @@ -42,16 +42,40 @@ impl Str { self } - /// The codepoints the string consists of. - pub fn codepoints(&self) -> Array { - self.as_str().chars().map(|c| Value::Str(c.into())).collect() - } - /// The grapheme clusters the string consists of. pub fn graphemes(&self) -> Array { self.as_str().graphemes(true).map(|s| Value::Str(s.into())).collect() } + /// Extract the first grapheme cluster. + pub fn first(&self) -> StrResult { + self.0 + .graphemes(true) + .next() + .map(Into::into) + .ok_or_else(string_is_empty) + } + + /// Extract the last grapheme cluster. + pub fn last(&self) -> StrResult { + self.0 + .graphemes(true) + .next_back() + .map(Into::into) + .ok_or_else(string_is_empty) + } + + /// Extract the grapheme cluster at the given index. + pub fn at(&self, index: i64) -> StrResult { + let len = self.len(); + let grapheme = self + .locate(index) + .filter(|&index| index <= self.0.len()) + .and_then(|index| self.0[index..].graphemes(true).next()) + .ok_or_else(|| out_of_bounds(index, len))?; + Ok(grapheme.into()) + } + /// Extract a contigous substring. pub fn slice(&self, start: i64, end: Option) -> StrResult { let len = self.len(); @@ -270,6 +294,12 @@ fn out_of_bounds(index: i64, len: i64) -> String { format!("string index out of bounds (index: {}, len: {})", index, len) } +/// The error message when the string is empty. +#[cold] +fn string_is_empty() -> EcoString { + "string is empty".into() +} + /// Convert an item of std's `match_indices` to a dictionary. fn match_to_dict((start, text): (usize, &str)) -> Dict { dict! { -- cgit v1.2.3