use getset::{Getters, WithSetters};
use tap::Pipe;
use crate::os_cmd::MiniStr;
#[derive(Debug, Clone, WithSetters, Getters, Default)]
#[getset(set_with = "pub")]
pub struct DecodedText {
pub lossy: bool,
#[getset(get = "pub")]
data: MiniStr,
}
impl core::ops::Deref for DecodedText {
type Target = MiniStr;
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl core::fmt::Display for DecodedText {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(&self.data)
}
}
impl<B> From<B> for DecodedText
where
B: Into<Vec<u8>>,
{
fn from(value: B) -> Self {
Self::from_vec(value)
}
}
impl DecodedText {
pub fn new_lossless(data: MiniStr) -> Self {
Self { lossy: false, data }
}
pub fn new_lossy(data: MiniStr) -> Self {
Self { lossy: true, data }
}
pub fn into_compact_string(self) -> MiniStr {
self.data
}
pub fn take_data(self) -> MiniStr {
self.data
}
pub fn from_slice<V: AsRef<[u8]>>(value: V) -> Self {
let slice = value.as_ref();
match MiniStr::from_utf8(slice) {
Ok(s) => Self::new_lossless(s),
_ => slice
.pipe(MiniStr::from_utf8_lossy)
.pipe(Self::new_lossy),
}
}
pub fn from_vec<V: Into<Vec<u8>>>(v: V) -> Self {
use std::borrow::Cow;
let value = v.into();
const INLINE: usize = match usize::BITS {
32 => 12,
_ => 24,
};
if value.len() <= INLINE {
return Self::from_slice(value);
}
let into_data = |s| MiniStr::from_string_buffer(s);
match String::from_utf8_lossy(&value) {
Cow::Owned(s) => s
.pipe(into_data)
.pipe(Self::new_lossy),
_ => unsafe { String::from_utf8_unchecked(value) }
.pipe(into_data)
.pipe(Self::new_lossless),
}
}
}