mut_str/char_ref.rs
1use core::{
2 borrow::{Borrow, BorrowMut},
3 cmp,
4 fmt::{self, Display},
5 hash, ptr, slice,
6 str::{self, FromStr},
7};
8#[cfg(feature = "alloc")]
9extern crate alloc;
10// `ToOwned` is in the std prelude, so ignore unused import
11#[allow(unused_imports)]
12#[cfg(feature = "alloc")]
13use alloc::borrow::ToOwned;
14
15use crate::{
16 errors::{
17 LenNotEqual, ReplaceWithPadCharError, ReplaceWithPadError, ReplacementTooLong,
18 TryFromBytesError, TryFromStrError,
19 },
20 OwnedChar,
21};
22
23#[repr(transparent)]
24/// A UTF-8 encoded character.
25///
26/// This type can only be obtained as a reference or mutable reference similarly to [`prim@str`].
27///
28/// ```
29/// use mut_str::Char;
30///
31/// let s = "Hello, World!";
32/// let c = Char::get(s, 1).unwrap();
33///
34/// assert_eq!(c, 'e');
35/// ```
36pub struct Char {
37 c: u8,
38}
39
40impl Char {
41 #[must_use]
42 #[inline]
43 /// Create a new character reference from a pointer to a character.
44 ///
45 /// # Safety
46 /// `p` must be a pointer to the first byte of a valid UTF-8 character.
47 pub const unsafe fn new_unchecked(p: *const u8) -> *const Self {
48 p.cast()
49 }
50
51 #[must_use]
52 #[inline]
53 /// Create a new mutable character reference from a mutable pointer to a character.
54 ///
55 /// # Safety
56 /// `p` must be a mutable pointer to the first byte of a valid UTF-8 character that
57 /// can be mutated. String literals cannot be mutated.
58 pub const unsafe fn new_unchecked_mut(p: *mut u8) -> *mut Self {
59 p.cast()
60 }
61
62 #[must_use]
63 /// Get a character reference from a [`prim@str`] and an index.
64 ///
65 /// ```
66 /// use mut_str::Char;
67 ///
68 /// let s = "Hello, World!";
69 /// let c = Char::get(s, 1).unwrap();
70 ///
71 /// assert_eq!(c, 'e');
72 /// ```
73 pub fn get(s: &str, i: usize) -> Option<&Self> {
74 let mut chars = s.char_indices();
75 let start = chars.nth(i)?.0;
76
77 let p = s.as_bytes().get(start)?;
78
79 // SAFETY:
80 // Pointer offset is from `CharIndices`, so it is valid.
81 Some(unsafe { &*Self::new_unchecked(p) })
82 }
83
84 #[must_use]
85 /// Get a mutable character reference from a mutable [`prim@str`] and an index.
86 ///
87 /// ```
88 /// use mut_str::Char;
89 ///
90 /// let mut s = Box::<str>::from("Hello, World!");
91 /// let c = Char::get_mut(&mut *s, 1).unwrap();
92 ///
93 /// assert_eq!(c, 'e');
94 /// ```
95 pub fn get_mut(s: &mut str, i: usize) -> Option<&mut Self> {
96 let mut chars = s.char_indices();
97 let start = chars.nth(i)?.0;
98
99 // SAFETY:
100 // `Self` maintains utf8 validity.
101 let p = unsafe { s.as_bytes_mut() }.get_mut(start)?;
102
103 // SAFETY:
104 // Pointer offset is from `CharIndices`, so it is valid.
105 Some(unsafe { &mut *Self::new_unchecked_mut(p) })
106 }
107
108 #[must_use]
109 #[inline]
110 // This can never be empty.
111 #[allow(clippy::len_without_is_empty)]
112 /// Get the length of the character in bytes.
113 ///
114 /// This will be in the range `1..=4`.
115 ///
116 /// ```
117 /// use mut_str::Char;
118 ///
119 /// let s = "oΦ⏣🌑";
120 ///
121 /// assert_eq!(Char::get(s, 0).unwrap().len(), 1);
122 /// assert_eq!(Char::get(s, 1).unwrap().len(), 2);
123 /// assert_eq!(Char::get(s, 2).unwrap().len(), 3);
124 /// assert_eq!(Char::get(s, 3).unwrap().len(), 4);
125 /// ```
126 pub fn len(&self) -> usize {
127 match self.c.leading_ones() {
128 0 => 1,
129 l @ 2..=4 => l as usize,
130 _ => unreachable!("invalid char pointer"),
131 }
132 }
133
134 #[must_use]
135 #[inline]
136 /// Get a pointer to the character ([`prim@pointer`]).
137 pub const fn as_ptr(&self) -> *const u8 {
138 ptr::from_ref(self).cast()
139 }
140
141 #[must_use]
142 #[inline]
143 /// Get a mutable pointer to the character ([`prim@pointer`]).
144 pub fn as_mut_ptr(&mut self) -> *mut u8 {
145 ptr::from_mut(self).cast()
146 }
147
148 #[must_use]
149 #[inline]
150 /// Get the character as a byte slice ([`prim@slice`]).
151 ///
152 /// ```
153 /// use mut_str::Char;
154 ///
155 /// let s = "Hello, 🌍!";
156 ///
157 /// let c = Char::get(s, 1).unwrap();
158 /// assert_eq!(c.as_bytes(), &[101]);
159 ///
160 /// let c = Char::get(s, 7).unwrap();
161 /// assert_eq!(c.as_bytes(), &[240, 159, 140, 141]);
162 /// ```
163 pub fn as_bytes(&self) -> &[u8] {
164 // SAFETY:
165 // The pointer is to the start of the character in the utf8 string.
166 // There is guaranteed to be `self.len()` bytes after (and including)
167 // the pointer.
168 unsafe { slice::from_raw_parts(self.as_ptr(), self.len()) }
169 }
170
171 #[must_use]
172 #[inline]
173 /// Get the character as a mutable byte slice ([`prim@slice`]).
174 ///
175 /// # Safety
176 /// See [`str::as_bytes_mut`].
177 pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
178 slice::from_raw_parts_mut(self.as_mut_ptr(), self.len())
179 }
180
181 #[must_use]
182 #[inline]
183 /// Get the character as a [`prim@str`].
184 ///
185 /// ```
186 /// use mut_str::Char;
187 ///
188 /// let s = "Hello, 🌍!";
189 ///
190 /// let c = Char::get(s, 1).unwrap();
191 /// assert_eq!(c.as_str(), "e");
192 ///
193 /// let c = Char::get(s, 7).unwrap();
194 /// assert_eq!(c.as_str(), "🌍");
195 /// ```
196 pub fn as_str(&self) -> &str {
197 // SAFETY:
198 // `self.s` is guaranteed to be the bytes of a valid utf8 string.
199 unsafe { str::from_utf8_unchecked(self.as_bytes()) }
200 }
201
202 #[must_use]
203 #[inline]
204 /// Get the character as a mutable [`prim@str`].
205 ///
206 /// ```
207 /// use mut_str::Char;
208 ///
209 /// let mut s = Box::<str>::from("Hello, 🌍!");
210 ///
211 /// let c = Char::get_mut(&mut *s, 1).unwrap();
212 /// assert_eq!(c.as_str_mut(), "e");
213 ///
214 /// let c = Char::get_mut(&mut *s, 7).unwrap();
215 /// assert_eq!(c.as_str_mut(), "🌍");
216 /// ```
217 pub fn as_str_mut(&mut self) -> &mut str {
218 // SAFETY:
219 // `self.s` is guaranteed to be the bytes of a valid utf8 string.
220 // It can be assumed that a `str` will stay valid.
221 unsafe { str::from_utf8_unchecked_mut(self.as_bytes_mut()) }
222 }
223
224 #[must_use]
225 /// Get the character as a [`char`].
226 ///
227 /// ```
228 /// use mut_str::Char;
229 ///
230 /// let s = "Hello, 🌍!";
231 ///
232 /// let c = Char::get(s, 1).unwrap();
233 /// assert_eq!(c.as_char(), 'e');
234 ///
235 /// let c = Char::get(s, 7).unwrap();
236 /// assert_eq!(c.as_char(), '🌍');
237 /// ```
238 pub fn as_char(&self) -> char {
239 // SAFETY:
240 // `self` is guaranteed to contain exactly one character, so calling`
241 // `next for the first time on the `Chars` iterator will yield an
242 // `Option::Some`.
243 unsafe { self.as_str().chars().next().unwrap_unchecked() }
244 }
245
246 #[must_use]
247 #[inline]
248 /// Creates an [`OwnedChar`] from a borrowed [`Char`].
249 ///
250 /// ```
251 /// use mut_str::{Char, OwnedChar};
252 ///
253 /// let s = "Hello, 🌍!";
254 ///
255 /// let c = Char::get(s, 1).unwrap();
256 /// assert_eq!(c.as_owned(), OwnedChar::from('e'));
257 ///
258 /// let c = Char::get(s, 7).unwrap();
259 /// assert_eq!(c.as_owned(), OwnedChar::from('🌍'));
260 /// ```
261 pub fn as_owned(&self) -> OwnedChar {
262 let bytes = self.as_bytes();
263
264 // SAFETY:
265 // `bytes` is guaranteed be to a valid UTF-8 character.
266 unsafe { OwnedChar::from_bytes_unchecked(bytes) }
267 }
268
269 #[inline]
270 /// Copy the character to a byte buffer and get the [`prim@str`] containing the inserted character.
271 /// Returns `None` if `buffer` is shorter than `self`.
272 ///
273 /// ```
274 /// use mut_str::Char;
275 ///
276 /// let s = "Hello, World!";
277 /// let c = Char::get(s, 1).unwrap();
278 ///
279 /// let mut buffer = [0; 4];
280 /// let c2 = c.copy_to(&mut buffer).unwrap();
281 ///
282 /// assert_eq!(c2, c);
283 /// ```
284 pub fn copy_to<'a>(&self, buffer: &'a mut [u8]) -> Option<&'a mut Self> {
285 let len = self.len();
286 if len > buffer.len() {
287 None
288 } else {
289 buffer[..len].copy_from_slice(self.as_bytes());
290
291 // SAFETY:
292 // This is valid as a utf8 character was just copied to the buffer.
293 Some(unsafe { &mut *Self::new_unchecked_mut(buffer.as_mut_ptr()) })
294 }
295 }
296
297 /// Replace the character with another of the same length.
298 ///
299 /// ```
300 /// use mut_str::Char;
301 ///
302 /// let mut s = Box::<str>::from("oΦ⏣🌑");
303 ///
304 /// let c = Char::get_mut(&mut *s, 0).unwrap();
305 /// assert!(c.replace('e').is_ok());
306 /// assert_eq!(&*s, "eΦ⏣🌑");
307 ///
308 /// let c = Char::get_mut(&mut *s, 1).unwrap();
309 /// assert!(c.replace('a').is_err());
310 /// ```
311 ///
312 /// # Errors
313 /// - If `r`, when utf8 encoded, does not have the same length as `self`, [`LenNotEqual`] will be returned.
314 pub fn replace<C>(&mut self, r: C) -> Result<(), LenNotEqual>
315 where
316 C: Into<char>,
317 {
318 let r = r.into();
319
320 if self.len() != r.len_utf8() {
321 return Err(LenNotEqual);
322 }
323
324 // SAFETY:
325 // Replacing the character with a valid utf8 character of the same
326 // length is valid.
327 r.encode_utf8(unsafe { self.as_bytes_mut() });
328 Ok(())
329 }
330
331 /// Replace the character with another of the same length or shorter.
332 /// The remaining bytes will be filled with spaces.
333 ///
334 /// ```
335 /// use mut_str::Char;
336 ///
337 /// let mut s = Box::<str>::from("oΦ⏣🌑");
338 ///
339 /// let c = Char::get_mut(&mut *s, 0).unwrap();
340 /// assert!(c.replace_with_pad_space('e').is_ok());
341 /// assert_eq!(&*s, "eΦ⏣🌑");
342 ///
343 /// let c = Char::get_mut(&mut *s, 1).unwrap();
344 /// assert!(c.replace_with_pad_space('a').is_ok());
345 /// assert_eq!(&*s, "ea ⏣🌑");
346 /// ```
347 ///
348 /// # Errors
349 /// - If `r`, when utf8 encoded, is longer than `self`, [`ReplacementTooLong`] will be returned.
350 pub fn replace_with_pad_space<C>(&mut self, r: C) -> Result<(), ReplacementTooLong>
351 where
352 C: Into<char>,
353 {
354 let r = r.into();
355
356 if self.len() < r.len_utf8() {
357 return Err(ReplacementTooLong);
358 }
359
360 // SAFETY:
361 // `Self` maintains utf8 validity.
362 let (char_slice, remaining) = unsafe { self.as_bytes_mut().split_at_mut(r.len_utf8()) };
363
364 r.encode_utf8(char_slice);
365 remaining.fill(b' ');
366
367 Ok(())
368 }
369
370 /// Replace the character with another of the same length or shorter.
371 /// The remaining bytes will be filled with `pad`.
372 ///
373 /// ```
374 /// use mut_str::Char;
375 ///
376 /// let mut s = Box::<str>::from("oΦ⏣🌑");
377 ///
378 /// let c = Char::get_mut(&mut *s, 0).unwrap();
379 /// assert!(c.replace_with_pad('e', b'b').is_ok());
380 /// assert_eq!(&*s, "eΦ⏣🌑");
381 ///
382 /// let c = Char::get_mut(&mut *s, 1).unwrap();
383 /// assert!(c.replace_with_pad('a', b'b').is_ok());
384 /// assert_eq!(&*s, "eab⏣🌑");
385 /// ```
386 ///
387 /// # Errors
388 /// - If `pad` is not valid utf8, [`ReplaceWithPadError::InvalidPad`] will be returned.
389 /// - If `r`, when utf8 encoded, is longer than `self`, [`ReplaceWithPadError::ReplacementLen`] will be returned.
390 pub fn replace_with_pad<C>(&mut self, r: C, pad: u8) -> Result<(), ReplaceWithPadError>
391 where
392 C: Into<char>,
393 {
394 let r = r.into();
395
396 if self.len() < r.len_utf8() {
397 return Err(ReplaceWithPadError::CHAR_LEN);
398 }
399
400 str::from_utf8(&[pad]).map_err(ReplaceWithPadError::InvalidPad)?;
401
402 // SAFETY:
403 // `Self` maintains utf8 validity.
404 let (char_slice, remaining) = unsafe { self.as_bytes_mut().split_at_mut(r.len_utf8()) };
405
406 r.encode_utf8(char_slice);
407 remaining.fill(pad);
408
409 Ok(())
410 }
411
412 /// Replace the character with another of the same length or shorter.
413 /// The remaining bytes will be filled with `pad`, which must be one byte long.
414 ///
415 /// ```
416 /// use mut_str::Char;
417 ///
418 /// let mut s = Box::<str>::from("oΦ⏣🌑");
419 ///
420 /// let c = Char::get_mut(&mut *s, 0).unwrap();
421 /// assert!(c.replace_with_pad_char('e', 'b').is_ok());
422 /// assert_eq!(&*s, "eΦ⏣🌑");
423 ///
424 /// let c = Char::get_mut(&mut *s, 1).unwrap();
425 /// assert!(c.replace_with_pad_char('a', 'b').is_ok());
426 /// assert_eq!(&*s, "eab⏣🌑");
427 /// ```
428 ///
429 /// # Errors
430 /// - If `pad_char`, when utf8 encoded, is longer than `Self`, [`ReplaceWithPadCharError::PadCharTooLong`] will be returned.
431 /// - If `r`, when utf8 encoded, is longer than `self`, [`ReplaceWithPadCharError::ReplacementLen`] will be returned.
432 pub fn replace_with_pad_char<C1, C2>(
433 &mut self,
434 r: C1,
435 pad_char: C2,
436 ) -> Result<(), ReplaceWithPadCharError>
437 where
438 C1: Into<char>,
439 C2: Into<char>,
440 {
441 let (r, pad_char) = (r.into(), pad_char.into());
442
443 if pad_char.len_utf8() != 1 {
444 return Err(ReplaceWithPadCharError::PadCharTooLong);
445 }
446
447 if self.len() < r.len_utf8() {
448 return Err(ReplaceWithPadCharError::CHAR_LEN);
449 }
450
451 let mut pad: u8 = 0;
452 pad_char.encode_utf8(slice::from_mut(&mut pad));
453
454 // SAFETY:
455 // `Self` maintains utf8 validity.
456 let (char_slice, remaining) = unsafe { self.as_bytes_mut().split_at_mut(r.len_utf8()) };
457
458 r.encode_utf8(char_slice);
459 remaining.fill(pad);
460
461 Ok(())
462 }
463
464 /// Replace the character with another of the same length or shorter, right aligned.
465 /// The remaining bytes before the character will be filled with spaces.
466 ///
467 /// ```
468 /// use mut_str::Char;
469 ///
470 /// let mut s = Box::<str>::from("oΦ⏣🌑");
471 ///
472 /// let c = Char::get_mut(&mut *s, 0).unwrap();
473 /// assert!(c.replace_with_pad_left_space('e').is_ok());
474 /// assert_eq!(&*s, "eΦ⏣🌑");
475 ///
476 /// let c = Char::get_mut(&mut *s, 1).unwrap();
477 /// let c2 = c.replace_with_pad_left_space('a').unwrap();
478 /// assert_eq!(c2, 'a');
479 /// assert_eq!(c, ' ');
480 /// assert_eq!(&*s, "e a⏣🌑");
481 /// ```
482 ///
483 /// # Errors
484 /// - If `r`, when utf8 encoded, is longer than `self`, [`ReplacementTooLong`] will be returned.
485 pub fn replace_with_pad_left_space<C>(&mut self, r: C) -> Result<&mut Self, ReplacementTooLong>
486 where
487 C: Into<char>,
488 {
489 let r = r.into();
490 let len = self.len();
491
492 if len < r.len_utf8() {
493 return Err(ReplacementTooLong);
494 }
495
496 let (remaining, char_slice) =
497 // SAFETY:
498 // `Self` maintains utf8 validity.
499 unsafe { self.as_bytes_mut().split_at_mut(len - r.len_utf8()) };
500
501 r.encode_utf8(char_slice);
502 remaining.fill(b' ');
503
504 // SAFETY:
505 // The pointer is directly after a char boundary.
506 Ok(unsafe { &mut *Self::new_unchecked_mut(char_slice.as_mut_ptr()) })
507 }
508
509 /// Replace the character with another of the same length or shorter, right aligned.
510 /// The remaining bytes before the character will be filled with `pad`.
511 ///
512 /// ```
513 /// use mut_str::Char;
514 ///
515 /// let mut s = Box::<str>::from("oΦ⏣🌑");
516 ///
517 /// let c = Char::get_mut(&mut *s, 0).unwrap();
518 /// assert!(c.replace_with_pad_left('e', b'b').is_ok());
519 /// assert_eq!(&*s, "eΦ⏣🌑");
520 ///
521 /// let c = Char::get_mut(&mut *s, 1).unwrap();
522 /// let c2 = c.replace_with_pad_left('a', b'b').unwrap();
523 /// assert_eq!(c2, 'a');
524 /// assert_eq!(c, 'b');
525 /// assert_eq!(&*s, "eba⏣🌑");
526 /// ```
527 ///
528 /// # Errors
529 /// - If `pad` is not valid utf8, [`ReplaceWithPadError::InvalidPad`] will be returned.
530 /// - If `r`, when utf8 encoded, is longer than `self`, [`ReplaceWithPadError::ReplacementLen`] will be returned.
531 pub fn replace_with_pad_left<C>(
532 &mut self,
533 r: C,
534 pad: u8,
535 ) -> Result<&mut Self, ReplaceWithPadError>
536 where
537 C: Into<char>,
538 {
539 let r = r.into();
540 let len = self.len();
541
542 if len < r.len_utf8() {
543 return Err(ReplaceWithPadError::CHAR_LEN);
544 }
545
546 str::from_utf8(&[pad]).map_err(ReplaceWithPadError::InvalidPad)?;
547
548 let (remaining, char_slice) =
549 // SAFETY:
550 // `Self` maintains utf8 validity.
551 unsafe { self.as_bytes_mut().split_at_mut(len - r.len_utf8()) };
552
553 r.encode_utf8(char_slice);
554 remaining.fill(pad);
555
556 // SAFETY:
557 // The pointer is directly after a char boundary.
558 Ok(unsafe { &mut *Self::new_unchecked_mut(char_slice.as_mut_ptr()) })
559 }
560
561 /// Replace the character with another of the same length or shorter, right aligned.
562 /// The remaining bytes before the character will be filled with `char`, which must be one byte long.
563 ///
564 /// ```
565 /// use mut_str::Char;
566 ///
567 /// let mut s = Box::<str>::from("oΦ⏣🌑");
568 ///
569 /// let c = Char::get_mut(&mut *s, 0).unwrap();
570 /// assert!(c.replace_with_pad_left_char('e', 'b').is_ok());
571 /// assert_eq!(&*s, "eΦ⏣🌑");
572 ///
573 /// let c = Char::get_mut(&mut *s, 1).unwrap();
574 /// let c2 = c.replace_with_pad_left_char('a', 'b').unwrap();
575 /// assert_eq!(c2, 'a');
576 /// assert_eq!(c, 'b');
577 /// assert_eq!(&*s, "eba⏣🌑");
578 /// ```
579 ///
580 /// # Errors
581 /// - If `pad_char`, when utf8 encoded, is longer than `Self`, [`ReplaceWithPadCharError::PadCharTooLong`] will be returned.
582 /// - If `r`, when utf8 encoded, is longer than `self`, [`ReplaceWithPadCharError::ReplacementLen`] will be returned.
583 pub fn replace_with_pad_left_char<C1, C2>(
584 &mut self,
585 r: C1,
586 pad_char: C2,
587 ) -> Result<&mut Self, ReplaceWithPadCharError>
588 where
589 C1: Into<char>,
590 C2: Into<char>,
591 {
592 let (r, pad_char) = (r.into(), pad_char.into());
593 let len = self.len();
594
595 if pad_char.len_utf8() != 1 {
596 return Err(ReplaceWithPadCharError::PadCharTooLong);
597 }
598
599 if len < r.len_utf8() {
600 return Err(ReplaceWithPadCharError::CHAR_LEN);
601 }
602
603 let mut pad: u8 = 0;
604 pad_char.encode_utf8(slice::from_mut(&mut pad));
605
606 let (remaining, char_slice) =
607 // SAFETY:
608 // `Self` maintains utf8 validity.
609 unsafe { self.as_bytes_mut().split_at_mut(len - r.len_utf8()) };
610
611 r.encode_utf8(char_slice);
612 remaining.fill(pad);
613
614 // SAFETY:
615 // The pointer is directly after a char boundary.
616 Ok(unsafe { &mut *Self::new_unchecked_mut(char_slice.as_mut_ptr()) })
617 }
618
619 #[must_use]
620 #[inline]
621 /// Checks if the value is within ASCII range.
622 ///
623 /// ```
624 /// use mut_str::Char;
625 ///
626 /// let s = "oΦ⏣🌑";
627 ///
628 /// let c = Char::get(s, 0).unwrap();
629 /// assert!(c.is_ascii());
630 ///
631 /// let c = Char::get(s, 1).unwrap();
632 /// assert!(!c.is_ascii());
633 /// ```
634 pub const fn is_ascii(&self) -> bool {
635 self.c.is_ascii()
636 }
637
638 #[inline]
639 /// Converts this type to its ASCII upper case equivalent in-place.
640 ///
641 /// ASCII letters ‘a’ to ‘z’ are mapped to 'A' to 'Z', but non-ASCII letters are unchanged.
642 ///
643 /// ```
644 /// use mut_str::Char;
645 ///
646 /// let mut s = Box::<str>::from("oφ⏣🌑");
647 ///
648 /// let c = Char::get_mut(&mut *s, 0).unwrap();
649 /// c.make_ascii_uppercase();
650 ///
651 /// let c = Char::get_mut(&mut *s, 1).unwrap();
652 /// c.make_ascii_uppercase();
653 ///
654 /// assert_eq!(&*s, "Oφ⏣🌑");
655 /// ```
656 pub fn make_ascii_uppercase(&mut self) {
657 self.c.make_ascii_uppercase();
658 }
659
660 #[inline]
661 /// Converts this type to its ASCII lower case equivalent in-place.
662 ///
663 /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', but non-ASCII letters are unchanged.
664 ///
665 /// ```
666 /// use mut_str::Char;
667 ///
668 /// let mut s = Box::<str>::from("OΦ⏣🌑");
669 ///
670 /// let c = Char::get_mut(&mut *s, 0).unwrap();
671 /// c.make_ascii_lowercase();
672 ///
673 /// let c = Char::get_mut(&mut *s, 1).unwrap();
674 /// c.make_ascii_lowercase();
675 ///
676 /// assert_eq!(&*s, "oΦ⏣🌑");
677 /// ```
678 pub fn make_ascii_lowercase(&mut self) {
679 self.c.make_ascii_lowercase();
680 }
681
682 /// Converts this type to its Unicode upper case equivalent in-place.
683 ///
684 /// ```
685 /// use mut_str::Char;
686 ///
687 /// let mut s = Box::<str>::from("oφ⏣🌑");
688 ///
689 /// let c = Char::get_mut(&mut *s, 0).unwrap();
690 /// c.try_make_uppercase().unwrap();
691 ///
692 /// let c = Char::get_mut(&mut *s, 1).unwrap();
693 /// c.try_make_uppercase().unwrap();
694 ///
695 /// assert_eq!(&*s, "OΦ⏣🌑");
696 /// ```
697 ///
698 /// # Errors
699 /// If the character and its uppercase version is not the same length when utf8 encoded, [`LenNotEqual`] will be returned.
700 pub fn try_make_uppercase(&mut self) -> Result<(), LenNotEqual> {
701 let chars = self.as_char().to_uppercase();
702
703 let mut buffer = [0; 4];
704 let mut index = 0;
705
706 let self_len = self.len();
707
708 for char in chars {
709 let len = char.len_utf8();
710 if index + len > self_len {
711 return Err(LenNotEqual);
712 }
713
714 char.encode_utf8(&mut buffer[index..]);
715 index += len;
716 }
717
718 if index != self_len {
719 return Err(LenNotEqual);
720 }
721
722 // SAFETY:
723 // Replacing the character with a valid utf8 character of the same
724 // length is valid.
725 unsafe { self.as_bytes_mut() }.copy_from_slice(&buffer[..index]);
726 Ok(())
727 }
728
729 /// Converts this type to its Unicode lower case equivalent in-place.
730 ///
731 /// ```
732 /// use mut_str::Char;
733 ///
734 /// let mut s = Box::<str>::from("OΦ⏣🌑");
735 ///
736 /// let c = Char::get_mut(&mut *s, 0).unwrap();
737 /// c.try_make_lowercase().unwrap();
738 ///
739 /// let c = Char::get_mut(&mut *s, 1).unwrap();
740 /// c.try_make_lowercase().unwrap();
741 ///
742 /// assert_eq!(&*s, "oφ⏣🌑");
743 /// ```
744 ///
745 /// # Errors
746 /// If the character and its lowercase version is not the same length when utf8 encoded, [`LenNotEqual`] will be returned.
747 pub fn try_make_lowercase(&mut self) -> Result<(), LenNotEqual> {
748 let chars = self.as_char().to_lowercase();
749
750 let mut buffer = [0; 4];
751 let mut index = 0;
752
753 let self_len = self.len();
754
755 for char in chars {
756 let len = char.len_utf8();
757 if index + len > self_len {
758 return Err(LenNotEqual);
759 }
760
761 char.encode_utf8(&mut buffer[index..]);
762 index += len;
763 }
764
765 if index != self_len {
766 return Err(LenNotEqual);
767 }
768
769 // SAFETY:
770 // Replacing the character with a valid utf8 character of the same
771 // length is valid.
772 unsafe { self.as_bytes_mut() }.copy_from_slice(&buffer[..index]);
773 Ok(())
774 }
775}
776
777impl fmt::Display for Char {
778 #[inline]
779 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
780 self.as_str().fmt(f)
781 }
782}
783
784impl fmt::Debug for Char {
785 #[inline]
786 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
787 let mut b = [b'\''; 6];
788 b[1..=self.len()].copy_from_slice(self.as_bytes());
789
790 // SAFETY:
791 // `self` is valid utf8, so when embedded in a string of single-byte
792 // utf8 characters, the resulting string will be valid.
793 let s = unsafe { str::from_utf8_unchecked(&b[..self.len() + 2]) };
794 Display::fmt(s, f)
795 }
796}
797
798impl PartialEq for Char {
799 #[inline]
800 fn eq(&self, other: &Self) -> bool {
801 self.as_bytes().eq(other.as_bytes())
802 }
803}
804
805impl PartialEq<OwnedChar> for Char {
806 #[inline]
807 fn eq(&self, other: &OwnedChar) -> bool {
808 self.eq(other.as_ref())
809 }
810}
811
812impl PartialEq<str> for Char {
813 #[inline]
814 fn eq(&self, other: &str) -> bool {
815 self.as_bytes().eq(other.as_bytes())
816 }
817}
818
819impl PartialEq<Char> for str {
820 #[inline]
821 fn eq(&self, other: &Char) -> bool {
822 self.as_bytes().eq(other.as_bytes())
823 }
824}
825
826impl PartialEq<char> for Char {
827 #[inline]
828 fn eq(&self, other: &char) -> bool {
829 self.as_char().eq(other)
830 }
831}
832
833impl PartialEq<Char> for char {
834 #[inline]
835 fn eq(&self, other: &Char) -> bool {
836 self.eq(&other.as_char())
837 }
838}
839
840impl PartialEq<char> for &Char {
841 #[inline]
842 fn eq(&self, other: &char) -> bool {
843 self.as_char().eq(other)
844 }
845}
846
847impl PartialEq<char> for &mut Char {
848 #[inline]
849 fn eq(&self, other: &char) -> bool {
850 self.as_char().eq(other)
851 }
852}
853
854impl Eq for Char {}
855
856impl Ord for Char {
857 #[inline]
858 fn cmp(&self, other: &Self) -> cmp::Ordering {
859 self.as_bytes().cmp(other.as_bytes())
860 }
861}
862
863impl PartialOrd for Char {
864 #[inline]
865 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
866 Some(self.cmp(other))
867 }
868}
869
870impl PartialOrd<OwnedChar> for Char {
871 #[inline]
872 fn partial_cmp(&self, other: &OwnedChar) -> Option<cmp::Ordering> {
873 self.partial_cmp(other.as_ref())
874 }
875}
876
877impl PartialOrd<str> for Char {
878 #[inline]
879 fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
880 Some(self.as_bytes().cmp(other.as_bytes()))
881 }
882}
883
884impl PartialOrd<Char> for str {
885 #[inline]
886 fn partial_cmp(&self, other: &Char) -> Option<cmp::Ordering> {
887 Some(self.as_bytes().cmp(other.as_bytes()))
888 }
889}
890
891impl PartialOrd<char> for Char {
892 #[inline]
893 fn partial_cmp(&self, other: &char) -> Option<cmp::Ordering> {
894 Some(self.as_char().cmp(other))
895 }
896}
897
898impl PartialOrd<Char> for char {
899 #[inline]
900 fn partial_cmp(&self, other: &Char) -> Option<cmp::Ordering> {
901 Some(self.cmp(&other.as_char()))
902 }
903}
904
905impl hash::Hash for &Char {
906 #[inline]
907 fn hash<H: hash::Hasher>(&self, state: &mut H) {
908 self.as_bytes().hash(state);
909 }
910}
911
912impl AsRef<str> for Char {
913 #[inline]
914 fn as_ref(&self) -> &str {
915 self.as_str()
916 }
917}
918
919impl AsMut<str> for Char {
920 #[inline]
921 fn as_mut(&mut self) -> &mut str {
922 self.as_str_mut()
923 }
924}
925
926impl Borrow<str> for Char {
927 #[inline]
928 fn borrow(&self) -> &str {
929 self.as_str()
930 }
931}
932
933impl BorrowMut<str> for Char {
934 #[inline]
935 fn borrow_mut(&mut self) -> &mut str {
936 self.as_str_mut()
937 }
938}
939
940#[cfg(feature = "alloc")]
941impl ToOwned for Char {
942 type Owned = OwnedChar;
943
944 #[inline]
945 fn to_owned(&self) -> Self::Owned {
946 self.as_owned()
947 }
948
949 #[inline]
950 fn clone_into(&self, target: &mut Self::Owned) {
951 let bytes = self.as_bytes();
952
953 // SAFETY:
954 // `bytes` is guaranteed to be a valid UTF-8 character. The succeeding
955 // bytes do not have to be zeroed as they will not be read.
956 unsafe { target.buffer_mut()[..bytes.len()].copy_from_slice(bytes) }
957 }
958}
959
960impl From<&Char> for char {
961 #[inline]
962 fn from(value: &Char) -> Self {
963 value.as_char()
964 }
965}
966
967impl TryFrom<&str> for &Char {
968 type Error = TryFromStrError;
969
970 #[inline]
971 fn try_from(value: &str) -> Result<Self, Self::Error> {
972 if value.is_empty() {
973 return Err(TryFromStrError::Empty);
974 }
975
976 // SAFETY:
977 // `value` is a `str` with at least one character, so its pointer must
978 // point to a valid character.
979 let c = unsafe { &*Char::new_unchecked(value.as_ptr()) };
980
981 if value.len() == c.len() {
982 Ok(c)
983 } else {
984 Err(TryFromStrError::MultipleChars)
985 }
986 }
987}
988
989impl TryFrom<&mut str> for &mut Char {
990 type Error = TryFromStrError;
991
992 #[inline]
993 fn try_from(value: &mut str) -> Result<Self, Self::Error> {
994 if value.is_empty() {
995 return Err(TryFromStrError::Empty);
996 }
997
998 // SAFETY:
999 // `value` is a `str` with at least one character, so its pointer must
1000 // point to a valid character.
1001 let c = unsafe { &mut *Char::new_unchecked_mut(value.as_mut_ptr()) };
1002
1003 if value.len() == c.len() {
1004 Ok(c)
1005 } else {
1006 Err(TryFromStrError::MultipleChars)
1007 }
1008 }
1009}
1010
1011impl FromStr for &Char {
1012 type Err = TryFromStrError;
1013
1014 #[inline]
1015 fn from_str(s: &str) -> Result<Self, Self::Err> {
1016 Self::try_from(s)
1017 }
1018}
1019
1020impl TryFrom<&[u8]> for &Char {
1021 type Error = TryFromBytesError;
1022
1023 #[inline]
1024 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
1025 if value.len() > 4 {
1026 return Err(TryFromStrError::MultipleChars.into());
1027 }
1028
1029 let s = str::from_utf8(value)?;
1030 Self::try_from(s).map_err(TryFromBytesError::Length)
1031 }
1032}
1033
1034impl TryFrom<&mut [u8]> for &mut Char {
1035 type Error = TryFromBytesError;
1036
1037 #[inline]
1038 fn try_from(value: &mut [u8]) -> Result<Self, Self::Error> {
1039 if value.len() > 4 {
1040 return Err(TryFromStrError::MultipleChars.into());
1041 }
1042
1043 let s = str::from_utf8_mut(value)?;
1044 Self::try_from(s).map_err(TryFromBytesError::Length)
1045 }
1046}
1047
1048#[cfg(test)]
1049mod test {
1050 use core::str;
1051
1052 use crate::{
1053 iter::{CharMutRefs, CharRefs},
1054 test::{test_str_owned, TEST_STR},
1055 Char,
1056 };
1057
1058 #[test]
1059 fn test_len() {
1060 for (expected_char, char) in TEST_STR.chars().zip(CharRefs::from(TEST_STR)) {
1061 assert_eq!(char.len(), expected_char.len_utf8());
1062 }
1063 }
1064
1065 #[test]
1066 fn test_get() {
1067 for (i, expected) in TEST_STR.chars().enumerate() {
1068 let actual = Char::get(TEST_STR, i).expect("expected a character reference");
1069 assert_eq!(actual.as_char(), expected);
1070 }
1071
1072 let mut s = test_str_owned();
1073
1074 for (i, expected) in TEST_STR.chars().enumerate() {
1075 let actual = Char::get_mut(&mut s, i).expect("expected a character reference");
1076 assert_eq!(actual.as_char(), expected);
1077 }
1078
1079 assert_eq!(
1080 &*s, TEST_STR,
1081 "`Char::get_mut` mutated the mutable string slice"
1082 );
1083 }
1084
1085 #[test]
1086 fn test_as() {
1087 let pr = TEST_STR.as_bytes().as_ptr_range();
1088
1089 for (c, actual) in TEST_STR.chars().zip(CharRefs::from(TEST_STR)) {
1090 assert_eq!(actual.as_char(), c);
1091
1092 let mut buffer = [0; 4];
1093
1094 let s = c.encode_utf8(&mut buffer);
1095 let len = s.len();
1096 assert_eq!(actual.as_str(), s);
1097
1098 let b = &buffer[..len];
1099 assert_eq!(actual.as_bytes(), b);
1100
1101 assert!(pr.contains(&actual.as_ptr()));
1102 }
1103
1104 let mut s = test_str_owned();
1105 let pr2 = s.as_bytes().as_ptr_range();
1106
1107 for (c, actual) in TEST_STR.chars().zip(CharMutRefs::from(&mut *s)) {
1108 assert_eq!(actual.as_char(), c);
1109
1110 let mut buffer = [0; 4];
1111
1112 let s2 = c.encode_utf8(&mut buffer);
1113 let len = s2.len();
1114 assert_eq!(actual.as_str_mut(), s2);
1115
1116 let b = &buffer[..len];
1117 // SAFETY:
1118 // Not mutating.
1119 assert_eq!(unsafe { actual.as_bytes_mut() }, b);
1120
1121 assert!(pr2.contains(&actual.as_ptr()));
1122 }
1123
1124 assert_eq!(
1125 &*s, TEST_STR,
1126 "`Char` as methods mutated the mutable string slice"
1127 );
1128 }
1129
1130 macro_rules! replace {
1131 ( ($fn:path)($c:expr $(, $arg:expr)*) <- $c2:expr, $expected:ident => $cfg:block ) => {
1132 let mut buffer = [0; 6];
1133 let s = $c2.encode_utf8(&mut buffer[1..]);
1134 let c2 = <&mut Char>::try_from(s).unwrap();
1135
1136 $fn(c2, $c $(, $arg)*).expect(concat!(stringify!($fn), " returned an error"));
1137
1138 let mut $expected = [0; 6];
1139 $cfg
1140
1141 assert_eq!(buffer, $expected, concat!(stringify!($fn), " failed a replace"));
1142 };
1143 }
1144
1145 #[test]
1146 fn test_replace() {
1147 let test_chars = ['a', 'à', 'ḁ', '🔤'];
1148
1149 for (i, c) in TEST_STR.chars().enumerate() {
1150 replace!((Char::replace)(c) <- test_chars[i], expected_buffer => {
1151 c.encode_utf8(&mut expected_buffer[1..=4]);
1152 });
1153
1154 for test_char in &test_chars[i..] {
1155 let test_char_len = test_char.len_utf8();
1156
1157 replace!(
1158 (Char::replace_with_pad_space)(c) <- test_char,
1159 expected_buffer => {
1160 let len = c.encode_utf8(&mut expected_buffer[1..]).len();
1161 expected_buffer[(len + 1)..=test_char_len].fill(b' ');
1162 }
1163 );
1164
1165 replace!(
1166 (Char::replace_with_pad)(c, b'a') <- test_char,
1167 expected_buffer => {
1168 let len = c.encode_utf8(&mut expected_buffer[1..]).len();
1169 expected_buffer[(len + 1)..=test_char_len].fill(b'a');
1170 }
1171 );
1172
1173 replace!(
1174 (Char::replace_with_pad_char)(c, 'a') <- test_char,
1175 expected_buffer => {
1176 let len = c.encode_utf8(&mut expected_buffer[1..]).len();
1177 expected_buffer[(len + 1)..=test_char_len].fill(b'a');
1178 }
1179 );
1180
1181 replace!(
1182 (Char::replace_with_pad_left_space)(c) <- test_char,
1183 expected_buffer => {
1184 let i = test_char_len + 1 - c.len_utf8();
1185 c.encode_utf8(&mut expected_buffer[i..]);
1186 expected_buffer[1..i].fill(b' ');
1187 }
1188 );
1189
1190 replace!(
1191 (Char::replace_with_pad_left)(c, b'a') <- test_char,
1192 expected_buffer => {
1193 let i = test_char_len + 1 - c.len_utf8();
1194 c.encode_utf8(&mut expected_buffer[i..]);
1195 expected_buffer[1..i].fill(b'a');
1196 }
1197 );
1198
1199 replace!(
1200 (Char::replace_with_pad_left_char)(c, 'a') <- test_char,
1201 expected_buffer => {
1202 let i = test_char_len + 1 - c.len_utf8();
1203 c.encode_utf8(&mut expected_buffer[i..]);
1204 expected_buffer[1..i].fill(b'a');
1205 }
1206 );
1207 }
1208 }
1209 }
1210
1211 #[test]
1212 fn test_eq() {
1213 for c in CharRefs::from(TEST_STR) {
1214 assert_eq!(c, c.as_str());
1215 assert_eq!(c, c.as_char());
1216
1217 {
1218 // Make sure that the character with a suffix does not equal it.
1219 let mut buffer = [b' '; 5];
1220 c.copy_to(&mut buffer).unwrap();
1221
1222 // SAFETY:
1223 // This is valid as the buffer was full of single-byte utf8
1224 // encoded characters and then had another embedded into it.
1225 let s = unsafe { str::from_utf8_unchecked(&buffer) };
1226
1227 assert_ne!(c, s);
1228 }
1229 assert_ne!(c, "b");
1230 assert_ne!(c, 'b');
1231 }
1232 }
1233}