Skip to main content

utf8_iter/
report.rs

1// Copyright Mozilla Foundation
2//
3// Licensed under the Apache License (Version 2.0), or the MIT license,
4// (the "Licenses") at your option. You may not use this file except in
5// compliance with one of the Licenses. You may obtain copies of the
6// Licenses at:
7//
8//    https://www.apache.org/licenses/LICENSE-2.0
9//    https://opensource.org/licenses/MIT
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the Licenses is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the Licenses for the specific language governing permissions and
15// limitations under the Licenses.
16
17use utf_types::utf8::Ascii;
18use utf_types::utf8::FourByteSequence;
19use utf_types::utf8::ThreeByteSequence;
20use utf_types::utf8::TwoByteSequence;
21
22use crate::Utf8Handler;
23use core::fmt::Formatter;
24
25/// A type for signaling UTF-8 errors.
26#[derive(#[automatically_derived]impl ::core::fmt::Debug for Utf8CharsError {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "Utf8CharsError")
    }
}Debug, #[automatically_derived]impl ::core::marker::StructuralPartialEq for
    Utf8CharsError {
}
#[automatically_derived]impl ::core::cmp::PartialEq for Utf8CharsError {
    #[inline]
    fn eq(&self, other: &Self) -> bool { true }
}PartialEq, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
    for Utf8CharsError {
}
#[automatically_derived]impl ::core::clone::Clone for Utf8CharsError {
    #[inline]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::marker::Copy for Utf8CharsError { }Copy, #[automatically_derived]impl ::core::cmp::Eq for Utf8CharsError { }Eq, #[automatically_derived]impl ::core::hash::Hash for Utf8CharsError {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {}
}Hash)]
27#[non_exhaustive]
28pub struct Utf8CharsError;
29
30impl core::fmt::Display for Utf8CharsError {
31    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
32        f.write_fmt(format_args!("byte sequence not well-formed UTF-8"))write!(f, "byte sequence not well-formed UTF-8")
33    }
34}
35
36impl core::error::Error for Utf8CharsError {}
37
38/// The `Output = Result<char, Utf8CharsError>` case.
39#[derive(#[automatically_derived]impl ::core::fmt::Debug for ErrorReportingHandler {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "ErrorReportingHandler")
    }
}Debug, #[automatically_derived]impl ::core::clone::Clone for ErrorReportingHandler {
    #[inline]
    fn clone(&self) -> Self { ErrorReportingHandler }
}Clone)]
40pub(crate) struct ErrorReportingHandler;
41
42impl ErrorReportingHandler {
43    pub(crate) fn new() -> Self {
44        Self {}
45    }
46}
47
48impl Utf8Handler for ErrorReportingHandler {
49    type Output = Result<char, Utf8CharsError>;
50
51    /// Map a single-byte UTF-8 sequence to `Output`.
52    ///
53    /// When `Output` is `char`, `ascii.to_char()`
54    /// is the appropriate implementation.
55    ///
56    /// The implementation is expected to be marked
57    /// `#[inline(always)]`.
58    #[inline(always)]
59    fn single_byte(&self, ascii: Ascii) -> Self::Output {
60        Ok(ascii.to_char())
61    }
62
63    /// Map a two-byte UTF-8 sequence to `Output`.
64    ///
65    /// When `Output` is `char`, `sequence.to_char()`
66    /// is the appropriate implementation.
67    ///
68    /// The implementation is expected to be marked
69    /// `#[inline(always)]`.
70    #[inline(always)]
71    fn two_byte(&self, sequence: TwoByteSequence) -> Self::Output {
72        Ok(sequence.to_char())
73    }
74
75    /// Map a three-byte UTF-8 sequence to `Output`.
76    ///
77    /// When `Output` is `char`, `sequence.to_char()`
78    /// is the appropriate implementation.
79    ///
80    /// The implementation is expected to be marked
81    /// `#[inline(always)]`.
82    #[inline(always)]
83    fn three_byte(&self, sequence: ThreeByteSequence) -> Self::Output {
84        Ok(sequence.to_char())
85    }
86
87    /// Map a four-byte UTF-8 sequence to `Output`.
88    ///
89    /// When `Output` is `char`, `sequence.to_char()`
90    /// is the appropriate implementation.
91    ///
92    /// The implementation is expected to be marked
93    /// `#[inline(always)]`.
94    #[inline(always)]
95    fn four_byte(&self, sequence: FourByteSequence) -> Self::Output {
96        Ok(sequence.to_char())
97    }
98
99    /// Map a single UTF-8 error to `Output`.
100    ///
101    /// What constitutes a single error is defined by the
102    /// WHATWG Encoding Standard.
103    ///
104    /// When `Output` is `char`,
105    /// `char::REPLACEMENT_CHARACTER`
106    /// is the appropriate implementation.
107    ///
108    /// The implementation of this method is expected to
109    /// be declared `#[inline(always)]`.
110    #[inline(always)]
111    fn error(&self) -> Self::Output {
112        Err(Utf8CharsError)
113    }
114}
115
116#[doc =
r" Iterator by `Result<char,Utf8CharsError>` over `&[u8]` that contains"]
#[doc =
r" potentially-invalid UTF-8. There is exactly one `Utf8CharsError` per"]
#[doc = r" each error as defined by the WHATWG Encoding Standard."]
#[doc = r""]
#[doc = r" ```"]
#[doc =
r#" let s = b"a\xFFb\xFF\x80c\xF0\x9F\xA4\xA6\xF0\x9F\xA4\xF0\x9F\xF0d";"#]
#[doc = r" let plain = utf8_iter::Utf8Chars::new(s);"]
#[doc = r" let reporting = utf8_iter::ErrorReportingUtf8Chars::new(s);"]
#[doc = r" assert!(plain.eq(reporting.map(|r| r.unwrap_or('\u{FFFD}'))));"]
#[doc = r" ```"]
pub struct ErrorReportingUtf8Chars<'a> {
    inner: crate::Utf8CharsWithHandler<'a, ErrorReportingHandler>,
}
#[automatically_derived]impl<'a> ::core::fmt::Debug for
    ErrorReportingUtf8Chars<'a> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field1_finish(f,
            "ErrorReportingUtf8Chars inner", &&self.inner)
    }
}
impl<'a> ErrorReportingUtf8Chars<'a> {
    #[inline(always)]
    /// Creates the iterator from a byte slice.
    pub fn new(bytes: &'a [u8]) -> Self {
        Self {
            inner: crate::Utf8CharsWithHandler::new(bytes,
                ErrorReportingHandler::new()),
        }
    }
    /// Views the current remaining data in the iterator as a subslice
    /// of the original slice.
    #[must_use]
    #[inline(always)]
    pub fn as_slice(&self) -> &'a [u8] { self.inner.as_slice() }
}
impl<'a> Iterator for ErrorReportingUtf8Chars<'a> {
    type Item = Result<char, Utf8CharsError>;
    #[inline(always)]
    fn next(&mut self) -> Option<Self::Item> { self.inner.next() }
    #[inline(always)]
    fn count(self) -> usize { self.inner.count() }
    #[inline(always)]
    fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
    #[inline(always)]
    fn last(mut self) -> Option<Self::Item> { self.next_back() }
}
impl<'a> DoubleEndedIterator for ErrorReportingUtf8Chars<'a> {
    #[inline(always)]
    fn next_back(&mut self) -> Option<Self::Item> { self.inner.next_back() }
}
impl core::iter::FusedIterator for ErrorReportingUtf8Chars<'_> {}
impl<'a> Clone for ErrorReportingUtf8Chars<'a> {
    fn clone(&self) -> Self { Self { inner: self.inner.clone() } }
}
#[doc = r" Iterator by `Result<char,Utf8CharsError>` and their indices over"]
#[doc = r" `&[u8]` that contains potentially-invalid UTF-8. See the crate"]
#[doc = r" documentation."]
pub struct ErrorReportingUtf8CharIndices<'a> {
    inner: crate::Utf8CharIndicesWithHandler<'a, ErrorReportingHandler>,
}
#[automatically_derived]impl<'a> ::core::fmt::Debug for
    ErrorReportingUtf8CharIndices<'a> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field1_finish(f,
            "ErrorReportingUtf8CharIndices inner", &&self.inner)
    }
}
impl<'a> ErrorReportingUtf8CharIndices<'a> {
    #[inline(always)]
    /// Creates the iterator from a byte slice.
    pub fn new(bytes: &'a [u8]) -> Self {
        Self {
            inner: crate::Utf8CharIndicesWithHandler::new(bytes,
                ErrorReportingHandler::new()),
        }
    }
    /// Views the current remaining data in the iterator as a subslice
    /// of the original slice.
    #[inline(always)]
    #[must_use]
    pub fn as_slice(&self) -> &'a [u8] { self.inner.as_slice() }
    /// The current index offset
    #[inline(always)]
    #[must_use]
    pub fn offset(&self) -> usize { self.inner.offset() }
}
impl<'a> Iterator for ErrorReportingUtf8CharIndices<'a> {
    type Item = (usize, Result<char, Utf8CharsError>);
    #[inline(always)]
    fn next(&mut self) -> Option<Self::Item> { self.inner.next() }
    #[inline(always)]
    fn count(self) -> usize { self.inner.count() }
    #[inline(always)]
    fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
    #[inline(always)]
    fn last(mut self) -> Option<Self::Item> { self.next_back() }
}
impl<'a> DoubleEndedIterator for ErrorReportingUtf8CharIndices<'a> {
    #[inline(always)]
    fn next_back(&mut self) -> Option<Self::Item> { self.inner.next_back() }
}
impl core::iter::FusedIterator for ErrorReportingUtf8CharIndices<'_> {}
impl<'a> Clone for ErrorReportingUtf8CharIndices<'a> {
    fn clone(&self) -> Self { Self { inner: self.inner.clone() } }
}crate::macros::named_iterators_from_no_argument_handler!(
117    ErrorReportingHandler,
118    Result<char, Utf8CharsError>,
119    /// Iterator by `Result<char,Utf8CharsError>` over `&[u8]` that contains
120    /// potentially-invalid UTF-8. There is exactly one `Utf8CharsError` per
121    /// each error as defined by the WHATWG Encoding Standard.
122    ///
123    /// ```
124    /// let s = b"a\xFFb\xFF\x80c\xF0\x9F\xA4\xA6\xF0\x9F\xA4\xF0\x9F\xF0d";
125    /// let plain = utf8_iter::Utf8Chars::new(s);
126    /// let reporting = utf8_iter::ErrorReportingUtf8Chars::new(s);
127    /// assert!(plain.eq(reporting.map(|r| r.unwrap_or('\u{FFFD}'))));
128    /// ```
129    ,
130    ErrorReportingUtf8Chars,
131    /// Iterator by `Result<char,Utf8CharsError>` and their indices over
132    /// `&[u8]` that contains potentially-invalid UTF-8. See the crate
133    /// documentation.
134    ,
135    ErrorReportingUtf8CharIndices,
136);
137
138#[cfg(test)]
139mod tests {
140    use crate::ErrorReportingUtf8Chars;
141
142    // Should be a static assert, but not taking a dependency for this.
143    #[test]
144    fn test_size() {
145        assert_eq!(
146            core::mem::size_of::<Option<<ErrorReportingUtf8Chars<'_> as Iterator>::Item>>(),
147            core::mem::size_of::<Option<char>>()
148        );
149    }
150
151    #[test]
152    fn test_eq() {
153        let a: <ErrorReportingUtf8Chars<'_> as Iterator>::Item = Ok('a');
154        let a_again: <ErrorReportingUtf8Chars<'_> as Iterator>::Item = Ok('a');
155        assert_eq!(a, a_again);
156    }
157}