use crate::auxiliary::zero;
use crate::guard;
use crate::vec::{InnerVec, Vec};
use std::cmp::{PartialEq, min, max};
use std::convert::From;
use std::iter::FromIterator;
use std::mem::MaybeUninit;
use std::str::Chars;
use unicode_normalization::UnicodeNormalization;
use unicode_normalization::char::decompose_canonical;
#[must_use]
#[derive(Debug, Default)]
pub struct String(Vec<u8>);
#[must_use]
#[derive(Debug)]
pub struct Ref<'t>(guard::Ref<'t, InnerVec<u8>>);
#[must_use]
#[derive(Debug)]
pub struct RefMut<'t>(guard::RefMut<'t, InnerVec<u8>>);
impl String {
const CMP_MIN: usize = 32;
fn eq_slice(a: &InnerVec<u8>, b: &[u8]) -> bool {
if a.capacity() == 0 {
debug_assert!(a.is_empty());
b.is_empty()
} else {
debug_assert!(a.capacity() >= Self::CMP_MIN);
b.iter().take(a.capacity()).enumerate().fold(0, |d, (i, e)| {
d | unsafe { a.as_ptr().add(i).read() as usize ^ *e as usize }
}) | (max(a.len(), b.len()) - min(a.len(), b.len())) == 0
}
}
#[inline]
pub fn new() -> Self {
Self(Vec::new())
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self(Vec::with_capacity(capacity))
}
#[inline]
pub fn capacity(&self) -> usize {
self.0.capacity()
}
#[inline]
pub fn len(&self) -> usize {
self.0.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
#[inline]
pub fn reserve(&mut self, capacity: usize) {
self.0.reserve(capacity);
}
#[inline]
pub fn reserve_exact(&mut self, capacity: usize) {
self.0.reserve_exact(capacity);
}
#[inline]
pub fn borrow(&self) -> Ref<'_> {
Ref(self.0.borrow())
}
#[inline]
pub fn borrow_mut(&mut self) -> RefMut<'_> {
RefMut(self.0.borrow_mut())
}
}
impl FromIterator<char> for String {
fn from_iter<I>(into: I) -> Self
where I: IntoIterator<Item = char> {
let iter = into.into_iter();
let (lower, upper) = iter.size_hint();
let mut string = Self::with_capacity(upper.unwrap_or(lower));
{
let mut mutable = string.borrow_mut();
for ch in iter {
mutable.push(ch);
}
}
string
}
}
impl From<&str> for String {
fn from(source: &str) -> Self {
let iter = source.nfd();
let (lower, upper) = iter.size_hint();
let mut string = Self::with_capacity(upper.unwrap_or(lower));
{
let mut mutable = string.borrow_mut();
for decomp in iter {
mutable.reserve(decomp.len_utf8());
decomp.encode_utf8(unsafe { MaybeUninit::slice_assume_init_mut(mutable.0.spare_capacity_mut()) });
unsafe { mutable.0.set_len(mutable.0.len() + decomp.len_utf8()); }
}
}
string
}
}
impl From<std::string::String> for String {
fn from(mut source: std::string::String) -> Self {
let string = Self::from(source.as_str());
unsafe { zero(source.as_mut_ptr(), source.len()); }
string
}
}
impl Ref<'_> {
#[must_use] #[inline]
pub fn as_bytes(&self) -> &[u8] {
self.0.as_slice()
}
#[must_use] #[inline]
pub fn as_str(&self) -> &str {
unsafe { std::str::from_utf8_unchecked(self.0.as_slice()) }
}
#[inline]
pub fn chars(&self) -> Chars<'_> {
self.as_str().chars()
}
}
impl PartialEq<Self> for Ref<'_> {
#[inline]
fn eq(&self, other: &Self) -> bool {
String::eq_slice(unsafe { self.0.0.inner() }, unsafe { other.0.0.inner() })
}
}
impl PartialEq<RefMut<'_>> for Ref<'_> {
#[inline]
fn eq(&self, other: &RefMut<'_>) -> bool {
String::eq_slice(unsafe { self.0.0.inner() }, unsafe { other.0.0.inner() })
}
}
impl RefMut<'_> {
#[must_use] #[inline]
pub fn as_bytes(&self) -> &[u8] {
self.0.as_slice()
}
#[must_use] #[inline]
pub fn as_str(&self) -> &str {
unsafe { std::str::from_utf8_unchecked(self.0.as_slice()) }
}
#[inline]
pub fn chars(&self) -> Chars<'_> {
self.as_str().chars()
}
#[inline]
pub fn reserve(&mut self, capacity: usize) {
self.0.reserve(capacity);
}
#[inline]
pub fn reserve_exact(&mut self, capacity: usize) {
self.0.reserve_exact(capacity);
}
pub fn push(&mut self, ch: char) {
decompose_canonical(ch, |decomp| {
self.0.0.reserve(decomp.len_utf8());
decomp.encode_utf8(unsafe { MaybeUninit::slice_assume_init_mut(self.0.spare_capacity_mut()) });
unsafe { self.0.0.set_len(self.0.len() + decomp.len_utf8()); }
});
}
pub fn push_str(&mut self, string: &str) {
let iter = string.nfd();
let (lower, upper) = iter.size_hint();
self.0.0.reserve(upper.unwrap_or(lower));
for decomp in iter {
self.0.0.reserve(decomp.len_utf8());
decomp.encode_utf8(unsafe { MaybeUninit::slice_assume_init_mut(self.0.spare_capacity_mut()) });
unsafe { self.0.0.set_len(self.0.len() + decomp.len_utf8()); }
}
}
pub fn pop(&mut self) -> Option<char> {
let ch = self.chars().next_back()?;
unsafe { self.0.0.set_len(self.0.len() - ch.len_utf8()); }
unsafe { zero(self.0.as_mut_ptr().add(self.0.len()), ch.len_utf8()); }
Some(ch)
}
}
impl PartialEq<Self> for RefMut<'_> {
#[inline]
fn eq(&self, other: &Self) -> bool {
String::eq_slice(unsafe { self.0.0.inner() }, unsafe { other.0.0.inner() })
}
}
impl PartialEq<Ref<'_>> for RefMut<'_> {
#[inline]
fn eq(&self, other: &Ref<'_>) -> bool {
String::eq_slice(unsafe { self.0.0.inner() }, unsafe { other.0.0.inner() })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn eq() {
assert_eq!(String::from("").borrow(), String::from("").borrow());
assert_eq!(String::from("ÄÖÜäöüß").borrow(), String::from("A\u{308}O\u{308}U\u{308}a\u{308}o\u{308}u\u{308}ß").borrow());
assert_ne!(String::from("empty").borrow(), String::from("").borrow());
assert_ne!(String::from("Warum Thunfische das?").borrow(), String::from("Darum Thunfische das!").borrow());
}
#[test]
fn pop() {
let mut string = String::from("Warum Thunfische das?");
let mut immutable = string.borrow_mut();
assert_eq!(immutable.pop(), Some('?'));
assert_eq!(immutable.pop(), Some('s'));
assert_eq!(immutable.pop(), Some('a'));
assert_eq!(immutable.pop(), Some('d'));
assert_eq!(immutable.pop(), Some(' '));
assert_eq!(immutable, String::from("Warum Thunfische").borrow());
}
}