use super::platform;
use super::{FromUtf32Error, UChar, UStr, UString};
use std;
use std::ffi::{OsStr, OsString};
use std::mem;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UCString<C: UChar> {
inner: Box<[C]>,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UCStr<C: UChar> {
inner: [C],
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct NulError<C: UChar>(usize, Vec<C>);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MissingNulError<C>(Option<Vec<C>>);
impl<C: UChar> UCString<C> {
pub fn new(v: impl Into<Vec<C>>) -> Result<Self, NulError<C>> {
let v = v.into();
match v.iter().position(|&val| val == UChar::NUL) {
None => Ok(unsafe { UCString::from_vec_unchecked(v) }),
Some(pos) => Err(NulError(pos, v)),
}
}
pub fn from_vec_with_nul(v: impl Into<Vec<C>>) -> Result<Self, MissingNulError<C>> {
let mut v = v.into();
match v.iter().position(|&val| val == UChar::NUL) {
None => Err(MissingNulError(Some(v))),
Some(pos) => {
v.truncate(pos + 1);
Ok(unsafe { UCString::from_vec_with_nul_unchecked(v) })
}
}
}
pub unsafe fn from_vec_unchecked(v: impl Into<Vec<C>>) -> Self {
let mut v = v.into();
match v.last() {
None => v.push(UChar::NUL),
Some(&c) if c != UChar::NUL => v.push(UChar::NUL),
Some(_) => (),
}
UCString::from_vec_with_nul_unchecked(v)
}
pub unsafe fn from_vec_with_nul_unchecked(v: impl Into<Vec<C>>) -> Self {
UCString {
inner: v.into().into_boxed_slice(),
}
}
pub fn from_ustr(s: impl AsRef<UStr<C>>) -> Result<Self, NulError<C>> {
UCString::new(s.as_ref().as_slice())
}
pub unsafe fn from_ustr_unchecked(s: impl AsRef<UStr<C>>) -> Self {
UCString::from_vec_unchecked(s.as_ref().as_slice())
}
pub fn from_ustr_with_nul(s: impl AsRef<UStr<C>>) -> Result<Self, MissingNulError<C>> {
UCString::from_vec_with_nul(s.as_ref().as_slice())
}
pub unsafe fn from_ustr_with_nul_unchecked(s: impl AsRef<UStr<C>>) -> Self {
UCString::from_vec_with_nul_unchecked(s.as_ref().as_slice())
}
pub unsafe fn from_ptr_str(p: *const C) -> Self {
assert!(!p.is_null());
let mut i: isize = 0;
while *p.offset(i) != UChar::NUL {
i = i + 1;
}
let slice = std::slice::from_raw_parts(p, i as usize + 1);
UCString::from_vec_with_nul_unchecked(slice)
}
pub fn as_ucstr(&self) -> &UCStr<C> {
self
}
pub fn into_vec(self) -> Vec<C> {
let mut v = self.into_inner().into_vec();
v.pop();
v
}
pub fn into_vec_with_nul(self) -> Vec<C> {
self.into_inner().into_vec()
}
pub fn into_raw(self) -> *mut C {
Box::into_raw(self.into_inner()) as *mut C
}
pub unsafe fn from_raw(p: *mut C) -> Self {
assert!(!p.is_null());
let mut i: isize = 0;
while *p.offset(i) != UChar::NUL {
i += 1;
}
let slice = std::slice::from_raw_parts_mut(p, i as usize + 1);
UCString {
inner: mem::transmute(slice),
}
}
pub fn into_boxed_ucstr(self) -> Box<UCStr<C>> {
unsafe { Box::from_raw(Box::into_raw(self.into_inner()) as *mut UCStr<C>) }
}
fn into_inner(self) -> Box<[C]> {
unsafe {
let result = std::ptr::read(&self.inner);
mem::forget(self);
result
}
}
}
impl UCString<u16> {
pub fn from_str(s: impl AsRef<str>) -> Result<Self, NulError<u16>> {
let v: Vec<u16> = s.as_ref().encode_utf16().collect();
UCString::new(v)
}
pub unsafe fn from_str_unchecked(s: impl AsRef<str>) -> Self {
let v: Vec<u16> = s.as_ref().encode_utf16().collect();
UCString::from_vec_unchecked(v)
}
pub fn from_str_with_nul(s: impl AsRef<str>) -> Result<Self, MissingNulError<u16>> {
let v: Vec<u16> = s.as_ref().encode_utf16().collect();
UCString::from_vec_with_nul(v)
}
pub unsafe fn from_str_with_nul_unchecked(s: impl AsRef<str>) -> Self {
let v: Vec<u16> = s.as_ref().encode_utf16().collect();
UCString::from_vec_with_nul_unchecked(v)
}
pub unsafe fn from_ptr(p: *const u16, len: usize) -> Result<Self, NulError<u16>> {
if len == 0 {
return Ok(UCString::default());
}
assert!(!p.is_null());
let slice = std::slice::from_raw_parts(p, len);
UCString::new(slice)
}
pub unsafe fn from_ptr_unchecked(p: *const u16, len: usize) -> Self {
if len == 0 {
return UCString::default();
}
assert!(!p.is_null());
let slice = std::slice::from_raw_parts(p, len);
UCString::from_vec_unchecked(slice)
}
pub unsafe fn from_ptr_with_nul(
p: *const u16,
len: usize,
) -> Result<Self, MissingNulError<u16>> {
if len == 0 {
return Ok(UCString::default());
}
assert!(!p.is_null());
let slice = std::slice::from_raw_parts(p, len);
UCString::from_vec_with_nul(slice)
}
pub unsafe fn from_ptr_with_nul_unchecked(p: *const u16, len: usize) -> Self {
if len == 0 {
return UCString::default();
}
assert!(!p.is_null());
let slice = std::slice::from_raw_parts(p, len);
UCString::from_vec_with_nul_unchecked(slice)
}
pub fn from_os_str(s: impl AsRef<OsStr>) -> Result<Self, NulError<u16>> {
let v = platform::os_to_wide(s.as_ref());
UCString::new(v)
}
pub unsafe fn from_os_str_unchecked(s: impl AsRef<OsStr>) -> Self {
let v = platform::os_to_wide(s.as_ref());
UCString::from_vec_unchecked(v)
}
pub fn from_os_str_with_nul(s: impl AsRef<OsStr>) -> Result<Self, MissingNulError<u16>> {
let v = platform::os_to_wide(s.as_ref());
UCString::from_vec_with_nul(v)
}
pub unsafe fn from_os_str_with_nul_unchecked(s: impl AsRef<OsStr>) -> Self {
let v = platform::os_to_wide(s.as_ref());
UCString::from_vec_with_nul_unchecked(v)
}
}
impl UCString<u32> {
pub fn from_chars(v: impl Into<Vec<char>>) -> Result<Self, NulError<u32>> {
let v: Vec<u32> = unsafe { mem::transmute(v.into()) };
UCString::new(v)
}
pub fn from_chars_with_nul(v: impl Into<Vec<char>>) -> Result<Self, MissingNulError<u32>> {
let v: Vec<u32> = unsafe { mem::transmute(v.into()) };
UCString::from_vec_with_nul(v)
}
pub unsafe fn from_chars_unchecked(v: impl Into<Vec<char>>) -> Self {
let v: Vec<u32> = mem::transmute(v.into());
UCString::from_vec_unchecked(v)
}
pub unsafe fn from_chars_with_nul_unchecked(v: impl Into<Vec<char>>) -> Self {
let v: Vec<u32> = mem::transmute(v.into());
UCString::from_vec_with_nul_unchecked(v)
}
pub fn from_str(s: impl AsRef<str>) -> Result<Self, NulError<u32>> {
let v: Vec<char> = s.as_ref().chars().collect();
UCString::from_chars(v)
}
pub unsafe fn from_str_unchecked(s: impl AsRef<str>) -> Self {
let v: Vec<char> = s.as_ref().chars().collect();
UCString::from_chars_unchecked(v)
}
pub fn from_str_with_nul(s: impl AsRef<str>) -> Result<Self, MissingNulError<u32>> {
let v: Vec<char> = s.as_ref().chars().collect();
UCString::from_chars_with_nul(v)
}
pub unsafe fn from_str_with_nul_unchecked(s: impl AsRef<str>) -> Self {
let v: Vec<char> = s.as_ref().chars().collect();
UCString::from_chars_with_nul_unchecked(v)
}
pub unsafe fn from_ptr(p: *const u32, len: usize) -> Result<Self, NulError<u32>> {
if len == 0 {
return Ok(UCString::default());
}
assert!(!p.is_null());
let slice = std::slice::from_raw_parts(p, len);
UCString::new(slice)
}
pub unsafe fn from_ptr_unchecked(p: *const u32, len: usize) -> Self {
if len == 0 {
return UCString::default();
}
assert!(!p.is_null());
let slice = std::slice::from_raw_parts(p, len);
UCString::from_vec_unchecked(slice)
}
pub unsafe fn from_ptr_with_nul(
p: *const u32,
len: usize,
) -> Result<Self, MissingNulError<u32>> {
if len == 0 {
return Ok(UCString::default());
}
assert!(!p.is_null());
let slice = std::slice::from_raw_parts(p, len);
UCString::from_vec_with_nul(slice)
}
pub unsafe fn from_ptr_with_nul_unchecked(p: *const u32, len: usize) -> Self {
if len == 0 {
return UCString::default();
}
assert!(!p.is_null());
let slice = std::slice::from_raw_parts(p, len);
UCString::from_vec_with_nul_unchecked(slice)
}
pub unsafe fn from_char_ptr(p: *const char, len: usize) -> Result<Self, NulError<u32>> {
UCString::<u32>::from_ptr(p as *const u32, len)
}
pub unsafe fn from_char_ptr_unchecked(p: *const char, len: usize) -> Self {
UCString::<u32>::from_ptr_unchecked(p as *const u32, len)
}
pub unsafe fn from_char_ptr_with_nul(
p: *const char,
len: usize,
) -> Result<Self, MissingNulError<u32>> {
UCString::<u32>::from_ptr_with_nul(p as *const u32, len)
}
pub unsafe fn from_char_ptr_with_nul_unchecked(p: *const char, len: usize) -> Self {
UCString::<u32>::from_ptr_with_nul_unchecked(p as *const u32, len)
}
pub fn from_os_str(s: impl AsRef<OsStr>) -> Result<Self, NulError<u32>> {
let v: Vec<char> = s.as_ref().to_string_lossy().chars().collect();
UCString::from_chars(v)
}
pub unsafe fn from_os_str_unchecked(s: impl AsRef<OsStr>) -> Self {
let v: Vec<char> = s.as_ref().to_string_lossy().chars().collect();
UCString::from_chars_unchecked(v)
}
pub fn from_os_str_with_nul(s: impl AsRef<OsStr>) -> Result<Self, MissingNulError<u32>> {
let v: Vec<char> = s.as_ref().to_string_lossy().chars().collect();
UCString::from_chars_with_nul(v)
}
pub unsafe fn from_os_str_with_nul_unchecked(s: impl AsRef<OsStr>) -> Self {
let v: Vec<char> = s.as_ref().to_string_lossy().chars().collect();
UCString::from_chars_with_nul_unchecked(v)
}
}
impl<C: UChar> UCStr<C> {
pub fn new<S: AsRef<UCStr<C>> + ?Sized>(s: &S) -> &Self {
s.as_ref()
}
pub unsafe fn from_ptr_str<'a>(p: *const C) -> &'a Self {
assert!(!p.is_null());
let mut i: isize = 0;
while *p.offset(i) != UChar::NUL {
i = i + 1;
}
mem::transmute(std::slice::from_raw_parts(p, i as usize + 1))
}
pub unsafe fn from_ptr_with_nul<'a>(p: *const C, len: usize) -> &'a Self {
assert!(*p.offset(len as isize) == UChar::NUL);
mem::transmute(std::slice::from_raw_parts(p, len + 1))
}
pub fn from_slice_with_nul(slice: &[C]) -> Result<&Self, MissingNulError<C>> {
match slice.iter().position(|x| *x == UChar::NUL) {
None => Err(MissingNulError(None)),
Some(i) => Ok(unsafe { UCStr::from_slice_with_nul_unchecked(&slice[..i + 1]) }),
}
}
pub unsafe fn from_slice_with_nul_unchecked(slice: &[C]) -> &Self {
std::mem::transmute(slice)
}
pub fn to_ucstring(&self) -> UCString<C> {
unsafe { UCString::from_vec_with_nul_unchecked(self.inner.to_owned()) }
}
pub fn to_ustring(&self) -> UString<C> {
UString::from_vec(self.as_slice())
}
pub fn as_slice(&self) -> &[C] {
&self.inner[..self.len()]
}
pub fn as_slice_with_nul(&self) -> &[C] {
&self.inner
}
pub fn as_ptr(&self) -> *const C {
self.inner.as_ptr()
}
pub fn len(&self) -> usize {
self.inner.len() - 1
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn into_ucstring(self: Box<Self>) -> UCString<C> {
let raw = Box::into_raw(self) as *mut [C];
UCString {
inner: unsafe { Box::from_raw(raw) },
}
}
fn from_inner(slice: &[C]) -> &UCStr<C> {
unsafe { mem::transmute(slice) }
}
}
impl UCStr<u16> {
pub fn to_os_string(&self) -> OsString {
platform::os_from_wide(self.as_slice())
}
pub fn to_string(&self) -> Result<String, std::string::FromUtf16Error> {
String::from_utf16(self.as_slice())
}
pub fn to_string_lossy(&self) -> String {
String::from_utf16_lossy(self.as_slice())
}
}
impl UCStr<u32> {
pub unsafe fn from_char_ptr_str<'a>(p: *const char) -> &'a Self {
UCStr::from_ptr_str(p as *const u32)
}
pub unsafe fn from_char_ptr_with_nul<'a>(p: *const char, len: usize) -> &'a Self {
UCStr::from_ptr_with_nul(p as *const u32, len)
}
pub fn from_char_slice_with_nul(slice: &[char]) -> Result<&Self, MissingNulError<u32>> {
UCStr::from_slice_with_nul(unsafe { mem::transmute(slice) })
}
pub unsafe fn from_char_slice_with_nul_unchecked(slice: &[char]) -> &Self {
UCStr::from_slice_with_nul_unchecked(mem::transmute(slice))
}
pub fn to_os_string(&self) -> OsString {
self.to_ustring().to_os_string()
}
pub fn to_string(&self) -> Result<String, FromUtf32Error> {
self.to_ustring().to_string()
}
pub fn to_string_lossy(&self) -> String {
self.to_ustring().to_string_lossy()
}
}
impl<C: UChar> Into<Vec<C>> for UCString<C> {
fn into(self) -> Vec<C> {
self.into_vec()
}
}
impl<'a> From<UCString<u16>> for std::borrow::Cow<'a, UCStr<u16>> {
fn from(s: UCString<u16>) -> std::borrow::Cow<'a, UCStr<u16>> {
std::borrow::Cow::Owned(s)
}
}
impl<'a> From<UCString<u32>> for std::borrow::Cow<'a, UCStr<u32>> {
fn from(s: UCString<u32>) -> std::borrow::Cow<'a, UCStr<u32>> {
std::borrow::Cow::Owned(s)
}
}
impl From<UCString<u16>> for OsString {
fn from(s: UCString<u16>) -> OsString {
s.to_os_string()
}
}
impl From<UCString<u32>> for OsString {
fn from(s: UCString<u32>) -> OsString {
s.to_os_string()
}
}
impl<C: UChar> From<UCString<C>> for UString<C> {
fn from(s: UCString<C>) -> Self {
s.to_ustring()
}
}
impl<'a, C: UChar, T: ?Sized + AsRef<UCStr<C>>> From<&'a T> for UCString<C> {
fn from(s: &'a T) -> Self {
s.as_ref().to_ucstring()
}
}
impl<C: UChar> std::ops::Index<std::ops::RangeFull> for UCString<C> {
type Output = UCStr<C>;
#[inline]
fn index(&self, _index: std::ops::RangeFull) -> &UCStr<C> {
UCStr::from_inner(&self.inner)
}
}
impl<C: UChar> std::ops::Deref for UCString<C> {
type Target = UCStr<C>;
#[inline]
fn deref(&self) -> &UCStr<C> {
&self[..]
}
}
impl<'a> Default for &'a UCStr<u16> {
fn default() -> Self {
const SLICE: &'static [u16] = &[UChar::NUL];
unsafe { UCStr::from_slice_with_nul_unchecked(SLICE) }
}
}
impl<'a> Default for &'a UCStr<u32> {
fn default() -> Self {
const SLICE: &'static [u32] = &[UChar::NUL];
unsafe { UCStr::from_slice_with_nul_unchecked(SLICE) }
}
}
impl Default for UCString<u16> {
fn default() -> Self {
let def: &UCStr<u16> = Default::default();
def.to_ucstring()
}
}
impl Default for UCString<u32> {
fn default() -> Self {
let def: &UCStr<u32> = Default::default();
def.to_ucstring()
}
}
impl<C: UChar> Drop for UCString<C> {
#[inline]
fn drop(&mut self) {
unsafe {
*self.inner.get_unchecked_mut(0) = UChar::NUL;
}
}
}
impl<C: UChar> std::borrow::Borrow<UCStr<C>> for UCString<C> {
fn borrow(&self) -> &UCStr<C> {
&self[..]
}
}
impl<C: UChar> ToOwned for UCStr<C> {
type Owned = UCString<C>;
fn to_owned(&self) -> UCString<C> {
self.to_ucstring()
}
}
impl<'a> From<&'a UCStr<u16>> for std::borrow::Cow<'a, UCStr<u16>> {
fn from(s: &'a UCStr<u16>) -> std::borrow::Cow<'a, UCStr<u16>> {
std::borrow::Cow::Borrowed(s)
}
}
impl<'a> From<&'a UCStr<u32>> for std::borrow::Cow<'a, UCStr<u32>> {
fn from(s: &'a UCStr<u32>) -> std::borrow::Cow<'a, UCStr<u32>> {
std::borrow::Cow::Borrowed(s)
}
}
impl<C: UChar> AsRef<UCStr<C>> for UCStr<C> {
fn as_ref(&self) -> &Self {
self
}
}
impl<C: UChar> AsRef<UCStr<C>> for UCString<C> {
fn as_ref(&self) -> &UCStr<C> {
self
}
}
impl<C: UChar> AsRef<[C]> for UCStr<C> {
fn as_ref(&self) -> &[C] {
self.as_slice()
}
}
impl<C: UChar> AsRef<[C]> for UCString<C> {
fn as_ref(&self) -> &[C] {
self.as_slice()
}
}
impl<'a, C: UChar> From<&'a UCStr<C>> for Box<UCStr<C>> {
fn from(s: &'a UCStr<C>) -> Box<UCStr<C>> {
let boxed: Box<[C]> = Box::from(s.as_slice_with_nul());
unsafe { Box::from_raw(Box::into_raw(boxed) as *mut UCStr<C>) }
}
}
impl<C: UChar> From<Box<UCStr<C>>> for UCString<C> {
#[inline]
fn from(s: Box<UCStr<C>>) -> Self {
s.into_ucstring()
}
}
impl<C: UChar> From<UCString<C>> for Box<UCStr<C>> {
#[inline]
fn from(s: UCString<C>) -> Box<UCStr<C>> {
s.into_boxed_ucstr()
}
}
impl<C: UChar> Default for Box<UCStr<C>> {
fn default() -> Box<UCStr<C>> {
let boxed: Box<[C]> = Box::from([UChar::NUL]);
unsafe { Box::from_raw(Box::into_raw(boxed) as *mut UCStr<C>) }
}
}
impl<C: UChar> NulError<C> {
pub fn nul_position(&self) -> usize {
self.0
}
pub fn into_vec(self) -> Vec<C> {
self.1
}
}
impl<C: UChar> Into<Vec<C>> for NulError<C> {
fn into(self) -> Vec<C> {
self.into_vec()
}
}
impl<C: UChar> std::fmt::Display for NulError<C> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "nul value found at position {}", self.0)
}
}
impl<C: UChar> std::error::Error for NulError<C> {
fn description(&self) -> &str {
"nul value found"
}
}
impl<C: UChar> MissingNulError<C> {
pub fn into_vec(self) -> Option<Vec<C>> {
self.0
}
}
impl<C: UChar> std::fmt::Display for MissingNulError<C> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "missing terminating nul value")
}
}
impl<C: UChar> std::error::Error for MissingNulError<C> {
fn description(&self) -> &str {
"missing terminating nul value"
}
}