use crate::{Bstr, Bytes, Result, Ustr};
use std::{
borrow::Borrow,
convert::TryFrom,
ffi::{CString, OsStr, OsString},
fmt,
fmt::{Debug, Formatter},
mem,
mem::MaybeUninit,
ops::{Deref, DerefMut},
os::unix::ffi::OsStringExt,
path::{Path, PathBuf},
slice,
};
#[derive(Eq, Ord, PartialOrd, PartialEq, Hash)]
pub struct Ustring {
bytes: Vec<u8>,
}
impl Ustring {
pub fn new() -> Ustring {
Ustring { bytes: Vec::new() }
}
fn init(&mut self) {
if self.bytes.is_empty() {
self.bytes.push(0);
}
}
pub fn reserve(&mut self, num: usize) {
self.init();
self.bytes.reserve(num);
}
pub fn reserve_exact(&mut self, additional: usize) {
self.init();
self.bytes.reserve_exact(additional);
}
pub fn capacity(&self) -> usize {
if self.bytes.is_empty() {
0
} else {
self.bytes.capacity() - 1
}
}
pub unsafe fn with_unused<F>(&mut self, f: F) -> Result<usize>
where
F: FnOnce(&mut [MaybeUninit<u8>]) -> Result<usize>,
{
let mut s = mem::replace(self, Ustring::new());
s.init();
let res = {
let bytes = slice::from_raw_parts_mut(
s.bytes.as_mut_ptr().add(s.bytes.len() - 1) as *mut _,
s.bytes.capacity() - s.bytes.len() + 1,
);
let len = bytes.len();
let res = f(&mut bytes[..len - 1]);
match res {
Ok(num) => {
bytes[num] = MaybeUninit::new(0);
s.bytes.set_len(s.bytes.len() + num);
}
_ => bytes[0] = MaybeUninit::new(0),
}
res
};
*self = s;
res
}
pub fn from_vec(mut s: Vec<u8>) -> Self {
if !s.is_empty() {
s.push(0);
}
Ustring { bytes: s }
}
pub unsafe fn from_vec_with_nul_unchecked(s: Vec<u8>) -> Self {
Ustring { bytes: s }
}
pub fn from_vec_with_nul(s: Vec<u8>) -> std::result::Result<Self, Vec<u8>> {
if !s.is_empty() && s[s.len() - 1] != 0 {
return Err(s);
}
Ok(Ustring { bytes: s })
}
pub fn into_vec(mut self) -> Vec<u8> {
if !self.bytes.is_empty() {
self.bytes.pop();
}
self.bytes
}
pub fn into_vec_with_nul(mut self) -> Vec<u8> {
self.init();
self.bytes
}
pub fn from_string(s: String) -> Self {
Self::from_vec(s.into_bytes())
}
pub fn from_string_with_nul(s: String) -> std::result::Result<Self, String> {
if !s.is_empty() && s.as_bytes()[s.len() - 1] != 0 {
return Err(s);
}
Ok(unsafe { Self::from_vec_with_nul_unchecked(s.into_bytes()) })
}
pub fn into_string(self) -> std::result::Result<String, Self> {
String::from_utf8(self.into_vec()).map_err(|e| Self::from_vec(e.into_bytes()))
}
pub fn into_string_with_nul(self) -> std::result::Result<String, Self> {
String::from_utf8(self.into_vec_with_nul())
.map_err(|e| Self::from_vec(e.into_bytes()))
}
pub fn from_c_string(s: CString) -> Self {
Self::from_vec(s.into_bytes())
}
pub fn into_c_string(self) -> std::result::Result<CString, (usize, Self)> {
CString::new(self.into_vec())
.map_err(|e| (e.nul_position(), Self::from_vec(e.into_vec())))
}
pub fn from_os_string(s: OsString) -> Self {
Self::from_vec(s.into_vec())
}
pub fn from_os_string_with_nul(s: OsString) -> std::result::Result<Self, OsString> {
Self::from_vec_with_nul(s.into_vec()).map_err(OsString::from_vec)
}
pub fn into_os_string(self) -> OsString {
OsString::from_vec(self.into_vec())
}
pub fn into_os_string_with_nul(self) -> OsString {
OsString::from_vec(self.into_vec_with_nul())
}
pub fn from_path_buf(s: PathBuf) -> Self {
Self::from_os_string(s.into_os_string())
}
pub fn from_path_buf_with_nul(s: PathBuf) -> std::result::Result<Self, PathBuf> {
Self::from_os_string_with_nul(s.into_os_string()).map_err(PathBuf::from)
}
pub fn into_path_buf(self) -> PathBuf {
PathBuf::from(self.into_os_string())
}
pub fn into_path_buf_with_nul(self) -> PathBuf {
PathBuf::from(self.into_os_string_with_nul())
}
pub fn push<T: Bytes + ?Sized>(&mut self, bytes: &T) {
let bytes = bytes.bytes();
if !bytes.is_empty() {
self.init();
self.bytes.reserve(bytes.len());
self.bytes.pop();
self.bytes.extend_from_slice(bytes);
self.bytes.push(0);
}
}
pub fn as_ustr(&self) -> &Ustr {
if self.bytes.is_empty() {
Ustr::empty()
} else {
unsafe { Ustr::from_bytes_unchecked(&self.bytes) }
}
}
pub fn as_ustr_mut(&mut self) -> &mut Ustr {
self.init();
unsafe { Ustr::from_bytes_unchecked_mut(&mut self.bytes) }
}
}
impl Default for Ustring {
fn default() -> Self {
Self::new()
}
}
impl Borrow<Ustr> for Ustring {
fn borrow(&self) -> &Ustr {
self.as_ustr()
}
}
impl Borrow<Bstr> for Ustring {
fn borrow(&self) -> &Bstr {
self.as_ustr().as_bstr()
}
}
impl From<String> for Ustring {
fn from(s: String) -> Self {
Ustring::from_string(s)
}
}
impl From<Vec<u8>> for Ustring {
fn from(s: Vec<u8>) -> Self {
Ustring::from_vec(s)
}
}
impl From<CString> for Ustring {
fn from(s: CString) -> Self {
Ustring::from_c_string(s)
}
}
impl From<OsString> for Ustring {
fn from(s: OsString) -> Self {
Ustring::from_os_string(s)
}
}
impl From<PathBuf> for Ustring {
fn from(s: PathBuf) -> Self {
Ustring::from_path_buf(s)
}
}
impl TryFrom<Ustring> for String {
type Error = Ustring;
fn try_from(value: Ustring) -> std::result::Result<Self, Self::Error> {
Ustring::into_string(value)
}
}
impl From<Ustring> for Vec<u8> {
fn from(s: Ustring) -> Self {
s.into_vec()
}
}
impl TryFrom<Ustring> for CString {
type Error = (usize, Ustring);
fn try_from(s: Ustring) -> std::result::Result<Self, Self::Error> {
s.into_c_string()
}
}
impl From<Ustring> for OsString {
fn from(s: Ustring) -> Self {
s.into_os_string()
}
}
impl From<Ustring> for PathBuf {
fn from(s: Ustring) -> Self {
s.into_path_buf()
}
}
impl AsRef<[u8]> for Ustring {
fn as_ref(&self) -> &[u8] {
self.deref().as_ref()
}
}
impl AsMut<[u8]> for Ustring {
fn as_mut(&mut self) -> &mut [u8] {
self.deref_mut().as_mut()
}
}
impl AsRef<OsStr> for Ustring {
fn as_ref(&self) -> &OsStr {
self.deref().as_ref()
}
}
impl AsRef<Path> for Ustring {
fn as_ref(&self) -> &Path {
self.deref().as_ref()
}
}
impl Deref for Ustring {
type Target = Ustr;
fn deref(&self) -> &Self::Target {
self.as_ustr()
}
}
impl DerefMut for Ustring {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_ustr_mut()
}
}
impl Debug for Ustring {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Debug::fmt(self.deref(), f)
}
}