diff options
| author | mo khan <mo@mokhan.ca> | 2025-07-02 18:36:06 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-07-02 18:36:06 -0600 |
| commit | 8cdfa445d6629ffef4cb84967ff7017654045bc2 (patch) | |
| tree | 22f0b0907c024c78d26a731e2e1f5219407d8102 /vendor/windows-strings/src/decode.rs | |
| parent | 4351c74c7c5f97156bc94d3a8549b9940ac80e3f (diff) | |
chore: add vendor directory
Diffstat (limited to 'vendor/windows-strings/src/decode.rs')
| -rw-r--r-- | vendor/windows-strings/src/decode.rs | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/vendor/windows-strings/src/decode.rs b/vendor/windows-strings/src/decode.rs new file mode 100644 index 00000000..dbc9e2ea --- /dev/null +++ b/vendor/windows-strings/src/decode.rs @@ -0,0 +1,58 @@ +/// An internal helper for decoding an iterator of chars and displaying them +pub struct Decode<F>(pub F); + +impl<F, R, E> core::fmt::Display for Decode<F> +where + F: Clone + FnOnce() -> R, + R: IntoIterator<Item = core::result::Result<char, E>>, +{ + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + use core::fmt::Write; + let iter = self.0.clone(); + for c in iter().into_iter() { + f.write_char(c.unwrap_or(core::char::REPLACEMENT_CHARACTER))? + } + Ok(()) + } +} + +/// Mirror of `std::char::decode_utf16` for utf-8. +pub fn decode_utf8( + mut buffer: &[u8], +) -> impl Iterator<Item = core::result::Result<char, core::str::Utf8Error>> + '_ { + let mut current = "".chars(); + let mut previous_error = None; + core::iter::from_fn(move || { + loop { + match (current.next(), previous_error) { + (Some(c), _) => return Some(Ok(c)), + // Return the previous error + (None, Some(e)) => { + previous_error = None; + return Some(Err(e)); + } + // We're completely done + (None, None) if buffer.is_empty() => return None, + (None, None) => { + match core::str::from_utf8(buffer) { + Ok(s) => { + current = s.chars(); + buffer = &[]; + } + Err(e) => { + let (valid, rest) = buffer.split_at(e.valid_up_to()); + // Skip the invalid sequence and stop completely if we ended early + let invalid_sequence_length = e.error_len()?; + buffer = &rest[invalid_sequence_length..]; + + // Set the current iterator to the valid section and indicate previous error + // SAFETY: `valid` is known to be valid utf-8 from error + current = unsafe { core::str::from_utf8_unchecked(valid) }.chars(); + previous_error = Some(e); + } + } + } + } + } + }) +} |
