1 | mod bstr; |
2 | mod hstring; |
3 | mod literals; |
4 | mod pcstr; |
5 | mod pcwstr; |
6 | mod pstr; |
7 | mod pwstr; |
8 | |
9 | pub use bstr::*; |
10 | pub use hstring::*; |
11 | #[doc (hidden)] |
12 | pub use literals::*; |
13 | pub use pcstr::*; |
14 | pub use pcwstr::*; |
15 | pub use pstr::*; |
16 | pub use pwstr::*; |
17 | |
18 | use super::*; |
19 | |
20 | extern "C" { |
21 | #[doc (hidden)] |
22 | pub fn strlen(s: PCSTR) -> usize; |
23 | #[doc (hidden)] |
24 | pub fn wcslen(s: PCWSTR) -> usize; |
25 | } |
26 | |
27 | /// An internal helper for decoding an iterator of chars and displaying them |
28 | #[doc (hidden)] |
29 | pub struct Decode<F>(pub F); |
30 | |
31 | impl<F, R, E> std::fmt::Display for Decode<F> |
32 | where |
33 | F: Clone + FnOnce() -> R, |
34 | R: IntoIterator<Item = std::result::Result<char, E>>, |
35 | { |
36 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
37 | use std::fmt::Write; |
38 | let iter: F = self.0.clone(); |
39 | for c: Result in iter().into_iter() { |
40 | f.write_char(c.unwrap_or(default:std::char::REPLACEMENT_CHARACTER))? |
41 | } |
42 | Ok(()) |
43 | } |
44 | } |
45 | |
46 | /// Mirror of `std::char::decode_utf16` for utf-8. |
47 | fn decode_utf8(mut buffer: &[u8]) -> impl Iterator<Item = std::result::Result<char, std::str::Utf8Error>> + '_ { |
48 | let mut current = "" .chars(); |
49 | let mut previous_error = None; |
50 | std::iter::from_fn(move || { |
51 | loop { |
52 | match (current.next(), previous_error) { |
53 | (Some(c), _) => return Some(Ok(c)), |
54 | // Return the previous error |
55 | (None, Some(e)) => { |
56 | previous_error = None; |
57 | return Some(Err(e)); |
58 | } |
59 | // We're completely done |
60 | (None, None) if buffer.is_empty() => return None, |
61 | (None, None) => { |
62 | match std::str::from_utf8(buffer) { |
63 | Ok(s) => { |
64 | current = s.chars(); |
65 | buffer = &[]; |
66 | } |
67 | Err(e) => { |
68 | let (valid, rest) = buffer.split_at(e.valid_up_to()); |
69 | // Skip the invalid sequence and stop completely if we ended early |
70 | let invalid_sequence_length = e.error_len()?; |
71 | buffer = &rest[invalid_sequence_length..]; |
72 | |
73 | // Set the current iterator to the valid section and indicate previous error |
74 | // SAFETY: `valid` is known to be valid utf-8 from error |
75 | current = unsafe { std::str::from_utf8_unchecked(valid) }.chars(); |
76 | previous_error = Some(e); |
77 | } |
78 | } |
79 | } |
80 | } |
81 | } |
82 | }) |
83 | } |
84 | |