use core::{
borrow::Borrow,
ffi::{c_char, CStr},
ops::{Deref, Index},
slice::SliceIndex,
};
use crate::cstr::Utf8CStr;
#[allow(unused_imports)]
use alloc::{
borrow::Cow,
boxed::Box,
ffi::{CString, FromVecWithNulError, IntoStringError, NulError},
rc::Rc,
string::FromUtf8Error,
string::String,
sync::Arc,
vec::Vec,
};
#[repr(transparent)]
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Utf8CString(CString);
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum FromOwnedUtf8WithNul {
Utf8(FromUtf8Error),
CString(FromVecWithNulError),
}
impl Utf8CString {
pub fn new(string: impl Into<String>) -> Result<Self, NulError> {
let cstring = CString::new(string.into())?;
Ok(unsafe { Self::from_cstring_unchecked(cstring) })
}
pub fn from_string_with_nul(string: impl Into<String>) -> Result<Self, NulError> {
let cstring = CString::new(string.into())?;
Ok(unsafe { Self::from_cstring_unchecked(cstring) })
}
pub fn from_utf8_with_nul(v: Vec<u8>) -> Result<Self, FromOwnedUtf8WithNul> {
let string = String::from_utf8(v)?;
let cstring = CString::from_vec_with_nul(string.into_bytes())?;
Ok(unsafe { Utf8CString::from_cstring_unchecked(cstring) })
}
#[must_use]
pub unsafe fn from_utf8_unchecked(v: Vec<u8>) -> Self {
unsafe {
let cstring = CString::from_vec_unchecked(v); Self::from_cstring_unchecked(cstring)
}
}
#[must_use]
pub unsafe fn from_utf8_with_nul_unchecked(v: Vec<u8>) -> Self {
unsafe {
let cstring = CString::from_vec_with_nul_unchecked(v); Self::from_cstring_unchecked(cstring)
}
}
#[must_use]
pub unsafe fn from_cstring_unchecked(cstring: CString) -> Self {
Utf8CString(cstring)
}
pub fn from_cstring(cstring: CString) -> Result<Self, IntoStringError> {
let string = cstring.into_string()?; Ok(unsafe { Self::from_utf8_unchecked(string.into_bytes()) })
}
#[must_use]
pub fn as_utf8_cstr(&self) -> &Utf8CStr {
unsafe { Utf8CStr::from_cstr_unchecked(self.0.as_c_str()) }
}
pub unsafe fn from_raw(ptr: *mut c_char) -> Self {
unsafe {
let cstring = CString::from_raw(ptr);
Self::from_cstring_unchecked(cstring)
}
}
#[must_use]
pub fn into_raw(self) -> *mut c_char {
self.0.into_raw()
}
#[must_use]
pub fn into_string(self) -> String {
unsafe { String::from_utf8_unchecked(self.0.into_bytes()) }
}
#[must_use]
pub fn into_string_with_nul(self) -> String {
unsafe { String::from_utf8_unchecked(self.0.into_bytes_with_nul()) }
}
#[must_use]
pub fn into_bytes(self) -> Vec<u8> {
self.0.into_bytes()
}
#[must_use]
pub fn into_bytes_with_nul(self) -> Vec<u8> {
self.0.into_bytes_with_nul()
}
#[must_use]
pub fn into_boxed_utf8_cstr(self) -> Box<Utf8CStr> {
unsafe { Box::from_raw(Box::into_raw(self.0.into_boxed_c_str()) as *mut Utf8CStr) }
}
}
impl Deref for Utf8CString {
type Target = Utf8CStr;
fn deref(&self) -> &Self::Target {
self.as_utf8_cstr()
}
}
impl AsRef<Utf8CStr> for Utf8CString {
fn as_ref(&self) -> &Utf8CStr {
self.as_utf8_cstr()
}
}
impl AsRef<str> for Utf8CString {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl AsRef<CStr> for Utf8CString {
fn as_ref(&self) -> &CStr {
self.as_c_str()
}
}
impl Borrow<Utf8CStr> for Utf8CString {
fn borrow(&self) -> &Utf8CStr {
self.as_utf8_cstr()
}
}
impl Borrow<CStr> for Utf8CString {
fn borrow(&self) -> &CStr {
self.as_c_str()
}
}
super::cmp_impls! {
impl Utf8CString {
CStr: Utf8CStr::as_c_str => core::convert::identity,
str: Utf8CStr::as_str => core::convert::identity,
&str: Utf8CStr::as_str => Deref::deref,
#[cfg(feature = "alloc")]
CString: Utf8CStr::as_c_str => CString::as_c_str,
#[cfg(feature = "alloc")]
String: Utf8CStr::as_str => String::as_str
}
}
impl<'a> From<&'a Utf8CString> for Cow<'a, Utf8CStr> {
fn from(value: &'a Utf8CString) -> Self {
Self::Borrowed(value.as_utf8_cstr())
}
}
impl<'a> From<Utf8CString> for Cow<'a, Utf8CStr> {
fn from(value: Utf8CString) -> Self {
Self::Owned(value)
}
}
impl From<Box<Utf8CStr>> for Utf8CString {
fn from(value: Box<Utf8CStr>) -> Self {
unsafe {
let cstr: Box<CStr> = Box::from_raw(Box::into_raw(value) as *mut CStr);
Self::from_cstring_unchecked(CString::from(cstr))
}
}
}
impl From<Utf8CString> for Arc<Utf8CStr> {
fn from(value: Utf8CString) -> Self {
unsafe {
let arc: Arc<CStr> = Arc::from(value.0);
Arc::from_raw(Arc::into_raw(arc) as *const Utf8CStr)
}
}
}
impl From<Utf8CString> for Rc<Utf8CStr> {
fn from(value: Utf8CString) -> Self {
unsafe {
let rc: Rc<CStr> = Rc::from(value.0);
Rc::from_raw(Rc::into_raw(rc) as *const Utf8CStr)
}
}
}
impl From<Utf8CString> for Box<Utf8CStr> {
fn from(value: Utf8CString) -> Self {
unsafe {
let b: Box<CStr> = Box::from(value.0);
Box::from_raw(Box::into_raw(b) as *mut Utf8CStr)
}
}
}
impl<I> Index<I> for Utf8CString
where
I: SliceIndex<str>,
{
type Output = I::Output;
fn index(&self, index: I) -> &Self::Output {
self.as_str().index(index)
}
}
impl core::fmt::Debug for Utf8CString {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.as_str_with_nul().fmt(f)
}
}
impl core::fmt::Display for Utf8CString {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.as_str().fmt(f)
}
}
impl Default for Utf8CString {
fn default() -> Self {
<&Utf8CStr>::default().to_cstring()
}
}
impl core::fmt::Display for FromOwnedUtf8WithNul {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
FromOwnedUtf8WithNul::Utf8(e) => e.fmt(f),
FromOwnedUtf8WithNul::CString(e) => e.fmt(f),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for FromOwnedUtf8WithNul {}
impl From<FromUtf8Error> for FromOwnedUtf8WithNul {
fn from(value: FromUtf8Error) -> Self {
Self::Utf8(value)
}
}
impl From<FromVecWithNulError> for FromOwnedUtf8WithNul {
fn from(value: FromVecWithNulError) -> Self {
Self::CString(value)
}
}