Skip to content

Instantly share code, notes, and snippets.

@thomcc
Last active September 5, 2020 23:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thomcc/6cda7e4fb69b32bff694b7ebc199d242 to your computer and use it in GitHub Desktop.
Save thomcc/6cda7e4fb69b32bff694b7ebc199d242 to your computer and use it in GitHub Desktop.
// https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=26888dbe066530c56f7181d3abc030e0
use std::borrow::Cow;
pub trait IntoUtf8Lossy {
type String;
fn into_utf8_lossy(self) -> Self::String;
}
impl<'a> IntoUtf8Lossy for &'a [u8] {
type String = Cow<'a, str>;
fn into_utf8_lossy(self) -> Cow<'a, str> {
String::from_utf8_lossy(self)
}
}
impl IntoUtf8Lossy for Vec<u8> {
type String = String;
fn into_utf8_lossy(self) -> String {
if let Cow::Owned(string) = String::from_utf8_lossy(&self) {
string
} else {
// SAFETY: `String::from_utf8_lossy`'s contract ensures that if
// it returns a `Cow::Borrowed`, it is identical to the input.
unsafe { String::from_utf8_unchecked(self) }
}
}
}
impl<'a> IntoUtf8Lossy for Cow<'a, [u8]> {
type String = Cow<'a, str>;
fn into_utf8_lossy(self) -> Self::String {
match self {
Cow::Owned(v) => Cow::Owned(v.into_utf8_lossy()),
Cow::Borrowed(v) => v.into_utf8_lossy(),
}
}
}
// I think the ideal here would be to impl<'a, T> &'a T where T: Deref<Target=[u8]>,
// but arrays aren't this (surprisingly!), and doing that prevents impls for arrays.
// that said, not having that blanket impl means this could be breaking for custom
// types which are `Deref<Target=[u8]>`
macro_rules! impl_via_deref {
($($T:ty,)+) => {$(
impl<'a> IntoUtf8Lossy for &'a $T {
type String = Cow<'a, str>;
fn into_utf8_lossy(self) -> Cow<'a, str> {
String::from_utf8_lossy(&*self)
}
}
)+};
}
macro_rules! impl_for_arrays {
($($n:literal)+) => {$(
impl<'a> IntoUtf8Lossy for &'a [u8; $n] {
type String = Cow<'a, str>;
fn into_utf8_lossy(self) -> Cow<'a, str> {
let s: &[u8] = &self[..];
String::from_utf8_lossy(s)
}
}
)+};
}
impl_via_deref!{
Vec<u8>,
Cow<'a, [u8]>,
std::rc::Rc<[u8]>,
std::sync::Arc<[u8]>,
// ...
}
impl_for_arrays!{
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
}
pub fn from_utf8_lossy(s: &[u8]) -> Cow<'_, str> {
String::from_utf8_lossy(s)
}
pub fn from_utf8_lossy2<I: IntoUtf8Lossy>(s: I) -> I::String {
s.into_utf8_lossy()
}
fn main() {
from_utf8_lossy(b"");
from_utf8_lossy(b"abc");
from_utf8_lossy(&[]);
from_utf8_lossy(&[b'a', b'b', b'c']);
from_utf8_lossy(&[b'a', b'b', b'c'][..]);
from_utf8_lossy(&vec![b'a', b'b', b'c']);
from_utf8_lossy(&Cow::<'static, [u8]>::Owned(vec![b'a', b'b', b'c']));
from_utf8_lossy(&std::rc::Rc::<[u8]>::from(&[b'a', b'b', b'c'][..]));
from_utf8_lossy(&std::sync::Arc::<[u8]>::from(&[b'a', b'b', b'c'][..]));
from_utf8_lossy2(b"");
from_utf8_lossy2(b"abc");
from_utf8_lossy2(&[]);
from_utf8_lossy2(&[b'a', b'b', b'c']);
from_utf8_lossy2(&[b'a', b'b', b'c'][..]);
from_utf8_lossy2(&vec![b'a', b'b', b'c']);
from_utf8_lossy2(&Cow::<'static, [u8]>::Owned(vec![b'a', b'b', b'c']));
from_utf8_lossy2(&std::rc::Rc::<[u8]>::from(&[b'a', b'b', b'c'][..]));
from_utf8_lossy2(&std::sync::Arc::<[u8]>::from(&[b'a', b'b', b'c'][..]));
from_utf8_lossy2(Cow::<'static, [u8]>::Owned(vec![b'a', b'b', b'c']));
from_utf8_lossy2(vec![b'a', b'b', b'c']);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment