use {
crate::{lua::LuaError, prelude::*},
glib::variant::VariantTypeMismatchError,
std::{fmt, ops::Deref, str},
};
newtype_wrapper! {
#[derive(Debug, Ord, Eq, Clone, Hash)]
pub struct LuaString([u8] | Vec<u8> = Self) as_bytes into_bytes;
}
impl<'a> LuaString<'a> {
pub fn as_str(&self) -> Result<&str, str::Utf8Error> {
str::from_utf8(self.as_bytes())
}
pub fn into_string(self) -> Result<String, str::Utf8Error> {
match self.as_str() {
Ok(..) => Ok(unsafe { String::from_utf8_unchecked(self.into_bytes()) }),
Err(e) => Err(e),
}
}
pub fn to_variant(&self) -> Variant {
match self.as_str() {
Ok(s) => s.to_variant(),
Err(..) => self.as_bytes().to_variant(),
}
}
pub fn parse<F: FromStr>(&self) -> Result<F, LuaError>
where
F::Err: Into<LuaError>,
{
self
.as_str()
.map_err(Into::into)
.and_then(|s| s.parse().map_err(Into::into))
}
}
impl<'a> Deref for LuaString<'a> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.as_bytes()
}
}
impl<'a> TryFrom<&'a Variant> for LuaString<'a> {
type Error = LuaError;
fn try_from(variant: &'a Variant) -> Result<Self, Self::Error> {
match variant.classify() {
VariantClass::Variant => Self::try_from(variant.as_variant().expect("VariantClass")),
VariantClass::String => Ok(Self::from(variant.str().expect("VariantClass"))),
VariantClass::Array if variant.type_() == VariantTy::BYTE_STRING =>
Ok(Self::from(variant.fixed_array::<u8>().expect("VariantClass"))),
_ => Err(LuaError::TypeMismatch(VariantTypeMismatchError::new(
variant.type_().to_owned(),
VariantTy::STRING.to_owned(),
))),
}
}
}
impl<'a> TryFrom<Variant> for LuaString<'a> {
type Error = LuaError;
fn try_from(variant: Variant) -> Result<Self, Self::Error> {
LuaString::try_from(&variant).map(|s| s.owned())
}
}
impl<'a> Into<Variant> for LuaString<'a> {
fn into(self) -> Variant {
Into::into(&self)
}
}
impl<'a> From<String> for LuaString<'a> {
fn from(v: String) -> Self {
Self::from(v.into_bytes())
}
}
impl<'a> From<&'a str> for LuaString<'a> {
fn from(v: &'a str) -> Self {
Self::from(v.as_bytes())
}
}
impl fmt::Display for LuaString<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.as_str() {
Ok(s) => fmt::Display::fmt(s, f),
Err(_) => todo!(),
}
}
}