use std::{
fmt::Display,
ops::{Add, Index, Mul},
str::FromStr,
string::ParseError,
};
use crate::{detail, Int, List};
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
pub struct Str {
data: String,
}
impl Str {
pub fn new() -> Self {
Self { data: String::new() }
}
pub fn len(&self) -> i32 {
self.data.len() as i32
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn as_str(&self) -> &str {
self.data.as_str()
}
pub fn chars(&self) -> std::str::Chars<'_> {
self.data.chars()
}
pub fn char_at(&self, mut index: i32) -> Option<char> {
if index < 0 {
index += self.data.chars().count() as i32;
if index < 0 {
return None;
}
}
self.data.chars().nth(index as usize)
}
pub fn find(&self, pattern: &str) -> Option<usize> {
self.data.find(pattern)
}
pub fn contains(&self, pattern: &str) -> bool {
self.data.contains(pattern)
}
pub fn count(&self, pattern: &str) -> usize {
if pattern.is_empty() {
return self.data.len() + 1;
}
let mut cnt = 0;
let mut start = 0;
while let Some(pos) = self.data[start..].find(pattern) {
cnt += 1;
start += pos + pattern.len();
}
cnt
}
pub fn to_decimal(&self) -> Option<f64> {
self.data.parse().ok()
}
pub fn to_integer(&self) -> Option<Int> {
self.data.parse().ok()
}
pub fn starts_with(&self, pattern: &str) -> bool {
self.data.starts_with(pattern)
}
pub fn ends_with(&self, pattern: &str) -> bool {
self.data.ends_with(pattern)
}
pub fn lower(&self) -> Self {
Self { data: self.data.to_lowercase() }
}
pub fn upper(&self) -> Self {
Self { data: self.data.to_uppercase() }
}
pub fn replace(&self, old_str: &str, new_str: &str) -> Self {
Self {
data: self.data.replace(old_str, new_str),
}
}
pub fn strip(&self) -> Self {
Self {
data: String::from(self.data.trim()),
}
}
pub fn split(&self, separator: &str) -> List<&str> {
self.data.split(separator).collect::<List<&str>>()
}
pub fn join(&self, str_list: List<&str>) -> Self {
Self {
data: str_list.data.join(self.data.as_str()),
}
}
}
impl From<&str> for Str {
fn from(value: &str) -> Self {
detail::check_full(value.len(), i32::MAX as usize);
Self { data: String::from(value) }
}
}
impl From<String> for Str {
fn from(value: String) -> Self {
detail::check_full(value.len(), i32::MAX as usize);
Self { data: value }
}
}
impl FromStr for Str {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self { data: s.to_string() })
}
}
impl Index<i32> for Str {
type Output = u8;
fn index(&self, index: i32) -> &Self::Output {
detail::check_bounds(index, -self.len(), self.len());
let index = detail::calc_index(index, self.data.len());
&self.data.as_bytes()[index]
}
}
impl Add for Str {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
(self.data + &rhs.data).into()
}
}
impl Mul<usize> for Str {
type Output = Self;
fn mul(self, rhs: usize) -> Self::Output {
self.data.repeat(rhs).into()
}
}
impl Display for Str {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "\"{}\"", self.data)
}
}
impl FromIterator<char> for Str {
fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> Self {
let data = iter.into_iter().collect();
Self { data }
}
}