use std::cmp::Ordering;
#[inline]
pub fn dupstring(s: &str) -> String {
s.to_string()
}
pub fn dupstring_wlen(s: &str, len: usize) -> String {
if len >= s.len() {
s.to_string()
} else {
s[..len].to_string()
}
}
pub fn tricat(s1: &str, s2: &str, s3: &str) -> String {
let mut result = String::with_capacity(s1.len() + s2.len() + s3.len());
result.push_str(s1);
result.push_str(s2);
result.push_str(s3);
result
}
pub fn bicat(s1: &str, s2: &str) -> String {
let mut result = String::with_capacity(s1.len() + s2.len());
result.push_str(s1);
result.push_str(s2);
result
}
pub fn dupstrpfx(s: &str, len: usize) -> String {
dupstring_wlen(s, len)
}
pub fn appstr(base: &str, append: &str) -> String {
bicat(base, append)
}
pub fn strend(s: &str) -> Option<char> {
s.chars().last()
}
pub mod sort_flags {
use crate::ported::zsh_h;
pub const SORTIT_BACKWARDS: u32 = zsh_h::SORTIT_BACKWARDS as u32;
pub const SORTIT_NUMERICALLY: u32 = zsh_h::SORTIT_NUMERICALLY as u32;
pub const SORTIT_NUMERICALLY_SIGNED: u32 = zsh_h::SORTIT_NUMERICALLY_SIGNED as u32;
pub const SORTIT_IGNORING_CASE: u32 = zsh_h::SORTIT_IGNORING_CASE as u32;
pub const SORTIT_IGNORING_BACKSLASHES: u32 = zsh_h::SORTIT_IGNORING_BACKSLASHES as u32;
}
pub fn zstrcmp(a: &str, b: &str, flags: u32) -> Ordering {
if flags & sort_flags::SORTIT_IGNORING_CASE != 0 {
return crate::ported::sort::zstrcmp(&a.to_lowercase(), &b.to_lowercase(), flags);
}
crate::ported::sort::zstrcmp(a, b, flags)
}
pub fn strmetasort(array: &mut [String], flags: u32) {
if array.len() < 2 {
return;
}
let backwards = flags & sort_flags::SORTIT_BACKWARDS != 0;
array.sort_by(|a, b| {
let cmp = zstrcmp(a, b, flags);
if backwards {
cmp.reverse()
} else {
cmp
}
});
}
pub fn sort_strings(array: &mut [&str], flags: u32) {
if array.len() < 2 {
return;
}
let backwards = flags & sort_flags::SORTIT_BACKWARDS != 0;
array.sort_by(|a, b| {
let cmp = zstrcmp(a, b, flags);
if backwards {
cmp.reverse()
} else {
cmp
}
});
}
pub fn natural_cmp(a: &str, b: &str) -> Ordering {
zstrcmp(a, b, sort_flags::SORTIT_NUMERICALLY)
}
pub fn strcasecmp(a: &str, b: &str) -> Ordering {
a.to_lowercase().cmp(&b.to_lowercase())
}
pub fn strstr(haystack: &str, needle: &str) -> Option<usize> {
haystack.find(needle)
}
pub fn strprefix(s: &str, prefix: &str) -> bool {
s.starts_with(prefix)
}
pub fn strsuffix(s: &str, suffix: &str) -> bool {
s.ends_with(suffix)
}
pub fn strjoin<I, S>(iter: I, sep: &str) -> String
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
iter.into_iter()
.map(|s| s.as_ref().to_string())
.collect::<Vec<_>>()
.join(sep)
}
pub fn strsplit(s: &str, sep: char) -> Vec<&str> {
s.split(sep).collect()
}
pub fn strtrim(s: &str) -> &str {
s.trim()
}
pub fn strlower(s: &str) -> String {
s.to_lowercase()
}
pub fn strupper(s: &str) -> String {
s.to_uppercase()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_dupstring() {
let _g = crate::test_util::global_state_lock();
assert_eq!(dupstring("hello"), "hello");
assert_eq!(dupstring(""), "");
}
#[test]
fn test_dupstring_wlen() {
let _g = crate::test_util::global_state_lock();
assert_eq!(dupstring_wlen("hello", 3), "hel");
assert_eq!(dupstring_wlen("hi", 10), "hi");
}
#[test]
fn test_tricat() {
let _g = crate::test_util::global_state_lock();
assert_eq!(tricat("a", "b", "c"), "abc");
assert_eq!(tricat("hello", " ", "world"), "hello world");
}
#[test]
fn test_bicat() {
let _g = crate::test_util::global_state_lock();
assert_eq!(bicat("hello", "world"), "helloworld");
}
#[test]
fn test_strend() {
let _g = crate::test_util::global_state_lock();
assert_eq!(strend("hello"), Some('o'));
assert_eq!(strend(""), None);
}
#[test]
fn test_zstrcmp_basic() {
let _g = crate::test_util::global_state_lock();
assert_eq!(zstrcmp("abc", "abc", 0), Ordering::Equal);
assert_eq!(zstrcmp("abc", "abd", 0), Ordering::Less);
assert_eq!(zstrcmp("abd", "abc", 0), Ordering::Greater);
}
#[test]
fn test_zstrcmp_case_insensitive() {
let _g = crate::test_util::global_state_lock();
let flags = sort_flags::SORTIT_IGNORING_CASE;
assert_eq!(zstrcmp("ABC", "abc", flags), Ordering::Equal);
assert_eq!(zstrcmp("ABC", "ABD", flags), Ordering::Less);
}
#[test]
fn test_zstrcmp_ignore_backslash() {
let _g = crate::test_util::global_state_lock();
let flags = sort_flags::SORTIT_IGNORING_BACKSLASHES;
assert_eq!(zstrcmp("a\\bc", "abc", flags), Ordering::Equal);
}
#[test]
fn test_zstrcmp_numeric() {
let _g = crate::test_util::global_state_lock();
let flags = sort_flags::SORTIT_NUMERICALLY;
assert_eq!(zstrcmp("file2", "file10", flags), Ordering::Less);
assert_eq!(zstrcmp("file10", "file2", flags), Ordering::Greater);
assert_eq!(zstrcmp("file10", "file10", flags), Ordering::Equal);
}
#[test]
fn test_zstrcmp_numeric_signed() {
let _g = crate::test_util::global_state_lock();
let flags = sort_flags::SORTIT_NUMERICALLY_SIGNED;
assert_eq!(zstrcmp("-5", "3", flags), Ordering::Less);
assert_eq!(zstrcmp("-10", "-2", flags), Ordering::Less);
}
#[test]
fn test_strmetasort() {
let _g = crate::test_util::global_state_lock();
let mut arr = vec![
"file10".to_string(),
"file2".to_string(),
"file1".to_string(),
];
strmetasort(&mut arr, sort_flags::SORTIT_NUMERICALLY);
assert_eq!(arr, vec!["file1", "file2", "file10"]);
}
#[test]
fn test_strmetasort_backwards() {
let _g = crate::test_util::global_state_lock();
let mut arr = vec!["a".to_string(), "c".to_string(), "b".to_string()];
strmetasort(&mut arr, sort_flags::SORTIT_BACKWARDS);
assert_eq!(arr, vec!["c", "b", "a"]);
}
#[test]
fn test_natural_cmp() {
let _g = crate::test_util::global_state_lock();
assert_eq!(natural_cmp("item2", "item10"), Ordering::Less);
}
#[test]
fn test_strcasecmp() {
let _g = crate::test_util::global_state_lock();
assert_eq!(strcasecmp("Hello", "HELLO"), Ordering::Equal);
assert_eq!(strcasecmp("abc", "ABD"), Ordering::Less);
}
#[test]
fn test_strstr() {
let _g = crate::test_util::global_state_lock();
assert_eq!(strstr("hello world", "world"), Some(6));
assert_eq!(strstr("hello", "xyz"), None);
}
#[test]
fn test_strprefix_suffix() {
let _g = crate::test_util::global_state_lock();
assert!(strprefix("hello", "hel"));
assert!(!strprefix("hello", "ell"));
assert!(strsuffix("hello", "llo"));
assert!(!strsuffix("hello", "ell"));
}
#[test]
fn test_strjoin() {
let _g = crate::test_util::global_state_lock();
assert_eq!(strjoin(["a", "b", "c"], ","), "a,b,c");
assert_eq!(strjoin(Vec::<&str>::new(), ","), "");
}
#[test]
fn test_strsplit() {
let _g = crate::test_util::global_state_lock();
assert_eq!(strsplit("a,b,c", ','), vec!["a", "b", "c"]);
}
#[test]
fn test_strtrim() {
let _g = crate::test_util::global_state_lock();
assert_eq!(strtrim(" hello "), "hello");
}
#[test]
fn test_case_conversion() {
let _g = crate::test_util::global_state_lock();
assert_eq!(strlower("HeLLo"), "hello");
assert_eq!(strupper("HeLLo"), "HELLO");
}
}