ascii/
ascii_str.rs

1#[cfg(feature = "alloc")]
2use alloc::borrow::ToOwned;
3#[cfg(feature = "alloc")]
4use alloc::boxed::Box;
5use core::fmt;
6use core::ops::{Index, IndexMut};
7use core::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive};
8use core::slice::{self, Iter, IterMut, SliceIndex};
9#[cfg(feature = "std")]
10use std::error::Error;
11#[cfg(feature = "std")]
12use std::ffi::CStr;
13
14use ascii_char::AsciiChar;
15#[cfg(feature = "alloc")]
16use ascii_string::AsciiString;
17
18/// [`AsciiStr`] represents a byte or string slice that only contains ASCII characters.
19///
20/// It wraps an `[AsciiChar]` and implements many of `str`s methods and traits.
21///
22/// It can be created by a checked conversion from a `str` or `[u8]`, or borrowed from an
23/// `AsciiString`.
24#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
25#[repr(transparent)]
26pub struct AsciiStr {
27    slice: [AsciiChar],
28}
29
30impl AsciiStr {
31    /// Converts `&self` to a `&str` slice.
32    #[inline]
33    #[must_use]
34    pub fn as_str(&self) -> &str {
35        // SAFETY: All variants of `AsciiChar` are valid bytes for a `str`.
36        unsafe { &*(self as *const AsciiStr as *const str) }
37    }
38
39    /// Converts `&self` into a byte slice.
40    #[inline]
41    #[must_use]
42    pub fn as_bytes(&self) -> &[u8] {
43        // SAFETY: All variants of `AsciiChar` are valid `u8`, given they're `repr(u8)`.
44        unsafe { &*(self as *const AsciiStr as *const [u8]) }
45    }
46
47    /// Returns the entire string as slice of `AsciiChar`s.
48    #[inline]
49    #[must_use]
50    pub const fn as_slice(&self) -> &[AsciiChar] {
51        &self.slice
52    }
53
54    /// Returns the entire string as mutable slice of `AsciiChar`s.
55    #[inline]
56    #[must_use]
57    pub fn as_mut_slice(&mut self) -> &mut [AsciiChar] {
58        &mut self.slice
59    }
60
61    /// Returns a raw pointer to the `AsciiStr`'s buffer.
62    ///
63    /// The caller must ensure that the slice outlives the pointer this function returns, or else it
64    /// will end up pointing to garbage. Modifying the `AsciiStr` may cause it's buffer to be
65    /// reallocated, which would also make any pointers to it invalid.
66    #[inline]
67    #[must_use]
68    pub const fn as_ptr(&self) -> *const AsciiChar {
69        self.as_slice().as_ptr()
70    }
71
72    /// Returns an unsafe mutable pointer to the `AsciiStr`'s buffer.
73    ///
74    /// The caller must ensure that the slice outlives the pointer this function returns, or else it
75    /// will end up pointing to garbage. Modifying the `AsciiStr` may cause it's buffer to be
76    /// reallocated, which would also make any pointers to it invalid.
77    #[inline]
78    #[must_use]
79    pub fn as_mut_ptr(&mut self) -> *mut AsciiChar {
80        self.as_mut_slice().as_mut_ptr()
81    }
82
83    /// Copies the content of this `AsciiStr` into an owned `AsciiString`.
84    #[cfg(feature = "alloc")]
85    #[must_use]
86    pub fn to_ascii_string(&self) -> AsciiString {
87        AsciiString::from(self.slice.to_vec())
88    }
89
90    /// Converts anything that can represent a byte slice into an `AsciiStr`.
91    ///
92    /// # Errors
93    /// If `bytes` contains a non-ascii byte, `Err` will be returned
94    ///
95    /// # Examples
96    /// ```
97    /// # use ascii::AsciiStr;
98    /// let foo = AsciiStr::from_ascii(b"foo");
99    /// let err = AsciiStr::from_ascii("Ŋ");
100    /// assert_eq!(foo.unwrap().as_str(), "foo");
101    /// assert_eq!(err.unwrap_err().valid_up_to(), 0);
102    /// ```
103    #[inline]
104    pub fn from_ascii<B>(bytes: &B) -> Result<&AsciiStr, AsAsciiStrError>
105    where
106        B: AsRef<[u8]> + ?Sized,
107    {
108        bytes.as_ref().as_ascii_str()
109    }
110
111    /// Converts anything that can be represented as a byte slice to an `AsciiStr` without checking
112    /// for non-ASCII characters..
113    ///
114    /// # Safety
115    /// If any of the bytes in `bytes` do not represent valid ascii characters, calling
116    /// this function is undefined behavior.
117    ///
118    /// # Examples
119    /// ```
120    /// # use ascii::AsciiStr;
121    /// let foo = unsafe { AsciiStr::from_ascii_unchecked(&b"foo"[..]) };
122    /// assert_eq!(foo.as_str(), "foo");
123    /// ```
124    #[inline]
125    #[must_use]
126    pub unsafe fn from_ascii_unchecked(bytes: &[u8]) -> &AsciiStr {
127        // SAFETY: Caller guarantees all bytes in `bytes` are valid
128        //         ascii characters.
129        unsafe { bytes.as_ascii_str_unchecked() }
130    }
131
132    /// Returns the number of characters / bytes in this ASCII sequence.
133    ///
134    /// # Examples
135    /// ```
136    /// # use ascii::AsciiStr;
137    /// let s = AsciiStr::from_ascii("foo").unwrap();
138    /// assert_eq!(s.len(), 3);
139    /// ```
140    #[inline]
141    #[must_use]
142    pub const fn len(&self) -> usize {
143        self.slice.len()
144    }
145
146    /// Returns true if the ASCII slice contains zero bytes.
147    ///
148    /// # Examples
149    /// ```
150    /// # use ascii::AsciiStr;
151    /// let mut empty = AsciiStr::from_ascii("").unwrap();
152    /// let mut full = AsciiStr::from_ascii("foo").unwrap();
153    /// assert!(empty.is_empty());
154    /// assert!(!full.is_empty());
155    /// ```
156    #[inline]
157    #[must_use]
158    pub const fn is_empty(&self) -> bool {
159        self.len() == 0
160    }
161
162    /// Returns an iterator over the characters of the `AsciiStr`.
163    #[inline]
164    #[must_use]
165    pub fn chars(&self) -> Chars {
166        Chars(self.slice.iter())
167    }
168
169    /// Returns an iterator over the characters of the `AsciiStr` which allows you to modify the
170    /// value of each `AsciiChar`.
171    #[inline]
172    #[must_use]
173    pub fn chars_mut(&mut self) -> CharsMut {
174        CharsMut(self.slice.iter_mut())
175    }
176
177    /// Returns an iterator over parts of the `AsciiStr` separated by a character.
178    ///
179    /// # Examples
180    /// ```
181    /// # use ascii::{AsciiStr, AsciiChar};
182    /// let words = AsciiStr::from_ascii("apple banana lemon").unwrap()
183    ///     .split(AsciiChar::Space)
184    ///     .map(|a| a.as_str())
185    ///     .collect::<Vec<_>>();
186    /// assert_eq!(words, ["apple", "banana", "lemon"]);
187    /// ```
188    #[must_use]
189    pub fn split(&self, on: AsciiChar) -> impl DoubleEndedIterator<Item = &AsciiStr> {
190        Split {
191            on,
192            ended: false,
193            chars: self.chars(),
194        }
195    }
196
197    /// Returns an iterator over the lines of the `AsciiStr`, which are themselves `AsciiStr`s.
198    ///
199    /// Lines are ended with either `LineFeed` (`\n`), or `CarriageReturn` then `LineFeed` (`\r\n`).
200    ///
201    /// The final line ending is optional.
202    #[inline]
203    #[must_use]
204    pub fn lines(&self) -> impl DoubleEndedIterator<Item = &AsciiStr> {
205        Lines { string: self }
206    }
207
208    /// Returns an ASCII string slice with leading and trailing whitespace removed.
209    ///
210    /// # Examples
211    /// ```
212    /// # use ascii::AsciiStr;
213    /// let example = AsciiStr::from_ascii("  \twhite \tspace  \t").unwrap();
214    /// assert_eq!("white \tspace", example.trim());
215    /// ```
216    #[must_use]
217    pub fn trim(&self) -> &Self {
218        self.trim_start().trim_end()
219    }
220
221    /// Returns an ASCII string slice with leading whitespace removed.
222    ///
223    /// # Examples
224    /// ```
225    /// # use ascii::AsciiStr;
226    /// let example = AsciiStr::from_ascii("  \twhite \tspace  \t").unwrap();
227    /// assert_eq!("white \tspace  \t", example.trim_start());
228    /// ```
229    #[must_use]
230    pub fn trim_start(&self) -> &Self {
231        let whitespace_len = self
232            .chars()
233            .position(|ch| !ch.is_whitespace())
234            .unwrap_or_else(|| self.len());
235
236        // SAFETY: `whitespace_len` is `0..=len`, which is at most `len`, which is a valid empty slice.
237        unsafe { self.as_slice().get_unchecked(whitespace_len..).into() }
238    }
239
240    /// Returns an ASCII string slice with trailing whitespace removed.
241    ///
242    /// # Examples
243    /// ```
244    /// # use ascii::AsciiStr;
245    /// let example = AsciiStr::from_ascii("  \twhite \tspace  \t").unwrap();
246    /// assert_eq!("  \twhite \tspace", example.trim_end());
247    /// ```
248    #[must_use]
249    pub fn trim_end(&self) -> &Self {
250        // Number of whitespace characters counting from the end
251        let whitespace_len = self
252            .chars()
253            .rev()
254            .position(|ch| !ch.is_whitespace())
255            .unwrap_or_else(|| self.len());
256
257        // SAFETY: `whitespace_len` is `0..=len`, which is at most `len`, which is a valid empty slice, and at least `0`, which is the whole slice.
258        unsafe {
259            self.as_slice()
260                .get_unchecked(..self.len() - whitespace_len)
261                .into()
262        }
263    }
264
265    /// Compares two strings case-insensitively.
266    #[must_use]
267    pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
268        self.len() == other.len()
269            && self
270                .chars()
271                .zip(other.chars())
272                .all(|(ch, other_ch)| ch.eq_ignore_ascii_case(&other_ch))
273    }
274
275    /// Replaces lowercase letters with their uppercase equivalent.
276    pub fn make_ascii_uppercase(&mut self) {
277        for ch in self.chars_mut() {
278            *ch = ch.to_ascii_uppercase();
279        }
280    }
281
282    /// Replaces uppercase letters with their lowercase equivalent.
283    pub fn make_ascii_lowercase(&mut self) {
284        for ch in self.chars_mut() {
285            *ch = ch.to_ascii_lowercase();
286        }
287    }
288
289    /// Returns a copy of this string where letters 'a' to 'z' are mapped to 'A' to 'Z'.
290    #[cfg(feature = "alloc")]
291    #[must_use]
292    pub fn to_ascii_uppercase(&self) -> AsciiString {
293        let mut ascii_string = self.to_ascii_string();
294        ascii_string.make_ascii_uppercase();
295        ascii_string
296    }
297
298    /// Returns a copy of this string where letters 'A' to 'Z' are mapped to 'a' to 'z'.
299    #[cfg(feature = "alloc")]
300    #[must_use]
301    pub fn to_ascii_lowercase(&self) -> AsciiString {
302        let mut ascii_string = self.to_ascii_string();
303        ascii_string.make_ascii_lowercase();
304        ascii_string
305    }
306
307    /// Returns the first character if the string is not empty.
308    #[inline]
309    #[must_use]
310    pub fn first(&self) -> Option<AsciiChar> {
311        self.slice.first().copied()
312    }
313
314    /// Returns the last character if the string is not empty.
315    #[inline]
316    #[must_use]
317    pub fn last(&self) -> Option<AsciiChar> {
318        self.slice.last().copied()
319    }
320
321    /// Converts a [`Box<AsciiStr>`] into a [`AsciiString`] without copying or allocating.
322    #[cfg(feature = "alloc")]
323    #[inline]
324    #[must_use]
325    pub fn into_ascii_string(self: Box<Self>) -> AsciiString {
326        let slice = Box::<[AsciiChar]>::from(self);
327        AsciiString::from(slice.into_vec())
328    }
329}
330
331macro_rules! impl_partial_eq {
332    ($wider: ty) => {
333        impl PartialEq<$wider> for AsciiStr {
334            #[inline]
335            fn eq(&self, other: &$wider) -> bool {
336                <AsciiStr as AsRef<$wider>>::as_ref(self) == other
337            }
338        }
339        impl PartialEq<AsciiStr> for $wider {
340            #[inline]
341            fn eq(&self, other: &AsciiStr) -> bool {
342                self == <AsciiStr as AsRef<$wider>>::as_ref(other)
343            }
344        }
345    };
346}
347
348impl_partial_eq! {str}
349impl_partial_eq! {[u8]}
350impl_partial_eq! {[AsciiChar]}
351
352#[cfg(feature = "alloc")]
353impl ToOwned for AsciiStr {
354    type Owned = AsciiString;
355
356    #[inline]
357    fn to_owned(&self) -> AsciiString {
358        self.to_ascii_string()
359    }
360}
361
362impl AsRef<[u8]> for AsciiStr {
363    #[inline]
364    fn as_ref(&self) -> &[u8] {
365        self.as_bytes()
366    }
367}
368impl AsRef<str> for AsciiStr {
369    #[inline]
370    fn as_ref(&self) -> &str {
371        self.as_str()
372    }
373}
374impl AsRef<[AsciiChar]> for AsciiStr {
375    #[inline]
376    fn as_ref(&self) -> &[AsciiChar] {
377        &self.slice
378    }
379}
380impl AsMut<[AsciiChar]> for AsciiStr {
381    #[inline]
382    fn as_mut(&mut self) -> &mut [AsciiChar] {
383        &mut self.slice
384    }
385}
386
387impl Default for &'static AsciiStr {
388    #[inline]
389    fn default() -> &'static AsciiStr {
390        From::from(&[] as &[AsciiChar])
391    }
392}
393impl<'a> From<&'a [AsciiChar]> for &'a AsciiStr {
394    #[inline]
395    fn from(slice: &[AsciiChar]) -> &AsciiStr {
396        let ptr = slice as *const [AsciiChar] as *const AsciiStr;
397        unsafe { &*ptr }
398    }
399}
400impl<'a> From<&'a mut [AsciiChar]> for &'a mut AsciiStr {
401    #[inline]
402    fn from(slice: &mut [AsciiChar]) -> &mut AsciiStr {
403        let ptr = slice as *mut [AsciiChar] as *mut AsciiStr;
404        unsafe { &mut *ptr }
405    }
406}
407#[cfg(feature = "alloc")]
408impl From<Box<[AsciiChar]>> for Box<AsciiStr> {
409    #[inline]
410    fn from(owned: Box<[AsciiChar]>) -> Box<AsciiStr> {
411        let ptr = Box::into_raw(owned) as *mut AsciiStr;
412        unsafe { Box::from_raw(ptr) }
413    }
414}
415
416impl AsRef<AsciiStr> for AsciiStr {
417    #[inline]
418    fn as_ref(&self) -> &AsciiStr {
419        self
420    }
421}
422impl AsMut<AsciiStr> for AsciiStr {
423    #[inline]
424    fn as_mut(&mut self) -> &mut AsciiStr {
425        self
426    }
427}
428impl AsRef<AsciiStr> for [AsciiChar] {
429    #[inline]
430    fn as_ref(&self) -> &AsciiStr {
431        self.into()
432    }
433}
434impl AsMut<AsciiStr> for [AsciiChar] {
435    #[inline]
436    fn as_mut(&mut self) -> &mut AsciiStr {
437        self.into()
438    }
439}
440
441impl<'a> From<&'a AsciiStr> for &'a [AsciiChar] {
442    #[inline]
443    fn from(astr: &AsciiStr) -> &[AsciiChar] {
444        &astr.slice
445    }
446}
447impl<'a> From<&'a mut AsciiStr> for &'a mut [AsciiChar] {
448    #[inline]
449    fn from(astr: &mut AsciiStr) -> &mut [AsciiChar] {
450        &mut astr.slice
451    }
452}
453impl<'a> From<&'a AsciiStr> for &'a [u8] {
454    #[inline]
455    fn from(astr: &AsciiStr) -> &[u8] {
456        astr.as_bytes()
457    }
458}
459impl<'a> From<&'a AsciiStr> for &'a str {
460    #[inline]
461    fn from(astr: &AsciiStr) -> &str {
462        astr.as_str()
463    }
464}
465macro_rules! widen_box {
466    ($wider: ty) => {
467        #[cfg(feature = "alloc")]
468        impl From<Box<AsciiStr>> for Box<$wider> {
469            #[inline]
470            fn from(owned: Box<AsciiStr>) -> Box<$wider> {
471                let ptr = Box::into_raw(owned) as *mut $wider;
472                unsafe { Box::from_raw(ptr) }
473            }
474        }
475    };
476}
477widen_box! {[AsciiChar]}
478widen_box! {[u8]}
479widen_box! {str}
480
481// allows &AsciiChar to be used by generic AsciiString Extend and FromIterator
482impl AsRef<AsciiStr> for AsciiChar {
483    fn as_ref(&self) -> &AsciiStr {
484        slice::from_ref(self).into()
485    }
486}
487
488impl fmt::Display for AsciiStr {
489    #[inline]
490    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
491        fmt::Display::fmt(self.as_str(), f)
492    }
493}
494
495impl fmt::Debug for AsciiStr {
496    #[inline]
497    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
498        fmt::Debug::fmt(self.as_str(), f)
499    }
500}
501
502macro_rules! impl_index {
503    ($idx:ty) => {
504        #[allow(clippy::indexing_slicing)] // In `Index`, if it's out of bounds, panic is the default
505        impl Index<$idx> for AsciiStr {
506            type Output = AsciiStr;
507
508            #[inline]
509            fn index(&self, index: $idx) -> &AsciiStr {
510                self.slice[index].as_ref()
511            }
512        }
513
514        #[allow(clippy::indexing_slicing)] // In `IndexMut`, if it's out of bounds, panic is the default
515        impl IndexMut<$idx> for AsciiStr {
516            #[inline]
517            fn index_mut(&mut self, index: $idx) -> &mut AsciiStr {
518                self.slice[index].as_mut()
519            }
520        }
521    };
522}
523
524impl_index! { Range<usize> }
525impl_index! { RangeTo<usize> }
526impl_index! { RangeFrom<usize> }
527impl_index! { RangeFull }
528impl_index! { RangeInclusive<usize> }
529impl_index! { RangeToInclusive<usize> }
530
531#[allow(clippy::indexing_slicing)] // In `Index`, if it's out of bounds, panic is the default
532impl Index<usize> for AsciiStr {
533    type Output = AsciiChar;
534
535    #[inline]
536    fn index(&self, index: usize) -> &AsciiChar {
537        &self.slice[index]
538    }
539}
540
541#[allow(clippy::indexing_slicing)] // In `IndexMut`, if it's out of bounds, panic is the default
542impl IndexMut<usize> for AsciiStr {
543    #[inline]
544    fn index_mut(&mut self, index: usize) -> &mut AsciiChar {
545        &mut self.slice[index]
546    }
547}
548
549/// Produces references for compatibility with `[u8]`.
550///
551/// (`str` doesn't implement `IntoIterator` for its references,
552///  so there is no compatibility to lose.)
553impl<'a> IntoIterator for &'a AsciiStr {
554    type Item = &'a AsciiChar;
555    type IntoIter = CharsRef<'a>;
556    #[inline]
557    fn into_iter(self) -> Self::IntoIter {
558        CharsRef(self.as_slice().iter())
559    }
560}
561
562impl<'a> IntoIterator for &'a mut AsciiStr {
563    type Item = &'a mut AsciiChar;
564    type IntoIter = CharsMut<'a>;
565    #[inline]
566    fn into_iter(self) -> Self::IntoIter {
567        self.chars_mut()
568    }
569}
570
571/// A copying iterator over the characters of an `AsciiStr`.
572#[derive(Clone, Debug)]
573pub struct Chars<'a>(Iter<'a, AsciiChar>);
574impl<'a> Chars<'a> {
575    /// Returns the ascii string slice with the remaining characters.
576    #[must_use]
577    pub fn as_str(&self) -> &'a AsciiStr {
578        self.0.as_slice().into()
579    }
580}
581impl<'a> Iterator for Chars<'a> {
582    type Item = AsciiChar;
583    #[inline]
584    fn next(&mut self) -> Option<AsciiChar> {
585        self.0.next().copied()
586    }
587    fn size_hint(&self) -> (usize, Option<usize>) {
588        self.0.size_hint()
589    }
590}
591impl<'a> DoubleEndedIterator for Chars<'a> {
592    #[inline]
593    fn next_back(&mut self) -> Option<AsciiChar> {
594        self.0.next_back().copied()
595    }
596}
597impl<'a> ExactSizeIterator for Chars<'a> {
598    fn len(&self) -> usize {
599        self.0.len()
600    }
601}
602
603/// A mutable iterator over the characters of an `AsciiStr`.
604#[derive(Debug)]
605pub struct CharsMut<'a>(IterMut<'a, AsciiChar>);
606impl<'a> CharsMut<'a> {
607    /// Returns the ascii string slice with the remaining characters.
608    #[must_use]
609    pub fn into_str(self) -> &'a mut AsciiStr {
610        self.0.into_slice().into()
611    }
612}
613impl<'a> Iterator for CharsMut<'a> {
614    type Item = &'a mut AsciiChar;
615    #[inline]
616    fn next(&mut self) -> Option<&'a mut AsciiChar> {
617        self.0.next()
618    }
619    fn size_hint(&self) -> (usize, Option<usize>) {
620        self.0.size_hint()
621    }
622}
623impl<'a> DoubleEndedIterator for CharsMut<'a> {
624    #[inline]
625    fn next_back(&mut self) -> Option<&'a mut AsciiChar> {
626        self.0.next_back()
627    }
628}
629impl<'a> ExactSizeIterator for CharsMut<'a> {
630    fn len(&self) -> usize {
631        self.0.len()
632    }
633}
634
635/// An immutable iterator over the characters of an `AsciiStr`.
636#[derive(Clone, Debug)]
637pub struct CharsRef<'a>(Iter<'a, AsciiChar>);
638impl<'a> CharsRef<'a> {
639    /// Returns the ascii string slice with the remaining characters.
640    #[must_use]
641    pub fn as_str(&self) -> &'a AsciiStr {
642        self.0.as_slice().into()
643    }
644}
645impl<'a> Iterator for CharsRef<'a> {
646    type Item = &'a AsciiChar;
647    #[inline]
648    fn next(&mut self) -> Option<&'a AsciiChar> {
649        self.0.next()
650    }
651    fn size_hint(&self) -> (usize, Option<usize>) {
652        self.0.size_hint()
653    }
654}
655impl<'a> DoubleEndedIterator for CharsRef<'a> {
656    #[inline]
657    fn next_back(&mut self) -> Option<&'a AsciiChar> {
658        self.0.next_back()
659    }
660}
661
662/// An iterator over parts of an `AsciiStr` separated by an `AsciiChar`.
663///
664/// This type is created by [`AsciiChar::split()`](struct.AsciiChar.html#method.split).
665#[derive(Clone, Debug)]
666struct Split<'a> {
667    on: AsciiChar,
668    ended: bool,
669    chars: Chars<'a>,
670}
671impl<'a> Iterator for Split<'a> {
672    type Item = &'a AsciiStr;
673
674    fn next(&mut self) -> Option<&'a AsciiStr> {
675        if !self.ended {
676            let start: &AsciiStr = self.chars.as_str();
677            let split_on = self.on;
678
679            if let Some(at) = self.chars.position(|ch| ch == split_on) {
680                // SAFETY: `at` is guaranteed to be in bounds, as `position` returns `Ok(0..len)`.
681                Some(unsafe { start.as_slice().get_unchecked(..at).into() })
682            } else {
683                self.ended = true;
684                Some(start)
685            }
686        } else {
687            None
688        }
689    }
690}
691impl<'a> DoubleEndedIterator for Split<'a> {
692    fn next_back(&mut self) -> Option<&'a AsciiStr> {
693        if !self.ended {
694            let start: &AsciiStr = self.chars.as_str();
695            let split_on = self.on;
696
697            if let Some(at) = self.chars.rposition(|ch| ch == split_on) {
698                // SAFETY: `at` is guaranteed to be in bounds, as `rposition` returns `Ok(0..len)`, and slices `1..`, `2..`, etc... until `len..` inclusive, are valid.
699                Some(unsafe { start.as_slice().get_unchecked(at + 1..).into() })
700            } else {
701                self.ended = true;
702                Some(start)
703            }
704        } else {
705            None
706        }
707    }
708}
709
710/// An iterator over the lines of the internal character array.
711#[derive(Clone, Debug)]
712struct Lines<'a> {
713    string: &'a AsciiStr,
714}
715impl<'a> Iterator for Lines<'a> {
716    type Item = &'a AsciiStr;
717
718    fn next(&mut self) -> Option<&'a AsciiStr> {
719        if let Some(idx) = self
720            .string
721            .chars()
722            .position(|chr| chr == AsciiChar::LineFeed)
723        {
724            // SAFETY: `idx` is guaranteed to be `1..len`, as we get it from `position` as `0..len` and make sure it's not `0`.
725            let line = if idx > 0
726                && *unsafe { self.string.as_slice().get_unchecked(idx - 1) }
727                    == AsciiChar::CarriageReturn
728            {
729                // SAFETY: As per above, `idx` is guaranteed to be `1..len`
730                unsafe { self.string.as_slice().get_unchecked(..idx - 1).into() }
731            } else {
732                // SAFETY: As per above, `idx` is guaranteed to be `0..len`
733                unsafe { self.string.as_slice().get_unchecked(..idx).into() }
734            };
735            // SAFETY: As per above, `idx` is guaranteed to be `0..len`, so at the extreme, slicing `len..` is a valid empty slice.
736            self.string = unsafe { self.string.as_slice().get_unchecked(idx + 1..).into() };
737            Some(line)
738        } else if self.string.is_empty() {
739            None
740        } else {
741            let line = self.string;
742            // SAFETY: An empty string is a valid string.
743            self.string = unsafe { AsciiStr::from_ascii_unchecked(b"") };
744            Some(line)
745        }
746    }
747}
748
749impl<'a> DoubleEndedIterator for Lines<'a> {
750    fn next_back(&mut self) -> Option<&'a AsciiStr> {
751        if self.string.is_empty() {
752            return None;
753        }
754
755        // If we end with `LF` / `CR/LF`, remove them
756        if let Some(AsciiChar::LineFeed) = self.string.last() {
757            // SAFETY: `last()` returned `Some`, so our len is at least 1.
758            self.string = unsafe {
759                self.string
760                    .as_slice()
761                    .get_unchecked(..self.string.len() - 1)
762                    .into()
763            };
764
765            if let Some(AsciiChar::CarriageReturn) = self.string.last() {
766                // SAFETY: `last()` returned `Some`, so our len is at least 1.
767                self.string = unsafe {
768                    self.string
769                        .as_slice()
770                        .get_unchecked(..self.string.len() - 1)
771                        .into()
772                };
773            }
774        }
775
776        // Get the position of the first `LF` from the end.
777        let lf_rev_pos = self
778            .string
779            .chars()
780            .rev()
781            .position(|ch| ch == AsciiChar::LineFeed)
782            .unwrap_or_else(|| self.string.len());
783
784        // SAFETY: `lf_rev_pos` will be in range `0..=len`, so `len - lf_rev_pos`
785        //         will be within `0..=len`, making it correct as a start and end
786        //         point for the strings.
787        let line = unsafe {
788            self.string
789                .as_slice()
790                .get_unchecked(self.string.len() - lf_rev_pos..)
791                .into()
792        };
793        self.string = unsafe {
794            self.string
795                .as_slice()
796                .get_unchecked(..self.string.len() - lf_rev_pos)
797                .into()
798        };
799        Some(line)
800    }
801}
802
803/// Error that is returned when a sequence of `u8` are not all ASCII.
804///
805/// Is used by `As[Mut]AsciiStr` and the `from_ascii` method on `AsciiStr` and `AsciiString`.
806#[derive(Clone, Copy, PartialEq, Eq, Debug)]
807pub struct AsAsciiStrError(usize);
808
809const ERRORMSG_STR: &str = "one or more bytes are not ASCII";
810
811impl AsAsciiStrError {
812    /// Returns the index of the first non-ASCII byte.
813    ///
814    /// It is the maximum index such that `from_ascii(input[..index])` would return `Ok(_)`.
815    #[inline]
816    #[must_use]
817    pub const fn valid_up_to(self) -> usize {
818        self.0
819    }
820    #[cfg(not(feature = "std"))]
821    /// Returns a description for this error, like `std::error::Error::description`.
822    #[inline]
823    #[must_use]
824    #[allow(clippy::unused_self)]
825    pub const fn description(&self) -> &'static str {
826        ERRORMSG_STR
827    }
828}
829impl fmt::Display for AsAsciiStrError {
830    fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
831        write!(fmtr, "the byte at index {} is not ASCII", self.0)
832    }
833}
834#[cfg(feature = "std")]
835impl Error for AsAsciiStrError {
836    #[inline]
837    fn description(&self) -> &'static str {
838        ERRORMSG_STR
839    }
840}
841
842/// Convert slices of bytes or [`AsciiChar`] to [`AsciiStr`].
843// Could nearly replace this trait with SliceIndex, but its methods isn't even
844// on a path for stabilization.
845pub trait AsAsciiStr {
846    /// Used to constrain `SliceIndex`
847    #[doc(hidden)]
848    type Inner;
849    /// Convert a subslice to an ASCII slice.
850    ///
851    /// # Errors
852    /// Returns `Err` if the range is out of bounds or if not all bytes in the
853    /// slice are ASCII. The value in the error will be the index of the first
854    /// non-ASCII byte or the end of the slice.
855    ///
856    /// # Examples
857    /// ```
858    /// use ascii::AsAsciiStr;
859    /// assert!("'zoä'".slice_ascii(..3).is_ok());
860    /// assert!("'zoä'".slice_ascii(0..4).is_err());
861    /// assert!("'zoä'".slice_ascii(5..=5).is_ok());
862    /// assert!("'zoä'".slice_ascii(4..).is_err());
863    /// assert!(b"\r\n".slice_ascii(..).is_ok());
864    /// ```
865    fn slice_ascii<R>(&self, range: R) -> Result<&AsciiStr, AsAsciiStrError>
866    where
867        R: SliceIndex<[Self::Inner], Output = [Self::Inner]>;
868    /// Convert to an ASCII slice.
869    ///
870    /// # Errors
871    /// Returns `Err` if not all bytes are valid ascii values.
872    ///
873    /// # Example
874    /// ```
875    /// use ascii::{AsAsciiStr, AsciiChar};
876    /// assert!("ASCII".as_ascii_str().is_ok());
877    /// assert!(b"\r\n".as_ascii_str().is_ok());
878    /// assert!("'zoä'".as_ascii_str().is_err());
879    /// assert!(b"\xff".as_ascii_str().is_err());
880    /// assert!([AsciiChar::C][..].as_ascii_str().is_ok()); // infallible
881    /// ```
882    fn as_ascii_str(&self) -> Result<&AsciiStr, AsAsciiStrError> {
883        self.slice_ascii(..)
884    }
885    /// Get a single ASCII character from the slice.
886    ///
887    /// Returns `None` if the index is out of bounds or the byte is not ASCII.
888    ///
889    /// # Examples
890    /// ```
891    /// use ascii::{AsAsciiStr, AsciiChar};
892    /// assert_eq!("'zoä'".get_ascii(4), None);
893    /// assert_eq!("'zoä'".get_ascii(5), Some(AsciiChar::Apostrophe));
894    /// assert_eq!("'zoä'".get_ascii(6), None);
895    /// ```
896    fn get_ascii(&self, index: usize) -> Option<AsciiChar> {
897        self.slice_ascii(index..=index)
898            .ok()
899            .and_then(AsciiStr::first)
900    }
901    /// Convert to an ASCII slice without checking for non-ASCII characters.
902    ///
903    /// # Safety
904    /// Calling this function when `self` contains non-ascii characters is
905    /// undefined behavior.
906    ///
907    /// # Examples
908    ///
909    unsafe fn as_ascii_str_unchecked(&self) -> &AsciiStr;
910}
911
912/// Convert mutable slices of bytes or [`AsciiChar`] to [`AsciiStr`].
913pub trait AsMutAsciiStr: AsAsciiStr {
914    /// Convert a subslice to an ASCII slice.
915    ///
916    /// # Errors
917    /// This function returns `Err` if range is out of bounds, or if
918    /// `self` contains non-ascii values
919    fn slice_ascii_mut<R>(&mut self, range: R) -> Result<&mut AsciiStr, AsAsciiStrError>
920    where
921        R: SliceIndex<[Self::Inner], Output = [Self::Inner]>;
922
923    /// Convert to a mutable ASCII slice.
924    ///
925    /// # Errors
926    /// This function returns `Err` if `self` contains non-ascii values
927    fn as_mut_ascii_str(&mut self) -> Result<&mut AsciiStr, AsAsciiStrError> {
928        self.slice_ascii_mut(..)
929    }
930
931    /// Convert to a mutable ASCII slice without checking for non-ASCII characters.
932    ///
933    /// # Safety
934    /// Calling this function when `self` contains non-ascii characters is
935    /// undefined behavior.
936    unsafe fn as_mut_ascii_str_unchecked(&mut self) -> &mut AsciiStr;
937}
938
939// These generic implementations mirror the generic implementations for AsRef<T> in core.
940impl<'a, T> AsAsciiStr for &'a T
941where
942    T: AsAsciiStr + ?Sized,
943{
944    type Inner = <T as AsAsciiStr>::Inner;
945    fn slice_ascii<R>(&self, range: R) -> Result<&AsciiStr, AsAsciiStrError>
946    where
947        R: SliceIndex<[Self::Inner], Output = [Self::Inner]>,
948    {
949        <T as AsAsciiStr>::slice_ascii(*self, range)
950    }
951
952    unsafe fn as_ascii_str_unchecked(&self) -> &AsciiStr {
953        // SAFETY: Caller guarantees `self` does not contain non-ascii characters
954        unsafe { <T as AsAsciiStr>::as_ascii_str_unchecked(*self) }
955    }
956}
957
958impl<'a, T> AsAsciiStr for &'a mut T
959where
960    T: AsAsciiStr + ?Sized,
961{
962    type Inner = <T as AsAsciiStr>::Inner;
963    fn slice_ascii<R>(&self, range: R) -> Result<&AsciiStr, AsAsciiStrError>
964    where
965        R: SliceIndex<[Self::Inner], Output = [Self::Inner]>,
966    {
967        <T as AsAsciiStr>::slice_ascii(*self, range)
968    }
969
970    unsafe fn as_ascii_str_unchecked(&self) -> &AsciiStr {
971        // SAFETY: Caller guarantees `self` does not contain non-ascii characters
972        unsafe { <T as AsAsciiStr>::as_ascii_str_unchecked(*self) }
973    }
974}
975
976impl<'a, T> AsMutAsciiStr for &'a mut T
977where
978    T: AsMutAsciiStr + ?Sized,
979{
980    fn slice_ascii_mut<R>(&mut self, range: R) -> Result<&mut AsciiStr, AsAsciiStrError>
981    where
982        R: SliceIndex<[Self::Inner], Output = [Self::Inner]>,
983    {
984        <T as AsMutAsciiStr>::slice_ascii_mut(*self, range)
985    }
986
987    unsafe fn as_mut_ascii_str_unchecked(&mut self) -> &mut AsciiStr {
988        // SAFETY: Caller guarantees `self` does not contain non-ascii characters
989        unsafe { <T as AsMutAsciiStr>::as_mut_ascii_str_unchecked(*self) }
990    }
991}
992
993impl AsAsciiStr for AsciiStr {
994    type Inner = AsciiChar;
995
996    fn slice_ascii<R>(&self, range: R) -> Result<&AsciiStr, AsAsciiStrError>
997    where
998        R: SliceIndex<[AsciiChar], Output = [AsciiChar]>,
999    {
1000        self.slice.slice_ascii(range)
1001    }
1002
1003    #[inline]
1004    fn as_ascii_str(&self) -> Result<&AsciiStr, AsAsciiStrError> {
1005        Ok(self)
1006    }
1007
1008    #[inline]
1009    unsafe fn as_ascii_str_unchecked(&self) -> &AsciiStr {
1010        self
1011    }
1012
1013    #[inline]
1014    fn get_ascii(&self, index: usize) -> Option<AsciiChar> {
1015        self.slice.get_ascii(index)
1016    }
1017}
1018impl AsMutAsciiStr for AsciiStr {
1019    fn slice_ascii_mut<R>(&mut self, range: R) -> Result<&mut AsciiStr, AsAsciiStrError>
1020    where
1021        R: SliceIndex<[AsciiChar], Output = [AsciiChar]>,
1022    {
1023        self.slice.slice_ascii_mut(range)
1024    }
1025
1026    #[inline]
1027    unsafe fn as_mut_ascii_str_unchecked(&mut self) -> &mut AsciiStr {
1028        self
1029    }
1030}
1031
1032impl AsAsciiStr for [AsciiChar] {
1033    type Inner = AsciiChar;
1034    fn slice_ascii<R>(&self, range: R) -> Result<&AsciiStr, AsAsciiStrError>
1035    where
1036        R: SliceIndex<[AsciiChar], Output = [AsciiChar]>,
1037    {
1038        match self.get(range) {
1039            Some(slice) => Ok(slice.into()),
1040            None => Err(AsAsciiStrError(self.len())),
1041        }
1042    }
1043
1044    #[inline]
1045    fn as_ascii_str(&self) -> Result<&AsciiStr, AsAsciiStrError> {
1046        Ok(self.into())
1047    }
1048
1049    #[inline]
1050    unsafe fn as_ascii_str_unchecked(&self) -> &AsciiStr {
1051        <&AsciiStr>::from(self)
1052    }
1053
1054    #[inline]
1055    fn get_ascii(&self, index: usize) -> Option<AsciiChar> {
1056        self.get(index).copied()
1057    }
1058}
1059impl AsMutAsciiStr for [AsciiChar] {
1060    fn slice_ascii_mut<R>(&mut self, range: R) -> Result<&mut AsciiStr, AsAsciiStrError>
1061    where
1062        R: SliceIndex<[AsciiChar], Output = [AsciiChar]>,
1063    {
1064        let len = self.len();
1065        match self.get_mut(range) {
1066            Some(slice) => Ok(slice.into()),
1067            None => Err(AsAsciiStrError(len)),
1068        }
1069    }
1070    #[inline]
1071    unsafe fn as_mut_ascii_str_unchecked(&mut self) -> &mut AsciiStr {
1072        <&mut AsciiStr>::from(self)
1073    }
1074}
1075
1076impl AsAsciiStr for [u8] {
1077    type Inner = u8;
1078
1079    fn slice_ascii<R>(&self, range: R) -> Result<&AsciiStr, AsAsciiStrError>
1080    where
1081        R: SliceIndex<[u8], Output = [u8]>,
1082    {
1083        if let Some(slice) = self.get(range) {
1084            slice.as_ascii_str().map_err(|AsAsciiStrError(not_ascii)| {
1085                let offset = slice.as_ptr() as usize - self.as_ptr() as usize;
1086                AsAsciiStrError(offset + not_ascii)
1087            })
1088        } else {
1089            Err(AsAsciiStrError(self.len()))
1090        }
1091    }
1092
1093    fn as_ascii_str(&self) -> Result<&AsciiStr, AsAsciiStrError> {
1094        // is_ascii is likely optimized
1095        if self.is_ascii() {
1096            // SAFETY: `is_ascii` guarantees all bytes are within ascii range.
1097            unsafe { Ok(self.as_ascii_str_unchecked()) }
1098        } else {
1099            Err(AsAsciiStrError(
1100                self.iter().take_while(|&b| b.is_ascii()).count(),
1101            ))
1102        }
1103    }
1104
1105    #[inline]
1106    unsafe fn as_ascii_str_unchecked(&self) -> &AsciiStr {
1107        // SAFETY: Caller guarantees `self` does not contain non-ascii characters
1108        unsafe { &*(self as *const [u8] as *const AsciiStr) }
1109    }
1110}
1111impl AsMutAsciiStr for [u8] {
1112    fn slice_ascii_mut<R>(&mut self, range: R) -> Result<&mut AsciiStr, AsAsciiStrError>
1113    where
1114        R: SliceIndex<[u8], Output = [u8]>,
1115    {
1116        let (ptr, len) = (self.as_ptr(), self.len());
1117        if let Some(slice) = self.get_mut(range) {
1118            let slice_ptr = slice.as_ptr();
1119            slice
1120                .as_mut_ascii_str()
1121                .map_err(|AsAsciiStrError(not_ascii)| {
1122                    let offset = slice_ptr as usize - ptr as usize;
1123                    AsAsciiStrError(offset + not_ascii)
1124                })
1125        } else {
1126            Err(AsAsciiStrError(len))
1127        }
1128    }
1129
1130    fn as_mut_ascii_str(&mut self) -> Result<&mut AsciiStr, AsAsciiStrError> {
1131        // is_ascii() is likely optimized
1132        if self.is_ascii() {
1133            // SAFETY: `is_ascii` guarantees all bytes are within ascii range.
1134            unsafe { Ok(self.as_mut_ascii_str_unchecked()) }
1135        } else {
1136            Err(AsAsciiStrError(
1137                self.iter().take_while(|&b| b.is_ascii()).count(),
1138            ))
1139        }
1140    }
1141
1142    #[inline]
1143    unsafe fn as_mut_ascii_str_unchecked(&mut self) -> &mut AsciiStr {
1144        // SAFETY: Caller guarantees `self` does not contain non-ascii characters
1145        unsafe { &mut *(self as *mut [u8] as *mut AsciiStr) }
1146    }
1147}
1148
1149impl AsAsciiStr for str {
1150    type Inner = u8;
1151    fn slice_ascii<R>(&self, range: R) -> Result<&AsciiStr, AsAsciiStrError>
1152    where
1153        R: SliceIndex<[u8], Output = [u8]>,
1154    {
1155        self.as_bytes().slice_ascii(range)
1156    }
1157    fn as_ascii_str(&self) -> Result<&AsciiStr, AsAsciiStrError> {
1158        self.as_bytes().as_ascii_str()
1159    }
1160    #[inline]
1161    unsafe fn as_ascii_str_unchecked(&self) -> &AsciiStr {
1162        // SAFETY: Caller guarantees `self` does not contain non-ascii characters
1163        unsafe { self.as_bytes().as_ascii_str_unchecked() }
1164    }
1165}
1166impl AsMutAsciiStr for str {
1167    fn slice_ascii_mut<R>(&mut self, range: R) -> Result<&mut AsciiStr, AsAsciiStrError>
1168    where
1169        R: SliceIndex<[u8], Output = [u8]>,
1170    {
1171        // SAFETY: We don't modify the reference in this function, and the caller may
1172        //         only modify it to include valid ascii characters.
1173        let bytes = unsafe { self.as_bytes_mut() };
1174        match bytes.get_mut(range) {
1175            // Valid ascii slice
1176            Some(slice) if slice.is_ascii() => {
1177                // SAFETY: All bytes are ascii, so this cast is valid
1178                let ptr = slice.as_mut_ptr().cast::<AsciiChar>();
1179                let len = slice.len();
1180
1181                // SAFETY: The pointer is valid for `len` elements, as it came
1182                //         from a slice.
1183                unsafe {
1184                    let slice = core::slice::from_raw_parts_mut(ptr, len);
1185                    Ok(<&mut AsciiStr>::from(slice))
1186                }
1187            }
1188            Some(slice) => {
1189                let not_ascii_len = slice.iter().copied().take_while(u8::is_ascii).count();
1190                let offset = slice.as_ptr() as usize - self.as_ptr() as usize;
1191
1192                Err(AsAsciiStrError(offset + not_ascii_len))
1193            }
1194            None => Err(AsAsciiStrError(self.len())),
1195        }
1196    }
1197    fn as_mut_ascii_str(&mut self) -> Result<&mut AsciiStr, AsAsciiStrError> {
1198        match self.bytes().position(|b| !b.is_ascii()) {
1199            Some(index) => Err(AsAsciiStrError(index)),
1200            // SAFETY: All bytes were iterated, and all were ascii
1201            None => unsafe { Ok(self.as_mut_ascii_str_unchecked()) },
1202        }
1203    }
1204    #[inline]
1205    unsafe fn as_mut_ascii_str_unchecked(&mut self) -> &mut AsciiStr {
1206        // SAFETY: Caller guarantees `self` does not contain non-ascii characters
1207        &mut *(self as *mut str as *mut AsciiStr)
1208    }
1209}
1210
1211/// Note that the trailing null byte will be removed in the conversion.
1212#[cfg(feature = "std")]
1213impl AsAsciiStr for CStr {
1214    type Inner = u8;
1215    fn slice_ascii<R>(&self, range: R) -> Result<&AsciiStr, AsAsciiStrError>
1216    where
1217        R: SliceIndex<[u8], Output = [u8]>,
1218    {
1219        self.to_bytes().slice_ascii(range)
1220    }
1221    #[inline]
1222    fn as_ascii_str(&self) -> Result<&AsciiStr, AsAsciiStrError> {
1223        self.to_bytes().as_ascii_str()
1224    }
1225    #[inline]
1226    unsafe fn as_ascii_str_unchecked(&self) -> &AsciiStr {
1227        // SAFETY: Caller guarantees `self` does not contain non-ascii characters
1228        unsafe { self.to_bytes().as_ascii_str_unchecked() }
1229    }
1230}
1231
1232#[cfg(test)]
1233mod tests {
1234    use super::{AsAsciiStr, AsAsciiStrError, AsMutAsciiStr, AsciiStr};
1235    #[cfg(feature = "alloc")]
1236    use alloc::string::{String, ToString};
1237    #[cfg(feature = "alloc")]
1238    use alloc::vec::Vec;
1239    use AsciiChar;
1240
1241    /// Ensures that common types, `str`, `[u8]`, `AsciiStr` and their
1242    /// references, shared and mutable implement `AsAsciiStr`.
1243    #[test]
1244    fn generic_as_ascii_str() {
1245        // Generic function to ensure `C` implements `AsAsciiStr`
1246        fn generic<C: AsAsciiStr + ?Sized>(c: &C) -> Result<&AsciiStr, AsAsciiStrError> {
1247            c.as_ascii_str()
1248        }
1249
1250        let arr = [AsciiChar::A];
1251        let ascii_str = arr.as_ref().into();
1252        let mut mut_arr = arr; // Note: We need a second copy to prevent overlapping mutable borrows.
1253        let mut_ascii_str = mut_arr.as_mut().into();
1254        let mut_arr_mut_ref: &mut [AsciiChar] = &mut [AsciiChar::A];
1255        let mut string_bytes = [b'A'];
1256        let string_mut = unsafe { core::str::from_utf8_unchecked_mut(&mut string_bytes) }; // SAFETY: 'A' is a valid string.
1257        let string_mut_bytes: &mut [u8] = &mut [b'A'];
1258
1259        // Note: This is a trick because `rustfmt` doesn't support
1260        //       attributes on blocks yet.
1261        #[rustfmt::skip]
1262        let _ = [
1263            assert_eq!(generic::<str             >("A"              ), Ok(ascii_str)),
1264            assert_eq!(generic::<[u8]            >(&b"A"[..]        ), Ok(ascii_str)),
1265            assert_eq!(generic::<AsciiStr        >(ascii_str        ), Ok(ascii_str)),
1266            assert_eq!(generic::<[AsciiChar]     >(&arr             ), Ok(ascii_str)),
1267            assert_eq!(generic::<&str            >(&"A"             ), Ok(ascii_str)),
1268            assert_eq!(generic::<&[u8]           >(&&b"A"[..]       ), Ok(ascii_str)),
1269            assert_eq!(generic::<&AsciiStr       >(&ascii_str       ), Ok(ascii_str)),
1270            assert_eq!(generic::<&[AsciiChar]    >(&&arr[..]        ), Ok(ascii_str)),
1271            assert_eq!(generic::<&mut str        >(&string_mut      ), Ok(ascii_str)),
1272            assert_eq!(generic::<&mut [u8]       >(&string_mut_bytes), Ok(ascii_str)),
1273            assert_eq!(generic::<&mut AsciiStr   >(&mut_ascii_str   ), Ok(ascii_str)),
1274            assert_eq!(generic::<&mut [AsciiChar]>(&mut_arr_mut_ref ), Ok(ascii_str)),
1275        ];
1276    }
1277
1278    #[cfg(feature = "std")]
1279    #[test]
1280    fn cstring_as_ascii_str() {
1281        use std::ffi::CString;
1282        fn generic<C: AsAsciiStr + ?Sized>(c: &C) -> Result<&AsciiStr, AsAsciiStrError> {
1283            c.as_ascii_str()
1284        }
1285        let arr = [AsciiChar::A];
1286        let ascii_str: &AsciiStr = arr.as_ref().into();
1287        let cstr = CString::new("A").unwrap();
1288        assert_eq!(generic(&*cstr), Ok(ascii_str));
1289    }
1290
1291    #[test]
1292    fn generic_as_mut_ascii_str() {
1293        fn generic_mut<C: AsMutAsciiStr + ?Sized>(
1294            c: &mut C,
1295        ) -> Result<&mut AsciiStr, AsAsciiStrError> {
1296            c.as_mut_ascii_str()
1297        }
1298
1299        let mut arr_mut = [AsciiChar::B];
1300        let mut ascii_str_mut: &mut AsciiStr = arr_mut.as_mut().into();
1301        // Need a second reference to prevent overlapping mutable borrows
1302        let mut arr_mut_2 = [AsciiChar::B];
1303        let ascii_str_mut_2: &mut AsciiStr = arr_mut_2.as_mut().into();
1304        assert_eq!(generic_mut(&mut ascii_str_mut), Ok(&mut *ascii_str_mut_2));
1305        assert_eq!(generic_mut(ascii_str_mut), Ok(&mut *ascii_str_mut_2));
1306    }
1307
1308    #[test]
1309    fn as_ascii_str() {
1310        macro_rules! err {{$i:expr} => {Err(AsAsciiStrError($i))}}
1311        let s = "abčd";
1312        let b = s.as_bytes();
1313        assert_eq!(s.as_ascii_str(), err!(2));
1314        assert_eq!(b.as_ascii_str(), err!(2));
1315        let a: &AsciiStr = [AsciiChar::a, AsciiChar::b][..].as_ref();
1316        assert_eq!(s[..2].as_ascii_str(), Ok(a));
1317        assert_eq!(b[..2].as_ascii_str(), Ok(a));
1318        assert_eq!(s.slice_ascii(..2), Ok(a));
1319        assert_eq!(b.slice_ascii(..2), Ok(a));
1320        assert_eq!(s.slice_ascii(..=2), err!(2));
1321        assert_eq!(b.slice_ascii(..=2), err!(2));
1322        assert_eq!(s.get_ascii(4), Some(AsciiChar::d));
1323        assert_eq!(b.get_ascii(4), Some(AsciiChar::d));
1324        assert_eq!(s.get_ascii(3), None);
1325        assert_eq!(b.get_ascii(3), None);
1326        assert_eq!(s.get_ascii(b.len()), None);
1327        assert_eq!(b.get_ascii(b.len()), None);
1328        assert_eq!(a.get_ascii(0), Some(AsciiChar::a));
1329        assert_eq!(a.get_ascii(a.len()), None);
1330    }
1331
1332    #[test]
1333    #[cfg(feature = "std")]
1334    fn cstr_as_ascii_str() {
1335        use std::ffi::CStr;
1336        macro_rules! err {{$i:expr} => {Err(AsAsciiStrError($i))}}
1337        let cstr = CStr::from_bytes_with_nul(b"a\xbbcde\xffg\0").unwrap();
1338        assert_eq!(cstr.as_ascii_str(), err!(1));
1339        assert_eq!(cstr.slice_ascii(2..), err!(5));
1340        assert_eq!(cstr.get_ascii(5), None);
1341        assert_eq!(cstr.get_ascii(6), Some(AsciiChar::g));
1342        assert_eq!(cstr.get_ascii(7), None);
1343        let ascii_slice = &[AsciiChar::X, AsciiChar::Y, AsciiChar::Z, AsciiChar::Null][..];
1344        let ascii_str: &AsciiStr = ascii_slice.as_ref();
1345        let cstr = CStr::from_bytes_with_nul(ascii_str.as_bytes()).unwrap();
1346        assert_eq!(cstr.slice_ascii(..2), Ok(&ascii_str[..2]));
1347        assert_eq!(cstr.as_ascii_str(), Ok(&ascii_str[..3]));
1348    }
1349
1350    #[test]
1351    #[cfg(feature = "alloc")]
1352    fn as_mut_ascii_str() {
1353        macro_rules! err {{$i:expr} => {Err(AsAsciiStrError($i))}}
1354        let mut s: String = "abčd".to_string();
1355        let mut b: Vec<u8> = s.clone().into();
1356        let mut first = [AsciiChar::a, AsciiChar::b];
1357        let mut second = [AsciiChar::d];
1358        assert_eq!(s.as_mut_ascii_str(), err!(2));
1359        assert_eq!(b.as_mut_ascii_str(), err!(2));
1360        assert_eq!(s.slice_ascii_mut(..), err!(2));
1361        assert_eq!(b.slice_ascii_mut(..), err!(2));
1362        assert_eq!(s[..2].as_mut_ascii_str(), Ok((&mut first[..]).into()));
1363        assert_eq!(b[..2].as_mut_ascii_str(), Ok((&mut first[..]).into()));
1364        assert_eq!(s.slice_ascii_mut(0..2), Ok((&mut first[..]).into()));
1365        assert_eq!(b.slice_ascii_mut(0..2), Ok((&mut first[..]).into()));
1366        assert_eq!(s.slice_ascii_mut(4..), Ok((&mut second[..]).into()));
1367        assert_eq!(b.slice_ascii_mut(4..), Ok((&mut second[..]).into()));
1368        assert_eq!(s.slice_ascii_mut(4..=10), err!(5));
1369        assert_eq!(b.slice_ascii_mut(4..=10), err!(5));
1370    }
1371
1372    #[test]
1373    fn default() {
1374        let default: &'static AsciiStr = Default::default();
1375        assert!(default.is_empty());
1376    }
1377
1378    #[test]
1379    #[allow(clippy::redundant_slicing)]
1380    fn index() {
1381        let mut arr = [AsciiChar::A, AsciiChar::B, AsciiChar::C, AsciiChar::D];
1382        {
1383            let a: &AsciiStr = arr[..].into();
1384            assert_eq!(a[..].as_slice(), &a.as_slice()[..]);
1385            assert_eq!(a[..4].as_slice(), &a.as_slice()[..4]);
1386            assert_eq!(a[4..].as_slice(), &a.as_slice()[4..]);
1387            assert_eq!(a[2..3].as_slice(), &a.as_slice()[2..3]);
1388            assert_eq!(a[..=3].as_slice(), &a.as_slice()[..=3]);
1389            assert_eq!(a[1..=1].as_slice(), &a.as_slice()[1..=1]);
1390        }
1391        let mut copy = arr;
1392        let a_mut: &mut AsciiStr = { &mut arr[..] }.into();
1393        assert_eq!(a_mut[..].as_mut_slice(), &mut copy[..]);
1394        assert_eq!(a_mut[..2].as_mut_slice(), &mut copy[..2]);
1395        assert_eq!(a_mut[3..].as_mut_slice(), &mut copy[3..]);
1396        assert_eq!(a_mut[4..4].as_mut_slice(), &mut copy[4..4]);
1397        assert_eq!(a_mut[..=0].as_mut_slice(), &mut copy[..=0]);
1398        assert_eq!(a_mut[0..=2].as_mut_slice(), &mut copy[0..=2]);
1399    }
1400
1401    #[test]
1402    fn as_str() {
1403        let b = b"( ;";
1404        let v = AsciiStr::from_ascii(b).unwrap();
1405        assert_eq!(v.as_str(), "( ;");
1406        assert_eq!(AsRef::<str>::as_ref(v), "( ;");
1407    }
1408
1409    #[test]
1410    fn as_bytes() {
1411        let b = b"( ;";
1412        let v = AsciiStr::from_ascii(b).unwrap();
1413        assert_eq!(v.as_bytes(), b"( ;");
1414        assert_eq!(AsRef::<[u8]>::as_ref(v), b"( ;");
1415    }
1416
1417    #[test]
1418    fn make_ascii_case() {
1419        let mut bytes = ([b'a', b'@', b'A'], [b'A', b'@', b'a']);
1420        let a = bytes.0.as_mut_ascii_str().unwrap();
1421        let b = bytes.1.as_mut_ascii_str().unwrap();
1422        assert!(a.eq_ignore_ascii_case(b));
1423        assert!(b.eq_ignore_ascii_case(a));
1424        a.make_ascii_lowercase();
1425        b.make_ascii_uppercase();
1426        assert_eq!(a, "a@a");
1427        assert_eq!(b, "A@A");
1428    }
1429
1430    #[test]
1431    #[cfg(feature = "alloc")]
1432    fn to_ascii_case() {
1433        let bytes = ([b'a', b'@', b'A'], [b'A', b'@', b'a']);
1434        let a = bytes.0.as_ascii_str().unwrap();
1435        let b = bytes.1.as_ascii_str().unwrap();
1436        assert_eq!(a.to_ascii_lowercase().as_str(), "a@a");
1437        assert_eq!(a.to_ascii_uppercase().as_str(), "A@A");
1438        assert_eq!(b.to_ascii_lowercase().as_str(), "a@a");
1439        assert_eq!(b.to_ascii_uppercase().as_str(), "A@A");
1440    }
1441
1442    #[test]
1443    fn chars_iter() {
1444        let chars = &[
1445            b'h', b'e', b'l', b'l', b'o', b' ', b'w', b'o', b'r', b'l', b'd', b'\0',
1446        ];
1447        let ascii = AsciiStr::from_ascii(chars).unwrap();
1448        for (achar, byte) in ascii.chars().zip(chars.iter().copied()) {
1449            assert_eq!(achar, byte);
1450        }
1451    }
1452
1453    #[test]
1454    fn chars_iter_mut() {
1455        let chars = &mut [
1456            b'h', b'e', b'l', b'l', b'o', b' ', b'w', b'o', b'r', b'l', b'd', b'\0',
1457        ];
1458        let ascii = chars.as_mut_ascii_str().unwrap();
1459        *ascii.chars_mut().next().unwrap() = AsciiChar::H;
1460        assert_eq!(ascii[0], b'H');
1461    }
1462
1463    #[test]
1464    fn lines_iter() {
1465        use core::iter::Iterator;
1466
1467        let lines: [&str; 4] = ["foo", "bar", "", "baz"];
1468        let joined = "foo\r\nbar\n\nbaz\n";
1469        let ascii = AsciiStr::from_ascii(joined.as_bytes()).unwrap();
1470        for (asciiline, line) in ascii.lines().zip(&lines) {
1471            assert_eq!(asciiline, *line);
1472        }
1473        assert_eq!(ascii.lines().count(), lines.len());
1474
1475        let lines: [&str; 4] = ["foo", "bar", "", "baz"];
1476        let joined = "foo\r\nbar\n\nbaz";
1477        let ascii = AsciiStr::from_ascii(joined.as_bytes()).unwrap();
1478        for (asciiline, line) in ascii.lines().zip(&lines) {
1479            assert_eq!(asciiline, *line);
1480        }
1481        assert_eq!(ascii.lines().count(), lines.len());
1482
1483        let trailing_line_break = b"\n";
1484        let ascii = AsciiStr::from_ascii(&trailing_line_break).unwrap();
1485        let mut line_iter = ascii.lines();
1486        assert_eq!(line_iter.next(), Some(AsciiStr::from_ascii("").unwrap()));
1487        assert_eq!(line_iter.next(), None);
1488
1489        let empty_lines = b"\n\r\n\n\r\n";
1490        let mut iter_count = 0;
1491        let ascii = AsciiStr::from_ascii(&empty_lines).unwrap();
1492        for line in ascii.lines() {
1493            iter_count += 1;
1494            assert!(line.is_empty());
1495        }
1496        assert_eq!(4, iter_count);
1497    }
1498
1499    #[test]
1500    fn lines_iter_rev() {
1501        let joined = "foo\r\nbar\n\nbaz\n";
1502        let ascii = AsciiStr::from_ascii(joined.as_bytes()).unwrap();
1503        assert_eq!(ascii.lines().rev().count(), 4);
1504        assert_eq!(ascii.lines().rev().count(), joined.lines().rev().count());
1505        for (asciiline, line) in ascii.lines().rev().zip(joined.lines().rev()) {
1506            assert_eq!(asciiline, line);
1507        }
1508        let mut iter = ascii.lines();
1509        assert_eq!(iter.next(), Some("foo".as_ascii_str().unwrap()));
1510        assert_eq!(iter.next_back(), Some("baz".as_ascii_str().unwrap()));
1511        assert_eq!(iter.next_back(), Some("".as_ascii_str().unwrap()));
1512        assert_eq!(iter.next(), Some("bar".as_ascii_str().unwrap()));
1513
1514        let empty_lines = b"\n\r\n\n\r\n";
1515        let mut iter_count = 0;
1516        let ascii = AsciiStr::from_ascii(&empty_lines).unwrap();
1517        for line in ascii.lines().rev() {
1518            iter_count += 1;
1519            assert!(line.is_empty());
1520        }
1521        assert_eq!(4, iter_count);
1522    }
1523
1524    #[test]
1525    fn lines_iter_empty() {
1526        assert_eq!("".as_ascii_str().unwrap().lines().next(), None);
1527        assert_eq!("".as_ascii_str().unwrap().lines().next_back(), None);
1528        assert_eq!("".lines().next(), None);
1529    }
1530
1531    #[test]
1532    fn split_str() {
1533        fn split_equals_str(haystack: &str, needle: char) {
1534            let mut strs = haystack.split(needle);
1535            let mut asciis = haystack
1536                .as_ascii_str()
1537                .unwrap()
1538                .split(AsciiChar::from_ascii(needle).unwrap())
1539                .map(AsciiStr::as_str);
1540            loop {
1541                assert_eq!(asciis.size_hint(), strs.size_hint());
1542                let (a, s) = (asciis.next(), strs.next());
1543                assert_eq!(a, s);
1544                if a == None {
1545                    break;
1546                }
1547            }
1548            // test fusedness if str's version is fused
1549            if strs.next() == None {
1550                assert_eq!(asciis.next(), None);
1551            }
1552        }
1553        split_equals_str("", '=');
1554        split_equals_str("1,2,3", ',');
1555        split_equals_str("foo;bar;baz;", ';');
1556        split_equals_str("|||", '|');
1557        split_equals_str(" a  b  c ", ' ');
1558    }
1559
1560    #[test]
1561    fn split_str_rev() {
1562        let words = " foo  bar baz ";
1563        let ascii = words.as_ascii_str().unwrap();
1564        for (word, asciiword) in words
1565            .split(' ')
1566            .rev()
1567            .zip(ascii.split(AsciiChar::Space).rev())
1568        {
1569            assert_eq!(asciiword, word);
1570        }
1571        let mut iter = ascii.split(AsciiChar::Space);
1572        assert_eq!(iter.next(), Some("".as_ascii_str().unwrap()));
1573        assert_eq!(iter.next_back(), Some("".as_ascii_str().unwrap()));
1574        assert_eq!(iter.next(), Some("foo".as_ascii_str().unwrap()));
1575        assert_eq!(iter.next_back(), Some("baz".as_ascii_str().unwrap()));
1576        assert_eq!(iter.next_back(), Some("bar".as_ascii_str().unwrap()));
1577        assert_eq!(iter.next(), Some("".as_ascii_str().unwrap()));
1578        assert_eq!(iter.next_back(), None);
1579    }
1580
1581    #[test]
1582    fn split_str_empty() {
1583        let empty = <&AsciiStr>::default();
1584        let mut iter = empty.split(AsciiChar::NAK);
1585        assert_eq!(iter.next(), Some(empty));
1586        assert_eq!(iter.next(), None);
1587        let mut iter = empty.split(AsciiChar::NAK);
1588        assert_eq!(iter.next_back(), Some(empty));
1589        assert_eq!(iter.next_back(), None);
1590        assert_eq!("".split('s').next(), Some("")); // str.split() also produces one element
1591    }
1592
1593    #[test]
1594    #[cfg(feature = "std")]
1595    fn fmt_ascii_str() {
1596        let s = "abc".as_ascii_str().unwrap();
1597        assert_eq!(format!("{}", s), "abc".to_string());
1598        assert_eq!(format!("{:?}", s), "\"abc\"".to_string());
1599    }
1600}