use crate::std::{borrow::Cow, string::String, vec::Vec};
#[must_use]
pub fn decode_utf8_or_latin1(bytes: &[u8]) -> Cow<'_, str> {
match core::str::from_utf8(bytes) {
Ok(text) => Cow::Borrowed(text),
Err(_) => Cow::Owned(bytes.iter().copied().map(char::from).collect()),
}
}
#[must_use]
pub fn decode_utf8_or_latin1_owned(bytes: Vec<u8>) -> String {
match String::from_utf8(bytes) {
Ok(text) => text,
Err(error) => error.into_bytes().into_iter().map(char::from).collect(),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn valid_utf8_is_borrowed() {
let bytes = "café".as_bytes();
let decoded = decode_utf8_or_latin1(bytes);
assert!(matches!(decoded, Cow::Borrowed("café")));
}
#[test]
fn invalid_utf8_decodes_the_complete_input_as_latin1() {
let decoded = decode_utf8_or_latin1(b"caf\xe9");
assert!(matches!(decoded, Cow::Owned(ref text) if text == "café"));
assert_eq!(decode_utf8_or_latin1(b"\xc3("), "Ã(");
}
#[test]
fn owned_decoder_handles_both_encodings() {
assert_eq!(
decode_utf8_or_latin1_owned("café".as_bytes().to_vec()),
"café"
);
assert_eq!(decode_utf8_or_latin1_owned(b"caf\xe9".to_vec()), "café");
}
}