#![allow(unsafe_code)]
#![deny(unsafe_op_in_unsafe_fn)]
use super::strlen;
use crate::io;
use alloc::borrow::{Cow, ToOwned};
use alloc::boxed::Box;
use alloc::rc::Rc;
use alloc::string::String;
use alloc::sync::Arc;
use alloc::vec::Vec;
use core::ascii;
use core::borrow::Borrow;
use core::cmp::Ordering;
use core::fmt::{self, Write};
use core::mem;
#[cfg(vec_into_raw_parts)]
use core::num::NonZeroU8;
use core::ops;
use core::ptr;
use core::slice;
#[cfg(slice_internals)]
use core::slice::memchr::memchr;
use core::str::{self, Utf8Error};
#[cfg(not(slice_internals))]
fn memchr(x: u8, text: &[u8]) -> Option<usize> {
text.iter().position(|elt| *elt == x)
}
#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone)]
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
pub struct ZString {
inner: Box<[u8]>,
}
#[derive(Hash)]
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
pub struct ZStr {
inner: [u8],
}
#[derive(Clone, PartialEq, Eq, Debug)]
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
pub struct NulError(usize, Vec<u8>);
#[derive(Clone, PartialEq, Eq, Debug)]
#[cfg_attr(staged_api, stable(feature = "cstr_from_bytes", since = "1.10.0"))]
pub struct FromBytesWithNulError {
kind: FromBytesWithNulErrorKind,
}
#[derive(Clone, PartialEq, Eq, Debug)]
#[cfg_attr(
staged_api,
stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")
)]
pub struct FromVecWithNulError {
error_kind: FromBytesWithNulErrorKind,
bytes: Vec<u8>,
}
#[derive(Clone, PartialEq, Eq, Debug)]
enum FromBytesWithNulErrorKind {
InteriorNul(usize),
NotNulTerminated,
}
impl FromBytesWithNulError {
fn interior_nul(pos: usize) -> FromBytesWithNulError {
FromBytesWithNulError {
kind: FromBytesWithNulErrorKind::InteriorNul(pos),
}
}
fn not_nul_terminated() -> FromBytesWithNulError {
FromBytesWithNulError {
kind: FromBytesWithNulErrorKind::NotNulTerminated,
}
}
}
#[cfg_attr(
staged_api,
stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")
)]
impl FromVecWithNulError {
#[must_use]
#[cfg_attr(
staged_api,
stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")
)]
pub fn as_bytes(&self) -> &[u8] {
&self.bytes[..]
}
#[must_use = "`self` will be dropped if the result is not used"]
#[cfg_attr(
staged_api,
stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")
)]
pub fn into_bytes(self) -> Vec<u8> {
self.bytes
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
#[cfg_attr(staged_api, stable(feature = "cstring_into", since = "1.7.0"))]
pub struct IntoStringError {
inner: ZString,
error: Utf8Error,
}
impl ZString {
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
pub fn new<T: Into<Vec<u8>>>(t: T) -> Result<ZString, NulError> {
trait SpecIntoVec {
fn into_vec(self) -> Vec<u8>;
}
#[cfg(not(specialization))]
impl<T: Into<Vec<u8>>> SpecIntoVec for T {
fn into_vec(self) -> Vec<u8> {
self.into()
}
}
#[cfg(specialization)]
impl<T: Into<Vec<u8>>> SpecIntoVec for T {
default fn into_vec(self) -> Vec<u8> {
self.into()
}
}
#[cfg(specialization)]
impl SpecIntoVec for &'_ [u8] {
fn into_vec(self) -> Vec<u8> {
let mut v = Vec::with_capacity(self.len() + 1);
v.extend(self);
v
}
}
#[cfg(specialization)]
impl SpecIntoVec for &'_ str {
fn into_vec(self) -> Vec<u8> {
let mut v = Vec::with_capacity(self.len() + 1);
v.extend(self.as_bytes());
v
}
}
Self::_new(SpecIntoVec::into_vec(t))
}
fn _new(bytes: Vec<u8>) -> Result<ZString, NulError> {
match memchr(b'\0', &bytes) {
Some(i) => Err(NulError(i, bytes)),
None => Ok(unsafe { ZString::from_vec_unchecked(bytes) }),
}
}
#[must_use]
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
pub unsafe fn from_vec_unchecked(mut v: Vec<u8>) -> ZString {
v.reserve_exact(1);
v.push(b'\0');
ZString {
inner: v.into_boxed_slice(),
}
}
#[must_use = "call `drop(from_raw(ptr))` if you intend to drop the `ZString`"]
#[cfg_attr(staged_api, stable(feature = "cstr_memory", since = "1.4.0"))]
pub unsafe fn from_raw(ptr: *mut u8) -> ZString {
unsafe {
let len = strlen(ptr) + 1; let slice = slice::from_raw_parts_mut(ptr, len as usize);
ZString {
inner: Box::from_raw(slice as *mut [u8]),
}
}
}
#[inline]
#[must_use = "`self` will be dropped if the result is not used"]
#[cfg_attr(staged_api, stable(feature = "cstr_memory", since = "1.4.0"))]
pub fn into_raw(self) -> *mut u8 {
Box::into_raw(self.into_inner()) as *mut u8
}
#[cfg_attr(staged_api, stable(feature = "cstring_into", since = "1.7.0"))]
pub fn into_string(self) -> Result<String, IntoStringError> {
String::from_utf8(self.into_bytes()).map_err(|e| IntoStringError {
error: e.utf8_error(),
inner: unsafe { ZString::from_vec_unchecked(e.into_bytes()) },
})
}
#[must_use = "`self` will be dropped if the result is not used"]
#[cfg_attr(staged_api, stable(feature = "cstring_into", since = "1.7.0"))]
pub fn into_bytes(self) -> Vec<u8> {
let mut vec = self.into_inner().into_vec();
let _nul = vec.pop();
debug_assert_eq!(_nul, Some(0u8));
vec
}
#[must_use = "`self` will be dropped if the result is not used"]
#[cfg_attr(staged_api, stable(feature = "cstring_into", since = "1.7.0"))]
pub fn into_bytes_with_nul(self) -> Vec<u8> {
self.into_inner().into_vec()
}
#[inline]
#[must_use]
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
pub fn as_bytes(&self) -> &[u8] {
unsafe { self.inner.get_unchecked(..self.inner.len() - 1) }
}
#[inline]
#[must_use]
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
pub fn as_bytes_with_nul(&self) -> &[u8] {
&self.inner
}
#[inline]
#[must_use]
#[cfg_attr(staged_api, stable(feature = "as_c_str", since = "1.20.0"))]
pub fn as_z_str(&self) -> &ZStr {
&*self
}
#[cfg(not(feature = "rustc-dep-of-std"))]
#[inline]
#[must_use]
#[cfg_attr(staged_api, stable(feature = "as_c_str", since = "1.20.0"))]
pub fn as_c_str(&self) -> &ZStr {
self.as_z_str()
}
#[must_use = "`self` will be dropped if the result is not used"]
#[cfg_attr(staged_api, stable(feature = "into_boxed_c_str", since = "1.20.0"))]
pub fn into_boxed_z_str(self) -> Box<ZStr> {
unsafe { Box::from_raw(Box::into_raw(self.into_inner()) as *mut ZStr) }
}
#[cfg(feature = "std")]
#[must_use = "`self` will be dropped if the result is not used"]
#[cfg_attr(staged_api, stable(feature = "into_boxed_c_str", since = "1.20.0"))]
pub fn into_boxed_c_str(self) -> Box<CStr> {
self.into_boxed_z_str()
}
#[inline]
fn into_inner(self) -> Box<[u8]> {
let this = mem::ManuallyDrop::new(self);
unsafe { ptr::read(&this.inner) }
}
#[must_use]
#[cfg_attr(
staged_api,
stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")
)]
pub unsafe fn from_vec_with_nul_unchecked(v: Vec<u8>) -> Self {
Self {
inner: v.into_boxed_slice(),
}
}
#[cfg_attr(
staged_api,
stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")
)]
pub fn from_vec_with_nul(v: Vec<u8>) -> Result<Self, FromVecWithNulError> {
let nul_pos = memchr(b'\0', &v);
match nul_pos {
Some(nul_pos) if nul_pos + 1 == v.len() => {
Ok(unsafe { Self::from_vec_with_nul_unchecked(v) })
}
Some(nul_pos) => Err(FromVecWithNulError {
error_kind: FromBytesWithNulErrorKind::InteriorNul(nul_pos),
bytes: v,
}),
None => Err(FromVecWithNulError {
error_kind: FromBytesWithNulErrorKind::NotNulTerminated,
bytes: v,
}),
}
}
}
#[cfg_attr(staged_api, stable(feature = "cstring_drop", since = "1.13.0"))]
impl Drop for ZString {
#[inline]
fn drop(&mut self) {
unsafe {
*self.inner.get_unchecked_mut(0) = 0;
}
}
}
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
impl ops::Deref for ZString {
type Target = ZStr;
#[inline]
fn deref(&self) -> &ZStr {
unsafe { ZStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) }
}
}
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
impl fmt::Debug for ZString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
#[cfg_attr(staged_api, stable(feature = "cstring_into", since = "1.7.0"))]
impl From<ZString> for Vec<u8> {
#[inline]
fn from(s: ZString) -> Vec<u8> {
s.into_bytes()
}
}
#[cfg_attr(staged_api, stable(feature = "cstr_debug", since = "1.3.0"))]
impl fmt::Debug for ZStr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "\"")?;
for byte in self
.to_bytes()
.iter()
.flat_map(|&b| ascii::escape_default(b))
{
f.write_char(byte as char)?;
}
write!(f, "\"")
}
}
#[cfg_attr(staged_api, stable(feature = "cstr_default", since = "1.10.0"))]
impl Default for &ZStr {
fn default() -> Self {
const SLICE: &[u8] = &[0];
unsafe { ZStr::from_ptr(SLICE.as_ptr()) }
}
}
#[cfg_attr(staged_api, stable(feature = "cstr_default", since = "1.10.0"))]
impl Default for ZString {
fn default() -> ZString {
let a: &ZStr = Default::default();
a.to_owned()
}
}
#[cfg_attr(staged_api, stable(feature = "cstr_borrow", since = "1.3.0"))]
impl Borrow<ZStr> for ZString {
#[inline]
fn borrow(&self) -> &ZStr {
self
}
}
#[cfg_attr(
staged_api,
stable(feature = "cstring_from_cow_cstr", since = "1.28.0")
)]
impl<'a> From<Cow<'a, ZStr>> for ZString {
#[inline]
fn from(s: Cow<'a, ZStr>) -> Self {
s.into_owned()
}
}
#[cfg_attr(staged_api, stable(feature = "box_from_c_str", since = "1.17.0"))]
impl From<&ZStr> for Box<ZStr> {
fn from(s: &ZStr) -> Box<ZStr> {
let boxed: Box<[u8]> = Box::from(s.to_bytes_with_nul());
unsafe { Box::from_raw(Box::into_raw(boxed) as *mut ZStr) }
}
}
#[cfg_attr(staged_api, stable(feature = "box_from_cow", since = "1.45.0"))]
impl From<Cow<'_, ZStr>> for Box<ZStr> {
#[inline]
fn from(cow: Cow<'_, ZStr>) -> Box<ZStr> {
match cow {
Cow::Borrowed(s) => Box::from(s),
Cow::Owned(s) => Box::from(s),
}
}
}
#[cfg_attr(staged_api, stable(feature = "c_string_from_box", since = "1.18.0"))]
impl From<Box<ZStr>> for ZString {
#[inline]
fn from(s: Box<ZStr>) -> ZString {
s.into_z_string()
}
}
#[cfg(vec_into_raw_parts)]
#[cfg_attr(
staged_api,
stable(feature = "cstring_from_vec_of_nonzerou8", since = "1.43.0")
)]
impl From<Vec<NonZeroU8>> for ZString {
#[inline]
fn from(v: Vec<NonZeroU8>) -> ZString {
unsafe {
let v: Vec<u8> = {
let (ptr, len, cap): (*mut NonZeroU8, _, _) = Vec::into_raw_parts(v);
Vec::from_raw_parts(ptr.cast::<u8>(), len, cap)
};
ZString::from_vec_unchecked(v)
}
}
}
#[cfg_attr(staged_api, stable(feature = "more_box_slice_clone", since = "1.29.0"))]
impl Clone for Box<ZStr> {
#[inline]
fn clone(&self) -> Self {
(**self).into()
}
}
#[cfg_attr(staged_api, stable(feature = "box_from_c_string", since = "1.20.0"))]
impl From<ZString> for Box<ZStr> {
#[inline]
fn from(s: ZString) -> Box<ZStr> {
s.into_boxed_z_str()
}
}
#[cfg_attr(staged_api, stable(feature = "cow_from_cstr", since = "1.28.0"))]
impl<'a> From<ZString> for Cow<'a, ZStr> {
#[inline]
fn from(s: ZString) -> Cow<'a, ZStr> {
Cow::Owned(s)
}
}
#[cfg_attr(staged_api, stable(feature = "cow_from_cstr", since = "1.28.0"))]
impl<'a> From<&'a ZStr> for Cow<'a, ZStr> {
#[inline]
fn from(s: &'a ZStr) -> Cow<'a, ZStr> {
Cow::Borrowed(s)
}
}
#[cfg_attr(staged_api, stable(feature = "cow_from_cstr", since = "1.28.0"))]
impl<'a> From<&'a ZString> for Cow<'a, ZStr> {
#[inline]
fn from(s: &'a ZString) -> Cow<'a, ZStr> {
Cow::Borrowed(s.as_z_str())
}
}
#[cfg_attr(staged_api, stable(feature = "shared_from_slice2", since = "1.24.0"))]
impl From<ZString> for Arc<ZStr> {
#[inline]
fn from(s: ZString) -> Arc<ZStr> {
let arc: Arc<[u8]> = Arc::from(s.into_inner());
unsafe { Arc::from_raw(Arc::into_raw(arc) as *const ZStr) }
}
}
#[cfg_attr(staged_api, stable(feature = "shared_from_slice2", since = "1.24.0"))]
impl From<&ZStr> for Arc<ZStr> {
#[inline]
fn from(s: &ZStr) -> Arc<ZStr> {
let arc: Arc<[u8]> = Arc::from(s.to_bytes_with_nul());
unsafe { Arc::from_raw(Arc::into_raw(arc) as *const ZStr) }
}
}
#[cfg_attr(staged_api, stable(feature = "shared_from_slice2", since = "1.24.0"))]
impl From<ZString> for Rc<ZStr> {
#[inline]
fn from(s: ZString) -> Rc<ZStr> {
let rc: Rc<[u8]> = Rc::from(s.into_inner());
unsafe { Rc::from_raw(Rc::into_raw(rc) as *const ZStr) }
}
}
#[cfg_attr(staged_api, stable(feature = "shared_from_slice2", since = "1.24.0"))]
impl From<&ZStr> for Rc<ZStr> {
#[inline]
fn from(s: &ZStr) -> Rc<ZStr> {
let rc: Rc<[u8]> = Rc::from(s.to_bytes_with_nul());
unsafe { Rc::from_raw(Rc::into_raw(rc) as *const ZStr) }
}
}
#[cfg_attr(staged_api, stable(feature = "default_box_extra", since = "1.17.0"))]
impl Default for Box<ZStr> {
fn default() -> Box<ZStr> {
let boxed: Box<[u8]> = Box::from([0]);
unsafe { Box::from_raw(Box::into_raw(boxed) as *mut ZStr) }
}
}
impl NulError {
#[must_use]
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
pub fn nul_position(&self) -> usize {
self.0
}
#[must_use = "`self` will be dropped if the result is not used"]
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
pub fn into_vec(self) -> Vec<u8> {
self.1
}
}
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
impl NulError {
#[allow(deprecated)]
pub fn description(&self) -> &str {
"nul byte found in data"
}
}
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
impl fmt::Display for NulError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "nul byte found in provided data at position: {}", self.0)
}
}
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
impl From<NulError> for io::Error {
fn from(_: NulError) -> io::Error {
io::Error::INVAL
}
}
#[cfg_attr(
staged_api,
stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")
)]
impl FromBytesWithNulError {
#[allow(deprecated)]
pub fn description(&self) -> &str {
match self.kind {
FromBytesWithNulErrorKind::InteriorNul(..) => {
"data provided contains an interior nul byte"
}
FromBytesWithNulErrorKind::NotNulTerminated => "data provided is not nul terminated",
}
}
}
#[cfg_attr(
staged_api,
stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")
)]
impl fmt::Display for FromBytesWithNulError {
#[allow(deprecated, deprecated_in_future)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.description())?;
if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind {
write!(f, " at byte pos {}", pos)?;
}
Ok(())
}
}
#[cfg_attr(
staged_api,
stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")
)]
impl fmt::Display for FromVecWithNulError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.error_kind {
FromBytesWithNulErrorKind::InteriorNul(pos) => {
write!(
f,
"data provided contains an interior nul byte at pos {}",
pos
)
}
FromBytesWithNulErrorKind::NotNulTerminated => {
write!(f, "data provided is not nul terminated")
}
}
}
}
impl IntoStringError {
#[must_use = "`self` will be dropped if the result is not used"]
#[cfg_attr(staged_api, stable(feature = "cstring_into", since = "1.7.0"))]
pub fn into_zstring(self) -> ZString {
self.inner
}
#[cfg(feature = "std")]
#[must_use = "`self` will be dropped if the result is not used"]
#[cfg_attr(staged_api, stable(feature = "cstring_into", since = "1.7.0"))]
pub fn into_cstring(self) -> CString {
self.into_zstring()
}
#[must_use]
#[cfg_attr(staged_api, stable(feature = "cstring_into", since = "1.7.0"))]
pub fn utf8_error(&self) -> Utf8Error {
self.error
}
}
#[cfg_attr(staged_api, stable(feature = "cstring_into", since = "1.7.0"))]
impl IntoStringError {
#[allow(deprecated)]
pub fn description(&self) -> &str {
"C string contained non-utf8 bytes"
}
}
#[cfg_attr(staged_api, stable(feature = "cstring_into", since = "1.7.0"))]
impl fmt::Display for IntoStringError {
#[allow(deprecated, deprecated_in_future)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.description().fmt(f)
}
}
impl ZStr {
#[inline]
#[must_use]
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
pub unsafe fn from_ptr<'a>(ptr: *const u8) -> &'a ZStr {
unsafe {
let len = strlen(ptr);
ZStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1))
}
}
#[cfg_attr(staged_api, stable(feature = "cstr_from_bytes", since = "1.10.0"))]
pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&ZStr, FromBytesWithNulError> {
let nul_pos = memchr(b'\0', bytes);
if let Some(nul_pos) = nul_pos {
if nul_pos + 1 != bytes.len() {
return Err(FromBytesWithNulError::interior_nul(nul_pos));
}
Ok(unsafe { ZStr::from_bytes_with_nul_unchecked(bytes) })
} else {
Err(FromBytesWithNulError::not_nul_terminated())
}
}
#[cfg(const_raw_ptr_deref)]
#[inline]
#[must_use]
#[cfg_attr(staged_api, stable(feature = "cstr_from_bytes", since = "1.10.0"))]
#[cfg_attr(
staged_api,
rustc_const_unstable(feature = "const_cstr_unchecked", issue = "90343")
)]
pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &ZStr {
unsafe { &*(bytes as *const [u8] as *const ZStr) }
}
#[cfg(not(const_raw_ptr_deref))]
#[inline]
#[must_use]
#[cfg_attr(staged_api, stable(feature = "cstr_from_bytes", since = "1.10.0"))]
#[cfg_attr(
staged_api,
rustc_const_unstable(feature = "const_cstr_unchecked", issue = "90343")
)]
pub unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &ZStr {
unsafe { &*(bytes as *const [u8] as *const ZStr) }
}
#[inline]
#[must_use]
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_str_as_ptr", since = "1.32.0")
)]
pub const fn as_ptr(&self) -> *const u8 {
self.inner.as_ptr()
}
#[inline]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
pub fn to_bytes(&self) -> &[u8] {
let bytes = self.to_bytes_with_nul();
unsafe { bytes.get_unchecked(..bytes.len() - 1) }
}
#[inline]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
pub fn to_bytes_with_nul(&self) -> &[u8] {
unsafe { &*(&self.inner as *const [u8]) }
}
#[cfg_attr(staged_api, stable(feature = "cstr_to_str", since = "1.4.0"))]
pub fn to_str(&self) -> Result<&str, str::Utf8Error> {
str::from_utf8(self.to_bytes())
}
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[cfg_attr(staged_api, stable(feature = "cstr_to_str", since = "1.4.0"))]
pub fn to_string_lossy(&self) -> Cow<'_, str> {
String::from_utf8_lossy(self.to_bytes())
}
#[must_use = "`self` will be dropped if the result is not used"]
#[cfg_attr(staged_api, stable(feature = "into_boxed_c_str", since = "1.20.0"))]
pub fn into_z_string(self: Box<ZStr>) -> ZString {
let raw = Box::into_raw(self) as *mut [u8];
ZString {
inner: unsafe { Box::from_raw(raw) },
}
}
#[cfg(feature = "std")]
#[must_use = "`self` will be dropped if the result is not used"]
#[cfg_attr(staged_api, stable(feature = "into_boxed_c_str", since = "1.20.0"))]
pub fn into_c_string(self: Box<ZStr>) -> CString {
self.into_z_string()
}
}
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
impl PartialEq for ZStr {
fn eq(&self, other: &ZStr) -> bool {
self.to_bytes().eq(other.to_bytes())
}
}
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
impl Eq for ZStr {}
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
impl PartialOrd for ZStr {
fn partial_cmp(&self, other: &ZStr) -> Option<Ordering> {
self.to_bytes().partial_cmp(&other.to_bytes())
}
}
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
impl Ord for ZStr {
fn cmp(&self, other: &ZStr) -> Ordering {
self.to_bytes().cmp(&other.to_bytes())
}
}
#[cfg_attr(staged_api, stable(feature = "cstr_borrow", since = "1.3.0"))]
impl ToOwned for ZStr {
type Owned = ZString;
fn to_owned(&self) -> ZString {
ZString {
inner: self.to_bytes_with_nul().into(),
}
}
#[cfg(toowned_clone_into)]
fn clone_into(&self, target: &mut ZString) {
let mut b = Vec::from(mem::take(&mut target.inner));
self.to_bytes_with_nul().clone_into(&mut b);
target.inner = b.into_boxed_slice();
}
}
#[cfg_attr(staged_api, stable(feature = "cstring_asref", since = "1.7.0"))]
impl From<&ZStr> for ZString {
fn from(s: &ZStr) -> ZString {
s.to_owned()
}
}
#[cfg_attr(staged_api, stable(feature = "cstring_asref", since = "1.7.0"))]
impl ops::Index<ops::RangeFull> for ZString {
type Output = ZStr;
#[inline]
fn index(&self, _index: ops::RangeFull) -> &ZStr {
self
}
}
#[cfg_attr(staged_api, stable(feature = "cstr_range_from", since = "1.47.0"))]
impl ops::Index<ops::RangeFrom<usize>> for ZStr {
type Output = ZStr;
fn index(&self, index: ops::RangeFrom<usize>) -> &ZStr {
let bytes = self.to_bytes_with_nul();
if index.start < bytes.len() {
unsafe { ZStr::from_bytes_with_nul_unchecked(&bytes[index.start..]) }
} else {
panic!(
"index out of bounds: the len is {} but the index is {}",
bytes.len(),
index.start
);
}
}
}
#[cfg_attr(staged_api, stable(feature = "cstring_asref", since = "1.7.0"))]
impl AsRef<ZStr> for ZStr {
#[inline]
fn as_ref(&self) -> &ZStr {
self
}
}
#[cfg_attr(staged_api, stable(feature = "cstring_asref", since = "1.7.0"))]
impl AsRef<ZStr> for ZString {
#[inline]
fn as_ref(&self) -> &ZStr {
self
}
}