1use core::str::{Bytes, CharIndices, Chars};
2
3use crate::{GString, GStringError, Validator};
4
5impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool>
7 GString<V, MIN, MAX, ASCII_ONLY>
8{
9 #[inline]
11 pub const fn len(&self) -> usize {
12 self.len
13 }
14
15 #[inline]
17 pub const fn capacity(&self) -> usize {
18 MAX
19 }
20
21 #[inline]
23 pub fn count(&self) -> usize {
24 self.chars().count()
25 }
26
27 #[inline]
29 pub const fn is_empty(&self) -> bool {
30 self.len == 0
31 }
32
33 #[inline]
35 pub const fn is_full(&self) -> bool {
36 self.len == MAX
37 }
38
39 #[inline]
40 pub const fn is_char_boundary(&self, index: usize) -> bool {
41 self.as_str().is_char_boundary(index)
42 }
43
44 #[inline]
46 pub const fn as_str(&self) -> &str {
47 unsafe {
50 let slice = core::slice::from_raw_parts(self.buf.as_ptr(), self.len);
51 core::str::from_utf8_unchecked(slice)
52 }
53 }
54
55 #[inline(always)]
57 pub const fn as_bytes(&self) -> &[u8] {
58 unsafe { core::slice::from_raw_parts(self.buf.as_ptr(), self.len) }
59 }
60}
61
62#[cfg(feature = "grapheme")]
64impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool>
65 GString<V, MIN, MAX, ASCII_ONLY>
66{
67 #[inline]
69 pub fn grapheme_count(&self) -> usize {
70 use crate::UnicodeSegmentation;
71 self.as_str().graphemes(true).count()
72 }
73
74 #[inline]
76 pub fn graphemes(&self) -> crate::Graphemes<'_> {
77 use crate::UnicodeSegmentation;
78 self.as_str().graphemes(true)
79 }
80}
81
82impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool>
84 GString<V, MIN, MAX, ASCII_ONLY>
85{
86 #[inline]
88 pub fn chars(&self) -> Chars<'_> {
89 self.as_str().chars()
90 }
91
92 #[inline]
94 pub fn char_indices(&self) -> CharIndices<'_> {
95 self.as_str().char_indices()
96 }
97
98 #[inline]
100 pub fn bytes(&self) -> Bytes<'_> {
101 self.as_str().bytes()
102 }
103}
104
105use core::str::FromStr;
106use core::str::{EncodeUtf16, EscapeDebug, EscapeDefault, EscapeUnicode, Lines, SplitWhitespace};
107
108pub trait Pattern {
109 type SplitIter<'a>: Iterator<Item = &'a str>
110 where
111 Self: 'a;
112
113 type MatchesIter<'a>: Iterator<Item = &'a str>
114 where
115 Self: 'a;
116
117 type RMatchesIter<'a>: Iterator<Item = &'a str>
118 where
119 Self: 'a;
120
121 type MatchIndicesIter<'a>: Iterator<Item = (usize, &'a str)>
122 where
123 Self: 'a;
124
125 type RMatchIndicesIter<'a>: Iterator<Item = (usize, &'a str)>
126 where
127 Self: 'a;
128
129 fn split<'a>(self, s: &'a str) -> Self::SplitIter<'a>
130 where
131 Self: 'a;
132
133 fn split_once<'a>(&self, s: &'a str) -> Option<(&'a str, &'a str)>;
134
135 fn rsplit_once<'a>(&self, s: &'a str) -> Option<(&'a str, &'a str)>;
136
137 fn strip_prefix<'a>(&self, s: &'a str) -> Option<&'a str>;
138
139 fn strip_suffix<'a>(&self, s: &'a str) -> Option<&'a str>;
140
141 fn matches<'a>(self, s: &'a str) -> Self::MatchesIter<'a>
142 where
143 Self: 'a;
144
145 fn rmatches<'a>(self, s: &'a str) -> Self::RMatchesIter<'a>
146 where
147 Self: 'a;
148
149 fn match_indices<'a>(self, s: &'a str) -> Self::MatchIndicesIter<'a>
150 where
151 Self: 'a;
152
153 fn rmatch_indices<'a>(self, s: &'a str) -> Self::RMatchIndicesIter<'a>
154 where
155 Self: 'a;
156
157 fn contains(&self, s: &str) -> bool;
161
162 fn starts_with(&self, s: &str) -> bool;
163
164 fn ends_with(&self, s: &str) -> bool;
165
166 fn find(&self, s: &str) -> Option<usize>;
167
168 fn rfind(&self, s: &str) -> Option<usize>;
169}
170
171impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool>
173 GString<V, MIN, MAX, ASCII_ONLY>
174{
175 #[inline]
176 pub fn contains<P>(&self, pat: P) -> bool
177 where
178 P: Pattern,
179 {
180 pat.contains(self.as_str())
181 }
182
183 #[inline]
184 pub fn starts_with<P>(&self, pat: P) -> bool
185 where
186 P: Pattern,
187 {
188 pat.starts_with(self.as_str())
189 }
190
191 #[inline]
192 pub fn ends_with<P>(&self, pat: P) -> bool
193 where
194 P: Pattern,
195 {
196 pat.ends_with(self.as_str())
197 }
198
199 #[inline]
200 pub fn find<P>(&self, pat: P) -> Option<usize>
201 where
202 P: Pattern,
203 {
204 pat.find(self.as_str())
205 }
206
207 #[inline]
208 pub fn rfind<P>(&self, pat: P) -> Option<usize>
209 where
210 P: Pattern,
211 {
212 pat.rfind(self.as_str())
213 }
214}
215
216impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool>
218 GString<V, MIN, MAX, ASCII_ONLY>
219{
220 #[inline]
221 pub fn get<I>(&self, i: I) -> Option<&<I as core::slice::SliceIndex<str>>::Output>
222 where
223 I: core::slice::SliceIndex<str>,
224 {
225 self.as_str().get(i)
226 }
227}
228
229impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool>
232 GString<V, MIN, MAX, ASCII_ONLY>
233{
234 #[inline]
237 pub fn split<P: Pattern>(&self, pat: P) -> P::SplitIter<'_> {
238 pat.split(self.as_str())
239 }
240
241 #[inline]
244 pub fn split_whitespace(&self) -> SplitWhitespace<'_> {
245 self.as_str().split_whitespace()
246 }
247
248 #[inline]
250 pub fn lines(&self) -> Lines<'_> {
251 self.as_str().lines()
252 }
253
254 #[inline]
256 pub fn split_once<P: Pattern>(&self, delimiter: P) -> Option<(&str, &str)> {
257 delimiter.split_once(self.as_str())
258 }
259
260 #[inline]
262 pub fn rsplit_once<P: Pattern>(&self, delimiter: P) -> Option<(&str, &str)> {
263 delimiter.rsplit_once(self.as_str())
264 }
265}
266
267impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool>
270 GString<V, MIN, MAX, ASCII_ONLY>
271{
272 #[inline]
274 pub fn try_trim(&self) -> Result<Self, GStringError<V::Err>> {
275 Self::try_new(self.as_str().trim())
276 }
277
278 #[inline]
280 pub fn try_trim_start(&self) -> Result<Self, GStringError<V::Err>> {
281 Self::try_new(self.as_str().trim_start())
282 }
283
284 #[inline]
286 pub fn try_trim_end(&self) -> Result<Self, GStringError<V::Err>> {
287 Self::try_new(self.as_str().trim_end())
288 }
289
290 #[inline]
292 pub fn strip_prefix<P: Pattern>(&self, prefix: P) -> Option<&str> {
293 prefix.strip_prefix(self.as_str())
294 }
295
296 #[inline]
298 pub fn strip_suffix<P: Pattern>(&self, suffix: P) -> Option<&str> {
299 suffix.strip_suffix(self.as_str())
300 }
301}
302
303impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool>
306 GString<V, MIN, MAX, ASCII_ONLY>
307{
308 #[inline]
310 pub fn matches<P: Pattern>(&self, pat: P) -> P::MatchesIter<'_> {
311 pat.matches(self.as_str())
312 }
313
314 #[inline]
317 pub fn rmatches<P: Pattern>(&self, pat: P) -> P::RMatchesIter<'_> {
318 pat.rmatches(self.as_str())
319 }
320
321 #[inline]
324 pub fn match_indices<P: Pattern>(&self, pat: P) -> P::MatchIndicesIter<'_> {
325 pat.match_indices(self.as_str())
326 }
327
328 #[inline]
331 pub fn rmatch_indices<P: Pattern>(&self, pat: P) -> P::RMatchIndicesIter<'_> {
332 pat.rmatch_indices(self.as_str())
333 }
334}
335
336impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool>
339 GString<V, MIN, MAX, ASCII_ONLY>
340{
341 #[inline]
343 pub fn parse<F>(&self) -> Result<F, F::Err>
344 where
345 F: FromStr,
346 {
347 self.as_str().parse()
348 }
349
350 #[inline]
352 pub fn is_ascii(&self) -> bool {
353 self.as_str().is_ascii()
354 }
355
356 #[inline]
358 pub fn eq_ignore_ascii_case(&self, other: &str) -> bool {
359 self.as_str().eq_ignore_ascii_case(other)
360 }
361}
362
363impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool>
366 GString<V, MIN, MAX, ASCII_ONLY>
367{
368 #[inline]
370 pub fn escape_debug(&self) -> EscapeDebug<'_> {
371 self.as_str().escape_debug()
372 }
373
374 #[inline]
377 pub fn escape_default(&self) -> EscapeDefault<'_> {
378 self.as_str().escape_default()
379 }
380
381 #[inline]
384 pub fn escape_unicode(&self) -> EscapeUnicode<'_> {
385 self.as_str().escape_unicode()
386 }
387}
388
389impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool>
392 GString<V, MIN, MAX, ASCII_ONLY>
393{
394 #[inline]
396 pub fn encode_utf16(&self) -> EncodeUtf16<'_> {
397 self.as_str().encode_utf16()
398 }
399}