use std::borrow::{Borrow, BorrowMut, Cow};
use std::cmp;
use std::convert::{TryFrom, TryInto};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::iter::FromIterator;
use std::mem;
use std::ops;
use std::string;
use mediumvec::Vec32;
use usize_cast::IntoUsize;
use super::{Str32, TryFromStrError, TryFromStringError};
#[derive(Clone, Debug, Default, Eq)]
#[repr(transparent)]
pub struct String32(Vec32<u8>);
impl String32 {
#[must_use]
pub fn new() -> Self {
Self(Vec32::new())
}
#[must_use]
pub fn with_capacity(cap: u32) -> Self {
Self(Vec32::with_capacity(cap))
}
#[must_use]
pub fn capacity(&self) -> u32 {
self.0.capacity()
}
pub fn as_string<F, T>(&mut self, f: F) -> T
where
F: FnOnce(&mut String) -> T,
{
let mut s = mem::take(self).into();
let ret = f(&mut s);
*self = s.try_into().unwrap();
ret
}
pub fn push(&mut self, ch: char) {
self.as_string(|s| s.push(ch));
}
pub fn push_str<S>(&mut self, s: S)
where
S: AsRef<str>,
{
self.as_string(|st| st.push_str(s.as_ref()));
}
pub fn pop(&mut self) -> Option<char> {
self.as_string(String::pop)
}
pub fn remove(&mut self, idx: u32) -> char {
self.as_string(|s| s.remove(idx.into_usize()))
}
pub fn insert(&mut self, idx: u32, ch: char) {
self.as_string(|s| s.insert(idx.into_usize(), ch));
}
pub fn insert_str<S>(&mut self, idx: u32, s: S)
where
S: AsRef<str>,
{
self.as_string(|st| st.insert_str(idx.into_usize(), s.as_ref()));
}
pub fn reserve(&mut self, additional: u32) {
self.0.reserve(additional)
}
pub fn reserve_exact(&mut self, additional: u32) {
self.0.reserve_exact(additional)
}
pub fn shrink_to_fit(&mut self) {
self.as_string(String::shrink_to_fit);
}
pub fn truncate(&mut self, new_len: u32) {
self.as_string(|s| s.truncate(new_len.into_usize()));
}
pub fn clear(&mut self) {
self.0.clear()
}
#[must_use]
pub fn into_bytes(self) -> Vec<u8> {
self.0.into_vec()
}
#[must_use]
pub fn into_boxed_str(self) -> Box<str> {
String::from(self).into_boxed_str()
}
#[must_use = "if you plan to discard the second half, consider using `String32::truncate` instead"]
pub fn split_off(&mut self, at: u32) -> Self {
self.as_string(|s| s.split_off(at.into_usize()).try_into().unwrap())
}
pub unsafe fn from_raw_parts(buf: *mut u8, len: u32, cap: u32) -> Self {
Self(Vec32::from_vec(Vec::from_raw_parts(
buf,
len.into_usize(),
cap.into_usize(),
)))
}
pub fn from_utf8(v: Vec<u8>) -> Result<Self, string::FromUtf8Error> {
String::from_utf8(v).map(|s| s.try_into().unwrap())
}
pub fn from_utf16(v: &[u16]) -> Result<Self, string::FromUtf16Error> {
String::from_utf16(v).map(|s| s.try_into().unwrap())
}
#[must_use]
pub fn from_utf16_lossy(v: &[u16]) -> Self {
String::from_utf16_lossy(v).try_into().unwrap()
}
}
impl ops::Add<&str> for String32 {
type Output = Self;
#[must_use]
fn add(mut self, rhs: &str) -> Self {
self.push_str(rhs);
self
}
}
impl ops::Add<&Str32> for String32 {
type Output = Self;
#[must_use]
fn add(mut self, rhs: &Str32) -> Self {
self.push_str(rhs);
self
}
}
impl ops::AddAssign<&str> for String32 {
fn add_assign(&mut self, rhs: &str) {
self.push_str(rhs);
}
}
impl ops::AddAssign<&Str32> for String32 {
fn add_assign(&mut self, rhs: &Str32) {
self.push_str(rhs);
}
}
impl AsMut<Str32> for String32 {
fn as_mut(&mut self) -> &mut Str32 {
self
}
}
impl AsRef<Str32> for String32 {
fn as_ref(&self) -> &Str32 {
&*self
}
}
impl AsRef<[u8]> for String32 {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl AsRef<str> for String32 {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl Borrow<Str32> for String32 {
fn borrow(&self) -> &Str32 {
&*self
}
}
impl BorrowMut<Str32> for String32 {
fn borrow_mut(&mut self) -> &mut Str32 {
&mut *self
}
}
impl ops::Deref for String32 {
type Target = Str32;
fn deref(&self) -> &Str32 {
let ptr = self.0.as_ref() as *const [u8] as *const str as *const Str32;
unsafe {
&*ptr
}
}
}
impl ops::DerefMut for String32 {
fn deref_mut(&mut self) -> &mut Str32 {
let ptr = self.0.as_mut() as *mut [u8] as *mut str as *mut Str32;
unsafe {
&mut *ptr
}
}
}
impl fmt::Display for String32 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<Str32 as fmt::Display>::fmt(self, f)
}
}
impl From<&Str32> for String32 {
fn from(s: &Str32) -> Self {
s.to_owned()
}
}
#[allow(clippy::fallible_impl_from)]
impl From<String32> for String {
fn from(s: String32) -> Self {
if cfg!(debug_assertions) {
Self::from_utf8(s.0.into_vec()).unwrap()
} else {
unsafe {
Self::from_utf8_unchecked(s.0.into_vec())
}
}
}
}
impl From<String32> for Vec<u8> {
fn from(s: String32) -> Self {
s.0.into_vec()
}
}
impl FromIterator<char> for String32 {
fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> Self {
String::from_iter(iter).try_into().unwrap()
}
}
impl<'a> FromIterator<&'a char> for String32 {
fn from_iter<I: IntoIterator<Item = &'a char>>(iter: I) -> Self {
String::from_iter(iter).try_into().unwrap()
}
}
impl<'a> FromIterator<&'a str> for String32 {
fn from_iter<I: IntoIterator<Item = &'a str>>(iter: I) -> Self {
String::from_iter(iter).try_into().unwrap()
}
}
impl<'a> FromIterator<&'a Str32> for String32 {
fn from_iter<I: IntoIterator<Item = &'a Str32>>(iter: I) -> Self {
String::from_iter(iter.into_iter().map(Str32::as_str))
.try_into()
.unwrap()
}
}
impl FromIterator<Box<str>> for String32 {
fn from_iter<I: IntoIterator<Item = Box<str>>>(iter: I) -> Self {
String::from_iter(iter).try_into().unwrap()
}
}
impl FromIterator<Box<Str32>> for String32 {
fn from_iter<I: IntoIterator<Item = Box<Str32>>>(iter: I) -> Self {
String::from_iter(iter.into_iter().map(Str32::into_boxed_str))
.try_into()
.unwrap()
}
}
impl FromIterator<String> for String32 {
fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> Self {
String::from_iter(iter).try_into().unwrap()
}
}
impl FromIterator<Self> for String32 {
fn from_iter<I: IntoIterator<Item = Self>>(iter: I) -> Self {
String::from_iter(iter.into_iter().map(String::from))
.try_into()
.unwrap()
}
}
impl Hash for String32 {
fn hash<H: Hasher>(&self, state: &mut H) {
(**self).hash(state);
}
}
impl Ord for String32 {
fn cmp(&self, rhs: &Self) -> cmp::Ordering {
<Str32 as Ord>::cmp(self, rhs)
}
}
impl PartialEq for String32 {
fn eq(&self, rhs: &Self) -> bool {
<Str32 as PartialEq>::eq(self, rhs)
}
}
impl PartialOrd for String32 {
fn partial_cmp(&self, rhs: &Self) -> Option<cmp::Ordering> {
<Str32 as PartialOrd>::partial_cmp(self, rhs)
}
}
macro_rules! impl_cmp {
($lhs:ty, $rhs: ty) => {
impl<'a, 'b> PartialEq<$rhs> for $lhs {
fn eq(&self, rhs: &$rhs) -> bool {
<[u8] as PartialEq>::eq(self.as_bytes(), rhs.as_bytes())
}
}
impl<'a, 'b> PartialEq<$lhs> for $rhs {
fn eq(&self, rhs: &$lhs) -> bool {
<[u8] as PartialEq>::eq(self.as_bytes(), rhs.as_bytes())
}
}
impl<'a, 'b> PartialOrd<$rhs> for $lhs {
fn partial_cmp(&self, rhs: &$rhs) -> Option<cmp::Ordering> {
<[u8] as PartialOrd>::partial_cmp(self.as_bytes(), rhs.as_bytes())
}
}
impl<'a, 'b> PartialOrd<$lhs> for $rhs {
fn partial_cmp(&self, rhs: &$lhs) -> Option<cmp::Ordering> {
<[u8] as PartialOrd>::partial_cmp(self.as_bytes(), rhs.as_bytes())
}
}
};
}
impl_cmp!(String32, Str32);
impl_cmp!(String32, &'a Str32);
impl_cmp!(String32, String);
impl_cmp!(String32, str);
impl_cmp!(String32, &'a str);
impl_cmp!(String32, Cow<'a, Str32>);
impl_cmp!(String32, Cow<'a, str>);
impl_cmp!(String32, Box<str>);
impl_cmp!(String32, Box<Str32>);
impl_cmp!(Str32, &'a Str32);
impl_cmp!(Str32, String);
impl_cmp!(Str32, str);
impl_cmp!(Str32, &'a str);
impl_cmp!(Str32, Cow<'a, Str32>);
impl_cmp!(Str32, Cow<'a, str>);
impl_cmp!(Str32, Box<str>);
impl_cmp!(Str32, Box<Str32>);
impl_cmp!(&'a Str32, String);
impl_cmp!(&'a Str32, str);
impl_cmp!(&'a Str32, Cow<'b, Str32>);
impl_cmp!(&'a Str32, Cow<'b, str>);
impl_cmp!(&'a Str32, Box<str>);
impl_cmp!(&'a Str32, Box<Str32>);
impl TryFrom<String> for String32 {
type Error = TryFromStringError<String>;
fn try_from(s: String) -> Result<Self, Self::Error> {
match u32::try_from(s.len()) {
Ok(_) => Ok(Self(Vec32::from_vec(s.into_bytes()))),
Err(_) => Err(TryFromStringError(s)),
}
}
}
impl TryFrom<Box<str>> for String32 {
type Error = TryFromStringError<Box<str>>;
fn try_from(s: Box<str>) -> Result<Self, Self::Error> {
match u32::try_from(s.len()) {
Ok(_) => Ok(Self(Vec32::from_vec(String::from(s).into_bytes()))),
Err(_) => Err(TryFromStringError(s)),
}
}
}
impl TryFrom<&str> for String32 {
type Error = TryFromStrError;
fn try_from(s: &str) -> Result<Self, Self::Error> {
match u32::try_from(s.len()) {
Ok(_) => Ok(Self(Vec32::from_vec(s.to_owned().into_bytes()))),
Err(_) => Err(TryFromStrError(())),
}
}
}