datex_core/values/core_values/
text.rs1use crate::{
2 prelude::*, shared_values::shared_container::IndexOutOfBoundsError,
3 traits::structural_eq::StructuralEq,
4};
5use core::{
6 fmt::Display,
7 ops::{Add, AddAssign},
8 result::Result,
9};
10use serde::{Deserialize, Serialize};
11
12#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
13pub struct Text(pub String);
14
15impl Display for Text {
16 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
18 core::write!(f, "\"{}\"", self.0)
19 }
20}
21
22impl Text {
23 pub fn length(&self) -> usize {
24 self.0.len()
25 }
26 pub fn to_uppercase(&self) -> Text {
27 Text(self.0.to_uppercase())
28 }
29 pub fn to_lowercase(&self) -> Text {
30 Text(self.0.to_lowercase())
31 }
32 pub fn as_str(&self) -> &str {
33 &self.0
34 }
35 pub fn as_string(&self) -> String {
36 self.0.clone()
37 }
38 pub fn char_at(&self, index: i64) -> Result<char, IndexOutOfBoundsError> {
39 let index = self.wrap_index(index);
40 self.0.chars().nth(index).ok_or(IndexOutOfBoundsError {
41 index: index as u32,
42 })
43 }
44
45 #[inline]
46 fn wrap_index(&self, index: i64) -> usize {
47 if index < 0 {
48 let len = self.0.chars().count() as i64;
49 (len + index) as usize
50 } else {
51 index as usize
52 }
53 }
54 #[inline]
55 fn get_valid_index(
56 &self,
57 index: i64,
58 ) -> Result<usize, IndexOutOfBoundsError> {
59 let index = self.wrap_index(index);
60 if (index) < self.0.len() {
61 Ok(index)
62 } else {
63 Err(IndexOutOfBoundsError {
64 index: index as u32,
65 })
66 }
67 }
68
69 pub fn substring(&self, start: usize, end: usize) -> Option<Text> {
70 if start > end || end > self.0.len() {
71 return None;
72 }
73 Some(Text(self.0[start..end].to_string()))
74 }
75 pub fn contains(&self, substring: &str) -> bool {
76 self.0.contains(substring)
77 }
78 pub fn starts_with(&self, prefix: &str) -> bool {
79 self.0.starts_with(prefix)
80 }
81 pub fn ends_with(&self, suffix: &str) -> bool {
82 self.0.ends_with(suffix)
83 }
84 pub fn index_of(&self, substring: &str) -> Option<usize> {
85 self.0.find(substring)
86 }
87 pub fn last_index_of(&self, substring: &str) -> Option<usize> {
88 self.0.rfind(substring)
89 }
90 pub fn is_empty(&self) -> bool {
91 self.0.is_empty()
92 }
93 pub fn trim(&self) -> Text {
94 Text(self.0.trim().to_string())
95 }
96 pub fn trim_start(&self) -> Text {
97 Text(self.0.trim_start().to_string())
98 }
99 pub fn split(&self, delimiter: &str) -> Vec<Text> {
100 self.0
101 .split(delimiter)
102 .map(|s| Text(s.to_string()))
103 .collect()
104 }
105 pub fn join(texts: &[Text], separator: &str) -> Text {
106 let joined = texts
107 .iter()
108 .map(|t| t.0.as_str())
109 .collect::<Vec<&str>>()
110 .join(separator);
111 Text(joined)
112 }
113 pub fn repeat(&self, n: usize) -> Text {
114 Text(self.0.repeat(n))
115 }
116}
117
118impl Text {
120 pub fn clear(&mut self) {
121 self.0.clear();
122 }
123 pub fn reverse(&mut self) {
124 let reversed = self.0.chars().rev().collect::<String>();
125 self.0 = reversed;
126 }
127 pub fn push_str(&mut self, s: &str) {
128 self.0.push_str(s);
129 }
130 pub fn push_char(&mut self, c: char) {
131 self.0.push(c);
132 }
133 pub fn pop_char(&mut self) -> Option<char> {
134 self.0.pop()
135 }
136 pub fn insert(&mut self, index: usize, s: &str) -> Result<(), String> {
137 if index > self.0.len() {
138 return Err("Index out of bounds".to_string());
139 }
140 self.0.insert_str(index, s);
141 Ok(())
142 }
143 pub fn remove(&mut self, index: usize) -> Result<char, String> {
145 if index >= self.0.len() {
146 return Err("Index out of bounds".to_string());
147 }
148 Ok(self.0.remove(index))
149 }
150 pub fn replace(&mut self, from: &str, to: &str) {
151 self.0 = self.0.replace(from, to);
152 }
153 pub fn replace_range(
154 &mut self,
155 range: core::ops::Range<usize>,
156 replace_with: &str,
157 ) -> Result<(), String> {
158 if range.start > range.end || range.end > self.0.len() {
159 return Err("Range out of bounds".to_string());
160 }
161 self.0.replace_range(range, replace_with);
162 Ok(())
163 }
164 pub fn set_char_at(
165 &mut self,
166 index: i64,
167 c: char,
168 ) -> Result<(), IndexOutOfBoundsError> {
169 let index = self.get_valid_index(index)?;
170 let mut chars: Vec<char> = self.0.chars().collect();
171 chars[index] = c;
172 self.0 = chars.iter().collect();
173 Ok(())
174 }
175}
176
177impl StructuralEq for Text {
178 fn structural_eq(&self, other: &Self) -> bool {
179 self.0 == other.0
180 }
181}
182
183impl From<&str> for Text {
186 fn from(s: &str) -> Self {
187 Text(s.to_string())
188 }
189}
190
191impl From<String> for Text {
192 fn from(s: String) -> Self {
193 Text(s)
194 }
195}
196
197impl AddAssign<Text> for Text {
200 fn add_assign(&mut self, rhs: Text) {
201 self.0 += &rhs.0;
202 }
203}
204
205impl Add for Text {
206 type Output = Self;
207
208 fn add(self, rhs: Self) -> Self::Output {
209 Text(self.0 + &rhs.0)
210 }
211}
212
213impl Add for &Text {
214 type Output = Text;
215
216 fn add(self, rhs: Self) -> Self::Output {
217 Text(self.0.clone() + &rhs.0)
218 }
219}
220
221impl Add<Text> for &Text {
222 type Output = Text;
223
224 fn add(self, rhs: Text) -> Self::Output {
225 Text(self.0.clone() + &rhs.0)
226 }
227}
228
229impl Add<&Text> for Text {
230 type Output = Text;
231
232 fn add(self, rhs: &Text) -> Self::Output {
233 Text(self.0 + &rhs.0)
234 }
235}
236
237impl Add<&str> for Text {
238 type Output = Text;
239
240 fn add(self, rhs: &str) -> Self::Output {
241 Text(self.0 + rhs)
242 }
243}