Last active
September 5, 2020 23:29
-
-
Save thomcc/6cda7e4fb69b32bff694b7ebc199d242 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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