use rand::Rng;
use std::sync::LazyLock;
pub trait StringExt {
fn http_std_case(&self) -> String;
fn url_decode(&self) -> String;
fn starts_with_ignore_ascii_case(&self, other: &str) -> bool;
}
impl StringExt for str {
fn http_std_case(&self) -> String {
let mut ret = "".to_string();
let mut upper = true;
for ch in self.chars() {
if ch == '-' {
upper = true;
ret.push(ch);
} else if upper {
ret.push(ch.to_ascii_uppercase());
upper = false;
} else {
ret.push(ch.to_ascii_lowercase());
}
}
ret
}
fn url_decode(&self) -> String {
let mut ret = vec![];
let mut chars = self.chars();
while let Some(ch) = chars.next() {
match ch {
'%' => {
let hex = chars.next().unwrap_or('0').to_digit(16).unwrap_or(0) << 4
| chars.next().unwrap_or('0').to_digit(16).unwrap_or(0);
ret.push(hex as u8);
}
'+' => {
ret.push(b' ');
}
_ => {
ret.push(ch as u8);
}
}
}
String::from_utf8(ret).unwrap_or("".to_string())
}
fn starts_with_ignore_ascii_case(&self, other: &str) -> bool {
if self.len() < other.len() {
return false;
}
(&self[..other.len()]).eq_ignore_ascii_case(other)
}
}
impl StringExt for String {
fn http_std_case(&self) -> String {
self[..].http_std_case()
}
fn url_decode(&self) -> String {
self[..].url_decode()
}
fn starts_with_ignore_ascii_case(&self, other: &str) -> bool {
self[..].starts_with_ignore_ascii_case(other)
}
}
pub static ALPHANUM_CHARS: LazyLock<Vec<char>> = LazyLock::new(|| {
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
.chars()
.collect()
});
pub struct StringUtil;
impl StringUtil {
pub fn rand(num: usize) -> String {
let mut rng = rand::thread_rng();
std::iter::repeat(())
.map(|()| ALPHANUM_CHARS[rng.r#gen::<usize>() % ALPHANUM_CHARS.len()])
.take(num)
.collect()
}
pub fn rand_name(num: usize) -> String {
if num == 0 {
return "".to_string();
}
format!("_{}", Self::rand(num - 1))
}
}
#[macro_export]
macro_rules! ssformat {
($len:expr, $($arg:tt)*) => {
{
use std::fmt::Write;
let mut buf = smallstr::SmallString::<[u8; $len]>::new();
let _ = buf.write_fmt(::core::format_args!($($arg)*));
buf
}
};
}