diff --git a/src/core/utils/rand.rs b/src/core/utils/rand.rs index 72487633..e627fbbc 100644 --- a/src/core/utils/rand.rs +++ b/src/core/utils/rand.rs @@ -31,6 +31,34 @@ pub fn string_array() -> ArrayString { ret } +#[must_use] +pub fn truncate_string(mut str: String, range: Range) -> String { + let len = thread_rng() + .gen_range(range) + .try_into() + .unwrap_or(usize::MAX); + + if let Some((i, _)) = str.char_indices().nth(len) { + str.truncate(i); + } + + str +} + +#[inline] +#[must_use] +pub fn truncate_str(str: &str, range: Range) -> &str { + let len = thread_rng() + .gen_range(range) + .try_into() + .unwrap_or(usize::MAX); + + str.char_indices() + .nth(len) + .map(|(i, _)| str.split_at(i).0) + .unwrap_or(str) +} + #[inline] #[must_use] pub fn time_from_now_secs(range: Range) -> SystemTime { diff --git a/src/core/utils/string.rs b/src/core/utils/string.rs index 854d5d4b..d35ced66 100644 --- a/src/core/utils/string.rs +++ b/src/core/utils/string.rs @@ -5,7 +5,7 @@ mod tests; mod unquote; mod unquoted; -use std::mem::replace; +use std::{mem::replace, ops::Range}; pub use self::{between::Between, split::SplitInfallible, unquote::Unquote, unquoted::Unquoted}; use crate::{Result, smallstr::SmallString}; @@ -112,6 +112,26 @@ pub fn common_prefix>(choice: &[T]) -> &str { }) } +#[inline] +#[must_use] +#[allow(clippy::arithmetic_side_effects)] +pub fn truncate_deterministic(str: &str, range: Option>) -> &str { + let range = range.unwrap_or(0..str.len()); + let len = str + .as_bytes() + .iter() + .copied() + .map(Into::into) + .fold(0_usize, usize::wrapping_add) + .wrapping_rem(str.len().max(1)) + .clamp(range.start, range.end); + + str.char_indices() + .nth(len) + .map(|(i, _)| str.split_at(i).0) + .unwrap_or(str) +} + pub fn to_small_string(t: T) -> SmallString<[u8; CAP]> where T: std::fmt::Display,