use widestring::*;
use widestring::NulError as WideNulError;
use std::ffi::*; use std::ffi::NulError as CNulError;
use std::borrow::Cow;
use std::error::Error;
use std::fmt::{Display, Formatter, Result as FmtResult};
use std::str::Utf8Error;
use std::string::FromUtf16Error;
#[derive(Debug)]
pub enum ConversionError<NE> { Nul(NE), InvalidChar(Utf8Error), InvalidUChar16(FromUtf16Error), InvalidUChar32(FromUtf32Error) }
impl<NE: Display> Display for ConversionError<NE>
{
fn fmt(&self, fmt: &mut Formatter) -> FmtResult
{
match self
{
ConversionError::Nul(n) => n.fmt(fmt),
ConversionError::InvalidChar(c) => c.fmt(fmt),
ConversionError::InvalidUChar16(c) => c.fmt(fmt),
ConversionError::InvalidUChar32(c) => c.fmt(fmt)
}
}
}
impl<NE: Error> Error for ConversionError<NE>
{
fn description(&self) -> &str
{
match *self
{
ConversionError::Nul(_) => "Null character found in string",
ConversionError::InvalidChar(_) => "Invalid charcode for UTF-8",
ConversionError::InvalidUChar16(_) => "Couldn't convert UTF-16 charcode to UTF-8",
ConversionError::InvalidUChar32(_) => "Couldn't convert UTF-32 charcode to UTF-8"
}
}
fn cause(&self) -> Option<&dyn Error>
{
match self
{
ConversionError::Nul(e) => Some(e),
ConversionError::InvalidChar(e) => Some(e),
ConversionError::InvalidUChar16(e) => Some(e),
ConversionError::InvalidUChar32(e) => Some(e)
}
}
}
impl From<CNulError> for ConversionError<CNulError> { fn from(e: CNulError) -> Self { ConversionError::Nul(e) } }
impl<U: UChar> From<WideNulError<U>> for ConversionError<WideNulError<U>> { fn from(e: WideNulError<U>) -> Self { ConversionError::Nul(e) } }
impl<NE> From<Utf8Error> for ConversionError<NE> { fn from(e: Utf8Error) -> Self { ConversionError::InvalidChar(e) } }
impl<NE> From<FromUtf16Error> for ConversionError<NE> { fn from(e: FromUtf16Error) -> Self { ConversionError::InvalidUChar16(e) } }
impl<NE> From<FromUtf32Error> for ConversionError<NE> { fn from(e: FromUtf32Error) -> Self { ConversionError::InvalidUChar32(e) } }
pub trait UnivString
{
fn to_cstr(&self) -> Result<Cow<CStr>, ConversionError<CNulError>>;
fn to_ucstr16(&self) -> Result<Cow<UCStr<u16>>, ConversionError<WideNulError<u16>>>;
fn to_ucstr32(&self) -> Result<Cow<UCStr<u32>>, ConversionError<WideNulError<u32>>>;
fn to_string(&self) -> Result<Cow<str>, ConversionError<CNulError>>;
fn to_wcstr(&self) -> Result<Cow<WideCStr>, ConversionError<WideNulError<WideChar>>>;
}
trait CharElement { type Char; }
impl<U: UChar> CharElement for UCStr<U> { type Char = U; }
impl<U: UChar> CharElement for UCString<U> { type Char = U; }
impl UnivString for str
{
fn to_cstr(&self) -> Result<Cow<CStr>, ConversionError<CNulError>> { CString::new(self).map(Cow::Owned).map_err(Into::into) }
fn to_ucstr16(&self) -> Result<Cow<UCStr<u16>>, ConversionError<WideNulError<u16>>> { U16CString::from_str(self).map(Cow::Owned).map_err(Into::into) }
fn to_ucstr32(&self) -> Result<Cow<UCStr<u32>>, ConversionError<WideNulError<u32>>> { U32CString::from_str(self).map(Cow::Owned).map_err(Into::into) }
fn to_string(&self) -> Result<Cow<str>, ConversionError<CNulError>> { Ok(ToString::to_string(self).into()) }
fn to_wcstr(&self) -> Result<Cow<WideCStr>, ConversionError<WideNulError<WideChar>>> { WideCString::from_str(self).map(Cow::Owned).map_err(Into::into) }
}
impl UnivString for String
{
fn to_cstr(&self) -> Result<Cow<CStr>, ConversionError<CNulError>> { CString::new(self as &str).map(Cow::Owned).map_err(Into::into) }
fn to_ucstr16(&self) -> Result<Cow<UCStr<u16>>, ConversionError<WideNulError<u16>>> { U16CString::from_str(self).map(Cow::Owned).map_err(Into::into) }
fn to_ucstr32(&self) -> Result<Cow<UCStr<u32>>, ConversionError<WideNulError<u32>>> { U32CString::from_str(self).map(Cow::Owned).map_err(Into::into) }
fn to_string(&self) -> Result<Cow<str>, ConversionError<CNulError>> { Ok(ToString::to_string(self).into()) }
fn to_wcstr(&self) -> Result<Cow<WideCStr>, ConversionError<WideNulError<WideChar>>> { WideCString::from_str(self).map(Cow::Owned).map_err(Into::into) }
}
impl UnivString for CStr
{
fn to_cstr(&self) -> Result<Cow<CStr>, ConversionError<CNulError>> { Ok(Cow::Borrowed(self)) }
fn to_ucstr16(&self) -> Result<Cow<UCStr<u16>>, ConversionError<WideNulError<u16>>> { self.to_str()?.to_ucstr16() }
fn to_ucstr32(&self) -> Result<Cow<UCStr<u32>>, ConversionError<WideNulError<u32>>> { self.to_str()?.to_ucstr32() }
fn to_string(&self) -> Result<Cow<str>, ConversionError<CNulError>> { self.to_str().map(Cow::Borrowed).map_err(Into::into) }
fn to_wcstr(&self) -> Result<Cow<WideCStr>, ConversionError<WideNulError<WideChar>>> { self.to_str()?.to_wcstr() }
}
impl UnivString for CString
{
fn to_cstr(&self) -> Result<Cow<CStr>, ConversionError<CNulError>> { Ok(Cow::Borrowed(self)) }
fn to_ucstr16(&self) -> Result<Cow<UCStr<u16>>, ConversionError<WideNulError<u16>>> { self.to_str()?.to_ucstr16() }
fn to_ucstr32(&self) -> Result<Cow<UCStr<u32>>, ConversionError<WideNulError<u32>>> { self.to_str()?.to_ucstr32() }
fn to_string(&self) -> Result<Cow<str>, ConversionError<CNulError>> { self.to_str().map(Cow::Borrowed).map_err(Into::into) }
fn to_wcstr(&self) -> Result<Cow<WideCStr>, ConversionError<WideNulError<WideChar>>> { self.to_str()?.to_wcstr() }
}
impl UnivString for U16CStr
{
fn to_cstr(&self) -> Result<Cow<CStr>, ConversionError<CNulError>> { CString::new(self.to_string()?).map(Cow::Owned).map_err(Into::into) }
fn to_ucstr16(&self) -> Result<Cow<UCStr<u16>>, ConversionError<WideNulError<u16>>> { Ok(Cow::Borrowed(self)) }
fn to_ucstr32(&self) -> Result<Cow<UCStr<u32>>, ConversionError<WideNulError<u32>>> { U32CString::from_str(self.to_string()?).map(Into::into).map_err(From::from) }
fn to_string(&self) -> Result<Cow<str>, ConversionError<CNulError>> { self.to_string().map(Cow::Owned).map_err(Into::into) }
fn to_wcstr(&self) -> Result<Cow<WideCStr>, ConversionError<WideNulError<WideChar>>> {
if std::mem::size_of::<<WideCStr as CharElement>::Char>() == 2 {
Ok(Cow::Borrowed(unsafe { std::mem::transmute(self) }))
} else {
WideCString::from_str(self.to_string()?).map(Into::into).map_err(From::from)
}
}
}
impl UnivString for U16CString
{
fn to_cstr(&self) -> Result<Cow<CStr>, ConversionError<CNulError>> { CString::new(WideCStr::to_string(self)?).map(Cow::Owned).map_err(Into::into) }
fn to_ucstr16(&self) -> Result<Cow<UCStr<u16>>, ConversionError<WideNulError<u16>>> { Ok(Cow::Borrowed(self)) }
fn to_ucstr32(&self) -> Result<Cow<UCStr<u32>>, ConversionError<WideNulError<u32>>> { U16CStr::to_ucstr32(self) }
fn to_string(&self) -> Result<Cow<str>, ConversionError<CNulError>> { std::ops::Deref::deref(self).to_string().map(Into::into).map_err(Into::into) }
fn to_wcstr(&self) -> Result<Cow<WideCStr>, ConversionError<WideNulError<WideChar>>> {
if std::mem::size_of::<<WideCStr as CharElement>::Char>() == 2 {
Ok(Cow::Borrowed(unsafe { std::mem::transmute(self as &U16CStr) }))
} else {
U16CStr::to_wcstr(self)
}
}
}
impl UnivString for U32CStr
{
fn to_cstr(&self) -> Result<Cow<CStr>, ConversionError<CNulError>> { CString::new(self.to_string()?).map(Cow::Owned).map_err(Into::into) }
fn to_ucstr16(&self) -> Result<Cow<UCStr<u16>>, ConversionError<WideNulError<u16>>> { U16CString::from_str(self.to_string()?).map(Into::into).map_err(From::from) }
fn to_ucstr32(&self) -> Result<Cow<UCStr<u32>>, ConversionError<WideNulError<u32>>> { Ok(Cow::Borrowed(self)) }
fn to_string(&self) -> Result<Cow<str>, ConversionError<CNulError>> { self.to_string().map(Cow::Owned).map_err(Into::into) }
fn to_wcstr(&self) -> Result<Cow<WideCStr>, ConversionError<WideNulError<WideChar>>> {
if std::mem::size_of::<<WideCStr as CharElement>::Char>() == 4 {
Ok(Cow::Borrowed(unsafe { std::mem::transmute(self) }))
} else {
WideCString::from_str(self.to_string()?).map(Into::into).map_err(From::from)
}
}
}
impl UnivString for U32CString
{
fn to_cstr(&self) -> Result<Cow<CStr>, ConversionError<CNulError>> { CString::new(U32CStr::to_string(self)?).map(Cow::Owned).map_err(Into::into) }
fn to_ucstr16(&self) -> Result<Cow<UCStr<u16>>, ConversionError<WideNulError<u16>>> { U32CStr::to_ucstr16(self) }
fn to_ucstr32(&self) -> Result<Cow<UCStr<u32>>, ConversionError<WideNulError<u32>>> { Ok(Cow::Borrowed(self)) }
fn to_string(&self) -> Result<Cow<str>, ConversionError<CNulError>> { std::ops::Deref::deref(self).to_string().map(Into::into).map_err(Into::into) }
fn to_wcstr(&self) -> Result<Cow<WideCStr>, ConversionError<WideNulError<WideChar>>> {
if std::mem::size_of::<<WideCStr as CharElement>::Char>() == 4 {
Ok(Cow::Borrowed(unsafe { std::mem::transmute(self as &U32CStr) }))
} else {
U32CStr::to_wcstr(self)
}
}
}