use super::platform;
use super::UChar;
use std;
use std::char;
use std::ffi::{OsStr, OsString};
use std::mem;
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UString<C: UChar> {
inner: Vec<C>,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UStr<C: UChar> {
inner: [C],
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FromUtf32Error();
impl<C: UChar> UString<C> {
pub fn new() -> Self {
Self { inner: vec![] }
}
pub fn from_vec(raw: impl Into<Vec<C>>) -> Self {
Self { inner: raw.into() }
}
pub unsafe fn from_ptr(p: *const C, len: usize) -> Self {
if len == 0 {
return Self::new();
}
assert!(!p.is_null());
let slice = std::slice::from_raw_parts(p, len);
Self::from_vec(slice)
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
inner: Vec::with_capacity(capacity),
}
}
pub fn capacity(&self) -> usize {
self.inner.capacity()
}
pub fn clear(&mut self) {
self.inner.clear()
}
pub fn reserve(&mut self, additional: usize) {
self.inner.reserve(additional)
}
pub fn reserve_exact(&mut self, additional: usize) {
self.inner.reserve_exact(additional)
}
pub fn into_vec(self) -> Vec<C> {
self.inner
}
pub fn as_ustr(&self) -> &UStr<C> {
self
}
pub fn push(&mut self, s: impl AsRef<UStr<C>>) {
self.inner.extend_from_slice(&s.as_ref().inner)
}
pub fn push_slice(&mut self, s: impl AsRef<[C]>) {
self.inner.extend_from_slice(&s.as_ref())
}
pub fn shrink_to_fit(&mut self) {
self.inner.shrink_to_fit();
}
pub fn into_boxed_ustr(self) -> Box<UStr<C>> {
let rw = Box::into_raw(self.inner.into_boxed_slice()) as *mut UStr<C>;
unsafe { Box::from_raw(rw) }
}
}
impl UString<u16> {
pub fn from_str<S: AsRef<str> + ?Sized>(s: &S) -> Self {
Self {
inner: s.as_ref().encode_utf16().collect(),
}
}
pub fn from_os_str<S: AsRef<OsStr> + ?Sized>(s: &S) -> Self {
Self {
inner: platform::os_to_wide(s.as_ref()),
}
}
pub fn push_str(&mut self, s: impl AsRef<str>) {
self.inner.extend(s.as_ref().encode_utf16())
}
pub fn push_os_str(&mut self, s: impl AsRef<OsStr>) {
self.inner.extend(platform::os_to_wide(s.as_ref()))
}
}
impl UString<u32> {
pub fn from_chars(raw: impl Into<Vec<char>>) -> Self {
UString {
inner: unsafe { mem::transmute(raw.into()) },
}
}
pub fn from_str<S: AsRef<str> + ?Sized>(s: &S) -> Self {
let v: Vec<char> = s.as_ref().chars().collect();
UString::from_chars(v)
}
pub fn from_os_str<S: AsRef<OsStr> + ?Sized>(s: &S) -> Self {
let v: Vec<char> = s.as_ref().to_string_lossy().chars().collect();
UString::from_chars(v)
}
pub unsafe fn from_char_ptr(p: *const char, len: usize) -> Self {
UString::from_ptr(p as *const u32, len)
}
pub fn push_str(&mut self, s: impl AsRef<str>) {
self.inner.extend(s.as_ref().chars().map(|c| c as u32))
}
pub fn push_os_str(&mut self, s: impl AsRef<OsStr>) {
self.inner
.extend(s.as_ref().to_string_lossy().chars().map(|c| c as u32))
}
}
impl<C: UChar> UStr<C> {
pub fn new<S: AsRef<Self> + ?Sized>(s: &S) -> &Self {
s.as_ref()
}
pub unsafe fn from_ptr<'a>(p: *const C, len: usize) -> &'a Self {
assert!(!p.is_null());
mem::transmute(std::slice::from_raw_parts(p, len))
}
pub fn from_slice(slice: &[C]) -> &Self {
unsafe { mem::transmute(slice) }
}
pub fn to_ustring(&self) -> UString<C> {
UString::from_vec(&self.inner)
}
pub fn as_slice(&self) -> &[C] {
&self.inner
}
pub fn as_ptr(&self) -> *const C {
self.inner.as_ptr()
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn into_ustring(self: Box<Self>) -> UString<C> {
let boxed = unsafe { Box::from_raw(Box::into_raw(self) as *mut [C]) };
UString {
inner: boxed.into_vec(),
}
}
}
impl UStr<u16> {
pub fn to_os_string(&self) -> OsString {
platform::os_from_wide(&self.inner)
}
pub fn to_string(&self) -> Result<String, std::string::FromUtf16Error> {
String::from_utf16(&self.inner)
}
pub fn to_string_lossy(&self) -> String {
String::from_utf16_lossy(&self.inner)
}
}
impl UStr<u32> {
pub unsafe fn from_char_ptr<'a>(p: *const char, len: usize) -> &'a Self {
UStr::from_ptr(p as *const u32, len)
}
pub fn from_char_slice(slice: &[char]) -> &Self {
unsafe { mem::transmute(slice) }
}
pub fn to_os_string(&self) -> OsString {
self.to_string_lossy().into()
}
pub fn to_string(&self) -> Result<String, FromUtf32Error> {
let chars: Vec<Option<char>> = self.inner.iter().map(|c| char::from_u32(*c)).collect();
if chars.iter().any(|c| c.is_none()) {
return Err(FromUtf32Error());
}
let size = chars.iter().filter_map(|o| o.map(|c| c.len_utf8())).sum();
let mut vec = Vec::with_capacity(size);
unsafe { vec.set_len(size) };
let mut i = 0;
for c in chars.iter().filter_map(|&o| o) {
c.encode_utf8(&mut vec[i..]);
i += c.len_utf8();
}
Ok(unsafe { String::from_utf8_unchecked(vec) })
}
pub fn to_string_lossy(&self) -> String {
let chars: Vec<char> = self
.inner
.iter()
.map(|&c| char::from_u32(c).unwrap_or(char::REPLACEMENT_CHARACTER))
.collect();
let size = chars.iter().map(|c| c.len_utf8()).sum();
let mut vec = Vec::with_capacity(size);
unsafe { vec.set_len(size) };
let mut i = 0;
for c in chars {
c.encode_utf8(&mut vec[i..]);
i += c.len_utf8();
}
unsafe { String::from_utf8_unchecked(vec) }
}
}
impl<C: UChar> Into<Vec<C>> for UString<C> {
fn into(self) -> Vec<C> {
self.into_vec()
}
}
impl<'a> From<UString<u16>> for std::borrow::Cow<'a, UStr<u16>> {
fn from(s: UString<u16>) -> Self {
std::borrow::Cow::Owned(s)
}
}
impl<'a> From<UString<u32>> for std::borrow::Cow<'a, UStr<u32>> {
fn from(s: UString<u32>) -> Self {
std::borrow::Cow::Owned(s)
}
}
impl Into<UString<u16>> for Vec<u16> {
fn into(self) -> UString<u16> {
UString::from_vec(self)
}
}
impl Into<UString<u32>> for Vec<u32> {
fn into(self) -> UString<u32> {
UString::from_vec(self)
}
}
impl Into<UString<u32>> for Vec<char> {
fn into(self) -> UString<u32> {
UString::from_chars(self)
}
}
impl From<String> for UString<u16> {
fn from(s: String) -> Self {
Self::from_str(&s)
}
}
impl From<String> for UString<u32> {
fn from(s: String) -> Self {
Self::from_str(&s)
}
}
impl From<OsString> for UString<u16> {
fn from(s: OsString) -> Self {
Self::from_os_str(&s)
}
}
impl From<OsString> for UString<u32> {
fn from(s: OsString) -> Self {
Self::from_os_str(&s)
}
}
impl From<UString<u16>> for OsString {
fn from(s: UString<u16>) -> Self {
s.to_os_string()
}
}
impl From<UString<u32>> for OsString {
fn from(s: UString<u32>) -> Self {
s.to_os_string()
}
}
impl<'a, C: UChar, T: ?Sized + AsRef<UStr<C>>> From<&'a T> for UString<C> {
fn from(s: &'a T) -> Self {
s.as_ref().to_ustring()
}
}
impl<C: UChar> std::ops::Index<std::ops::RangeFull> for UString<C> {
type Output = UStr<C>;
#[inline]
fn index(&self, _index: std::ops::RangeFull) -> &UStr<C> {
UStr::from_slice(&self.inner)
}
}
impl<C: UChar> std::ops::Deref for UString<C> {
type Target = UStr<C>;
#[inline]
fn deref(&self) -> &UStr<C> {
&self[..]
}
}
impl<C: UChar> PartialEq<UStr<C>> for UString<C> {
#[inline]
fn eq(&self, other: &UStr<C>) -> bool {
self.as_ustr() == other
}
}
impl<C: UChar> PartialOrd<UStr<C>> for UString<C> {
#[inline]
fn partial_cmp(&self, other: &UStr<C>) -> Option<std::cmp::Ordering> {
self.as_ustr().partial_cmp(other)
}
}
impl<'a, C: UChar> PartialEq<&'a UStr<C>> for UString<C> {
#[inline]
fn eq(&self, other: &&'a UStr<C>) -> bool {
self.as_ustr() == *other
}
}
impl<'a, C: UChar> PartialOrd<&'a UStr<C>> for UString<C> {
#[inline]
fn partial_cmp(&self, other: &&'a UStr<C>) -> Option<std::cmp::Ordering> {
self.as_ustr().partial_cmp(*other)
}
}
impl<'a, C: UChar> PartialEq<std::borrow::Cow<'a, UStr<C>>> for UString<C> {
#[inline]
fn eq(&self, other: &std::borrow::Cow<'a, UStr<C>>) -> bool {
self.as_ustr() == other.as_ref()
}
}
impl<'a, C: UChar> PartialOrd<std::borrow::Cow<'a, UStr<C>>> for UString<C> {
#[inline]
fn partial_cmp(&self, other: &std::borrow::Cow<'a, UStr<C>>) -> Option<std::cmp::Ordering> {
self.as_ustr().partial_cmp(other.as_ref())
}
}
impl<C: UChar> std::borrow::Borrow<UStr<C>> for UString<C> {
fn borrow(&self) -> &UStr<C> {
&self[..]
}
}
impl<C: UChar> ToOwned for UStr<C> {
type Owned = UString<C>;
fn to_owned(&self) -> UString<C> {
self.to_ustring()
}
}
impl<'a> From<&'a UStr<u16>> for std::borrow::Cow<'a, UStr<u16>> {
fn from(s: &'a UStr<u16>) -> Self {
std::borrow::Cow::Borrowed(s)
}
}
impl<'a> From<&'a UStr<u32>> for std::borrow::Cow<'a, UStr<u32>> {
fn from(s: &'a UStr<u32>) -> Self {
std::borrow::Cow::Borrowed(s)
}
}
impl<C: UChar> AsRef<UStr<C>> for UStr<C> {
fn as_ref(&self) -> &Self {
self
}
}
impl<C: UChar> AsRef<UStr<C>> for UString<C> {
fn as_ref(&self) -> &UStr<C> {
self
}
}
impl<C: UChar> AsRef<[C]> for UStr<C> {
fn as_ref(&self) -> &[C] {
self.as_slice()
}
}
impl<C: UChar> AsRef<[C]> for UString<C> {
fn as_ref(&self) -> &[C] {
self.as_slice()
}
}
impl<'a, C: UChar> From<&'a UStr<C>> for Box<UStr<C>> {
fn from(s: &'a UStr<C>) -> Self {
let boxed: Box<[C]> = Box::from(&s.inner);
let rw = Box::into_raw(boxed) as *mut UStr<C>;
unsafe { Box::from_raw(rw) }
}
}
impl<C: UChar> From<Box<UStr<C>>> for UString<C> {
fn from(boxed: Box<UStr<C>>) -> Self {
boxed.into_ustring()
}
}
impl<C: UChar> From<UString<C>> for Box<UStr<C>> {
fn from(s: UString<C>) -> Self {
s.into_boxed_ustr()
}
}
impl<C: UChar> Default for Box<UStr<C>> {
fn default() -> Self {
let boxed: Box<[C]> = Box::from([]);
let rw = Box::into_raw(boxed) as *mut UStr<C>;
unsafe { Box::from_raw(rw) }
}
}
impl std::fmt::Display for FromUtf32Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "error converting from UTF-32 to UTF-8")
}
}
impl std::error::Error for FromUtf32Error {
fn description(&self) -> &str {
"error converting from UTF-32 to UTF-8"
}
}