use crate::{
__lib::{cmp::Ordering, fmt::Write, slice},
*,
};
#[cfg(feature = "std")]
use crate::convert::*;
macro_rules! str_impl_debug {
($x:ident) => {
impl fmt::Debug for $x {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_char('"')?;
#[cfg(not(feature = "std"))]
{
fmt::Debug::fmt(&self.to_bytes_with_nul(), f)?;
}
#[cfg(feature = "std")]
{
fmt::Display::fmt(&self.to_string_lossy(), f)?;
}
f.write_char('"')
}
}
};
}
#[repr(C)]
pub struct WStr {
inner: [wchar_t],
}
impl WStr {
#[inline]
pub fn as_ptr(&self) -> *const wchar_t { self.inner.as_ptr() }
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut wchar_t { self.inner.as_mut_ptr() }
#[inline]
pub fn len(&self) -> usize { size_of_val(&self.inner) }
#[inline]
pub fn is_empty(&self) -> bool { self.len() == 0 }
#[inline]
pub fn to_bytes_with_nul(&self) -> &[u16] { &self.inner }
pub fn to_bytes(&self) -> &[u16] {
let bytes = self.to_bytes_with_nul();
&bytes[..bytes.len() - 1]
}
#[inline]
pub fn to_u8_bytes_with_nul(&self) -> &[u8] {
unsafe {
slice::from_raw_parts(
self.inner.as_ptr() as *const u8,
self.inner.len() * 2,
)
}
}
pub fn to_u8_bytes(&self) -> &[u8] {
let bytes = self.to_u8_bytes_with_nul();
&bytes[..bytes.len() - 2]
}
#[cfg(feature = "std")]
pub fn try_to_string(&self) -> ConvertResult<String> {
unsafe {
let mut mb = wide_to_utf8(self.to_bytes_with_nul())
.map_err(conv_err!(@utf8))?;
mb.set_len(mb.len() - 1); Ok(String::from_utf8_unchecked(mb))
}
}
#[cfg(feature = "std")]
pub fn to_string_lossy(&self) -> String {
unsafe {
let mut mb = wide_to_utf8_lossy(self.to_bytes_with_nul())
.map_err(conv_err!(@utf8))
.unwrap();
mb.set_len(mb.len() - 1); String::from_utf8_unchecked(mb)
}
}
#[cfg(feature = "std")]
pub fn to_wstring(&self) -> WString {
unsafe { WString::new_nul_unchecked(&self.inner) }
}
#[cfg(feature = "std")]
pub fn to_astring(&self) -> ConvertResult<AString> {
let mb =
wide_to_mb(self.to_bytes_with_nul()).map_err(conv_err!(@ansi))?;
unsafe { Ok(AString::new_unchecked(mb)) }
}
#[cfg(feature = "std")]
pub fn to_astring_lossy(&self) -> AString {
let mb = wide_to_mb_lossy(self.to_bytes_with_nul()).unwrap();
unsafe { AString::new_unchecked(mb) }
}
#[inline]
pub unsafe fn from_bytes_with_nul_unchecked(bytes: &[u16]) -> &Self {
unsafe { &*(bytes as *const [u16] as *const Self) }
}
#[inline]
pub unsafe fn from_bytes_with_nul_unchecked_mut(
bytes: &mut [u16],
) -> &mut Self {
unsafe { &mut *(bytes as *mut [u16] as *mut Self) }
}
pub unsafe fn from_raw<'a>(ptr: *const wchar_t) -> &'a Self {
unsafe { Self::from_raw_s_unchecked(ptr, wcslen(ptr)) }
}
pub unsafe fn from_raw_s<'a>(
ptr: *const wchar_t,
mut len: usize,
) -> &'a Self {
unsafe {
let len2 = wcsnlen(ptr, len);
if len2 < len {
len = len2;
}
Self::from_raw_s_unchecked(ptr, len)
}
}
#[inline]
pub unsafe fn from_raw_s_unchecked<'a>(
ptr: *const wchar_t,
len: usize,
) -> &'a Self {
unsafe {
let slice = slice::from_raw_parts(ptr, len + 1);
Self::from_bytes_with_nul_unchecked(slice)
}
}
}
impl PartialEq for WStr {
fn eq(&self, other: &Self) -> bool { self.to_bytes().eq(other.to_bytes()) }
}
impl Eq for WStr {}
impl PartialOrd for WStr {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for WStr {
fn cmp(&self, other: &Self) -> Ordering {
self.to_bytes().cmp(other.to_bytes())
}
}
#[repr(C)]
pub struct AStr {
inner: [u8],
}
impl AStr {
#[inline]
pub fn as_ptr(&self) -> *const i8 { self.inner.as_ptr() as *const i8 }
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut i8 {
self.inner.as_mut_ptr() as *mut i8
}
#[inline]
pub fn as_u8_ptr(&self) -> *const u8 { self.inner.as_ptr() }
#[inline]
pub fn as_mut_u8_ptr(&mut self) -> *mut u8 { self.inner.as_mut_ptr() }
#[inline]
pub fn len(&self) -> usize { self.inner.len() }
#[inline]
pub fn is_empty(&self) -> bool { self.len() == 0 }
#[inline]
pub fn to_bytes_with_nul(&self) -> &[u8] { &self.inner }
#[inline]
pub fn to_bytes(&self) -> &[u8] {
let bytes = self.to_bytes_with_nul();
&bytes[..bytes.len() - 1]
}
#[cfg(feature = "std")]
pub fn try_to_string(&self) -> ConvertResult<String> {
self.to_wstring()?.try_to_string()
}
#[cfg(feature = "std")]
pub fn to_string_lossy(&self) -> String {
self.to_wstring_lossy().to_string_lossy()
}
#[cfg(feature = "std")]
pub fn to_astring(&self) -> AString {
unsafe { AString::new_nul_unchecked(&self.inner) }
}
#[cfg(feature = "std")]
pub fn to_wstring(&self) -> ConvertResult<WString> {
let wc = mb_to_wide(self.to_bytes()).map_err(conv_err!(@unicode))?;
unsafe { Ok(WString::_new(wc)) }
}
#[cfg(feature = "std")]
pub fn to_wstring_lossy(&self) -> WString {
let wc = mb_to_wide_lossy(self.to_bytes())
.map_err(conv_err!(@unicode))
.unwrap();
unsafe { WString::_new(wc) }
}
#[inline]
pub unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &Self {
unsafe { &*(bytes as *const [u8] as *const Self) }
}
#[inline]
pub unsafe fn from_bytes_with_nul_unchecked_mut(
bytes: &mut [u8],
) -> &mut Self {
unsafe { &mut *(bytes as *mut [u8] as *mut Self) }
}
pub unsafe fn from_raw<'a>(ptr: *const u8) -> &'a Self {
unsafe { Self::from_raw_s_unchecked(ptr, strlen(ptr)) }
}
pub unsafe fn from_raw_s<'a>(ptr: *const u8, mut len: usize) -> &'a Self {
unsafe {
let len2 = strnlen(ptr, len);
if len2 < len {
len = len2;
}
Self::from_raw_s_unchecked(ptr, len)
}
}
#[inline]
pub unsafe fn from_raw_s_unchecked<'a>(
ptr: *const u8,
len: usize,
) -> &'a Self {
unsafe {
let slice = slice::from_raw_parts(ptr, len + 1);
Self::from_bytes_with_nul_unchecked(slice)
}
}
}
impl PartialEq for AStr {
fn eq(&self, other: &Self) -> bool { self.to_bytes().eq(other.to_bytes()) }
}
impl Eq for AStr {}
impl PartialOrd for AStr {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for AStr {
fn cmp(&self, other: &Self) -> Ordering {
self.to_bytes().cmp(other.to_bytes())
}
}
str_impl_debug!(WStr);
str_impl_debug!(AStr);