use crate::RootObj;
use crate::convert::PFrom;
use crate::alloc::MemPool;
use crate::clone::PClone;
use crate::stm::*;
use crate::vec::Vec;
use std::string::FromUtf8Error;
use std::borrow::{Cow, ToOwned};
use std::char::decode_utf16;
use std::ops::{self, Index, IndexMut, RangeBounds};
use std::str::pattern::Pattern;
use std::string::String as StdString;
use std::string::ToString as StdToString;
use std::vec::Vec as StdVec;
use std::{fmt, hash, ptr, str};
#[derive(PartialOrd, Eq, Ord)]
pub struct String<A: MemPool> {
vec: Vec<u8, A>,
}
impl<A: MemPool> String<A> {
#[inline]
pub const fn new() -> String<A> {
String { vec: Vec::new() }
}
#[inline]
pub fn with_capacity(capacity: usize, j: &Journal<A>) -> String<A> {
String {
vec: Vec::with_capacity(capacity, j),
}
}
pub fn from_str(s: &str, j: &Journal<A>) -> String<A> {
Self {
vec: Vec::from_slice(s.as_bytes(), j),
}
}
pub(crate) unsafe fn from_str_nolog(s: &str) -> (String<A>, usize) {
let (vec, z) = Vec::from_slice_nolog(s.as_bytes());
(Self { vec }, z)
}
pub fn off(&self) -> u64 {
self.vec.off()
}
#[inline]
pub fn from_utf8(vec: StdVec<u8>, j: &Journal<A>) -> Result<String<A>, FromUtf8Error> {
let s = StdString::from_utf8(vec)?;
Ok(Self::from_str(&s, j))
}
pub fn from_utf8_lossy<'a>(v: &'a [u8], j: &Journal<A>) -> String<A> {
Self::from_str(&StdString::from_utf8_lossy(v), j)
}
pub fn from_utf16(v: &[u16], j: &Journal<A>) -> Result<String<A>, &'static str> {
let mut ret = String::with_capacity(v.len(), j);
for c in decode_utf16(v.iter().cloned()) {
if let Ok(c) = c {
ret.push(c, j);
} else {
return Err("FromUtf16Error");
}
}
Ok(ret)
}
#[inline]
pub fn from_utf16_lossy(v: &[u16], j: &Journal<A>) -> String<A> {
let s = StdString::from_utf16_lossy(v);
String::from_str(&s, j)
}
#[inline]
pub unsafe fn from_utf8_unchecked(bytes: StdVec<u8>, journal: &Journal<A>) -> String<A> {
Self {
vec: Vec::from_slice(bytes.as_slice(), journal),
}
}
#[inline]
pub fn into_bytes(self) -> Vec<u8, A> {
self.vec
}
#[inline]
pub fn as_str(&self) -> &str {
self.vec.to_str()
}
#[inline]
pub fn push_str(&mut self, string: &str, j: &Journal<A>) {
self.vec.extend_from_slice(string.as_bytes(), j)
}
#[inline]
pub fn capacity(&self) -> usize {
self.vec.capacity()
}
#[inline]
pub fn reserve(&mut self, additional: usize, j: &Journal<A>) {
self.vec.reserve(additional, j)
}
#[inline]
pub fn shrink_to_fit(&mut self, j: &Journal<A>) {
self.vec.shrink_to_fit(j)
}
#[inline]
pub fn shrink_to(&mut self, min_capacity: usize, j: &Journal<A>) {
self.vec.shrink_to(min_capacity, j)
}
#[inline]
pub fn push(&mut self, ch: char, j: &Journal<A>) {
match ch.len_utf8() {
1 => self.vec.push(ch as u8, j),
_ => self
.vec
.extend_from_slice(ch.encode_utf8(&mut [0; 4]).as_bytes(), j),
}
}
#[inline]
pub fn as_bytes(&self) -> &[u8] {
&self.vec
}
#[inline]
pub fn truncate(&mut self, new_len: usize) {
if new_len <= self.len() {
assert!(str::is_char_boundary(self.as_str(), new_len));
self.vec.truncate(new_len)
}
}
#[inline]
pub fn pop(&mut self) -> Option<char> {
if self.vec.is_empty() {
None
} else {
let ch = self.as_str().chars().rev().next()?;
let newlen = self.len() - ch.len_utf8();
unsafe {
self.vec.set_len(newlen);
}
Some(ch)
}
}
#[inline]
pub fn remove(&mut self, idx: usize) -> char {
let ch = match self.as_str()[idx..].chars().next() {
Some(ch) => ch,
None => panic!("cannot remove a char from the end of a string"),
};
let next = idx + ch.len_utf8();
let len = self.len();
unsafe {
ptr::copy(
self.vec.as_ptr().add(next),
self.vec.to_slice_mut().as_mut_ptr().add(idx),
len - next,
);
self.vec.set_len(len - (next - idx));
}
ch
}
#[inline]
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(char) -> bool,
{
let len = self.len();
let mut del_bytes = 0;
let mut idx = 0;
while idx < len {
let ch = unsafe {
self.as_str()
.get_unchecked(idx..len)
.chars()
.next()
.unwrap()
};
let ch_len = ch.len_utf8();
if !f(ch) {
del_bytes += ch_len;
} else if del_bytes > 0 {
unsafe {
ptr::copy(
self.vec.as_ptr().add(idx),
self.vec.to_slice_mut().as_mut_ptr().add(idx - del_bytes),
ch_len,
);
}
}
idx += ch_len;
}
if del_bytes > 0 {
unsafe {
self.vec.set_len(len - del_bytes);
}
}
}
#[inline]
pub fn insert(&mut self, idx: usize, ch: char, j: &Journal<A>) {
assert!(self.as_str().is_char_boundary(idx));
let mut bits = [0; 4];
let bits = ch.encode_utf8(&mut bits).as_bytes();
unsafe {
self.insert_bytes(idx, bits, j);
}
}
unsafe fn insert_bytes(&mut self, idx: usize, bytes: &[u8], j: &Journal<A>) {
let len = self.len();
let amt = bytes.len();
self.vec.reserve(amt, j);
ptr::copy(
self.vec.as_ptr().add(idx),
self.vec.to_slice_mut().as_mut_ptr().add(idx + amt),
len - idx,
);
ptr::copy(
bytes.as_ptr(),
self.vec.to_slice_mut().as_mut_ptr().add(idx),
amt,
);
self.vec.set_len(len + amt);
}
#[inline]
pub fn insert_str(&mut self, idx: usize, string: &str, j: &Journal<A>) {
assert!(self.as_str().is_char_boundary(idx));
unsafe {
self.insert_bytes(idx, string.as_bytes(), j);
}
}
#[inline]
pub fn len(&self) -> usize {
self.vec.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub fn split_off(&mut self, at: usize, j: &Journal<A>) -> String<A> {
assert!(self.as_str().is_char_boundary(at));
let other = self.vec.split_off(at, j);
unsafe { String::from_utf8_unchecked(other.as_slice().to_vec(), j) }
}
#[inline]
pub fn clear(&mut self) {
self.vec.clear()
}
pub(crate) unsafe fn free_nolog(&mut self) {
self.vec.free_nolog();
}
pub fn replace_range<R>(&mut self, range: R, replace_with: &str, j: &Journal<A>)
where
R: RangeBounds<usize>,
{
let mut s = self.as_str().to_string();
s.replace_range(range, replace_with);
if s.len() > self.len() {
self.vec.reserve(s.len()-self.len(), j);
}
let slice: &mut [u8] = self.vec.to_slice_mut();
unsafe {
ptr::copy_nonoverlapping(
s.as_bytes() as *const _ as *const u8,
slice as *mut _ as *mut u8,
s.len());
self.vec.set_len(s.len());
}
}
}
impl<A: MemPool> PClone<A> for String<A> {
fn pclone(&self, journal: &Journal<A>) -> Self {
Self {
vec: self.vec.pclone(journal),
}
}
fn pclone_from(&mut self, source: &Self, journal: &Journal<A>) {
self.vec.pclone_from(&source.vec, journal);
}
}
impl<'a, 'b, A: MemPool> Pattern<'a> for &'b String<A> {
type Searcher = <&'b str as Pattern<'a>>::Searcher;
fn into_searcher(self, haystack: &'a str) -> <&'b str as Pattern<'a>>::Searcher {
self.as_str()[..].into_searcher(haystack)
}
#[inline]
fn is_contained_in(self, haystack: &'a str) -> bool {
self.as_str()[..].is_contained_in(haystack)
}
#[inline]
fn is_prefix_of(self, haystack: &'a str) -> bool {
self.as_str()[..].is_prefix_of(haystack)
}
}
impl<A: MemPool> PartialEq for String<A> {
#[inline]
fn eq(&self, other: &String<A>) -> bool {
PartialEq::eq(&self.as_str()[..], &other.as_str()[..])
}
#[inline]
fn ne(&self, other: &String<A>) -> bool {
PartialEq::ne(&self[..], &other[..])
}
}
macro_rules! impl_eq {
($lhs:ty, $rhs: ty) => {
#[allow(unused_lifetimes)]
impl<'a, 'b, A: MemPool> PartialEq<$rhs> for $lhs {
#[inline]
fn eq(&self, other: &$rhs) -> bool {
PartialEq::eq(&self[..], &other[..])
}
#[inline]
fn ne(&self, other: &$rhs) -> bool {
PartialEq::ne(&self[..], &other[..])
}
}
#[allow(unused_lifetimes)]
impl<'a, 'b, A: MemPool> PartialEq<$lhs> for $rhs {
#[inline]
fn eq(&self, other: &$lhs) -> bool {
PartialEq::eq(&self[..], &other[..])
}
#[inline]
fn ne(&self, other: &$lhs) -> bool {
PartialEq::ne(&self[..], &other[..])
}
}
};
}
impl_eq! { String<A>, str }
impl_eq! { String<A>, &'a str }
impl<A: MemPool> Default for String<A> {
#[inline]
fn default() -> String<A> {
String { vec: Vec::default() }
}
}
impl<A: MemPool> RootObj<A> for String<A> {
#[inline]
fn init(j: &Journal<A>) -> String<A> {
String { vec: Vec::init(j) }
}
}
impl<A: MemPool> fmt::Display for String<A> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&**self, f)
}
}
impl<A: MemPool> fmt::Debug for String<A> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<A: MemPool> hash::Hash for String<A> {
#[inline]
fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
(**self).hash(hasher)
}
}
impl<A: MemPool> ops::Index<ops::Range<usize>> for String<A> {
type Output = str;
#[inline]
fn index(&self, index: ops::Range<usize>) -> &str {
&self[..][index]
}
}
impl<A: MemPool> ops::Index<ops::RangeTo<usize>> for String<A> {
type Output = str;
#[inline]
fn index(&self, index: ops::RangeTo<usize>) -> &str {
&self[..][index]
}
}
impl<A: MemPool> ops::Index<ops::RangeFrom<usize>> for String<A> {
type Output = str;
#[inline]
fn index(&self, index: ops::RangeFrom<usize>) -> &str {
&self[..][index]
}
}
impl<A: MemPool> ops::Index<ops::RangeFull> for String<A> {
type Output = str;
#[inline]
fn index(&self, _index: ops::RangeFull) -> &str {
unsafe { str::from_utf8_unchecked(&self.vec) }
}
}
impl<A: MemPool> ops::Index<ops::RangeInclusive<usize>> for String<A> {
type Output = str;
#[inline]
fn index(&self, index: ops::RangeInclusive<usize>) -> &str {
Index::index(&**self, index)
}
}
impl<A: MemPool> ops::Index<ops::RangeToInclusive<usize>> for String<A> {
type Output = str;
#[inline]
fn index(&self, index: ops::RangeToInclusive<usize>) -> &str {
Index::index(&**self, index)
}
}
impl<A: MemPool> ops::IndexMut<ops::Range<usize>> for String<A> {
#[inline]
fn index_mut(&mut self, index: ops::Range<usize>) -> &mut str {
&mut self[..][index]
}
}
impl<A: MemPool> ops::IndexMut<ops::RangeTo<usize>> for String<A> {
#[inline]
fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut str {
&mut self[..][index]
}
}
impl<A: MemPool> ops::IndexMut<ops::RangeFrom<usize>> for String<A> {
#[inline]
fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut str {
&mut self[..][index]
}
}
impl<A: MemPool> ops::IndexMut<ops::RangeFull> for String<A> {
#[inline]
fn index_mut(&mut self, _index: ops::RangeFull) -> &mut str {
unsafe { str::from_utf8_unchecked_mut(self.vec.to_slice_mut()) }
}
}
impl<A: MemPool> ops::IndexMut<ops::RangeInclusive<usize>> for String<A> {
#[inline]
fn index_mut(&mut self, index: ops::RangeInclusive<usize>) -> &mut str {
IndexMut::index_mut(&mut **self, index)
}
}
impl<A: MemPool> ops::IndexMut<ops::RangeToInclusive<usize>> for String<A> {
#[inline]
fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut str {
IndexMut::index_mut(&mut **self, index)
}
}
impl<A: MemPool> ops::Deref for String<A> {
type Target = str;
#[inline]
fn deref(&self) -> &str {
unsafe { str::from_utf8_unchecked(&self.vec) }
}
}
impl<A: MemPool> ops::DerefMut for String<A> {
#[inline]
fn deref_mut(&mut self) -> &mut str {
unsafe { str::from_utf8_unchecked_mut(self.vec.to_slice_mut()) }
}
}
pub trait ToPStringSlice<A: MemPool> {
fn to_pstring(&self, journal: &Journal<A>) -> StdVec<String<A>>;
}
impl<T: fmt::Display, A: MemPool> ToPStringSlice<A> for [T] {
#[inline]
default fn to_pstring(&self, journal: &Journal<A>) -> StdVec<String<A>> {
let mut vec = StdVec::<String<A>>::with_capacity(self.len());
for v in self {
use fmt::Write;
let mut buf = StdString::new();
buf.write_fmt(format_args!("{}", v))
.expect("a Display implementation returned an error unexpectedly");
buf.shrink_to_fit();
vec.push(String::from_str(&buf, journal));
}
vec
}
}
impl<A: MemPool> ToPStringSlice<A> for StdVec<&str> {
#[inline]
default fn to_pstring(&self, journal: &Journal<A>) -> StdVec<String<A>> {
let mut vec = StdVec::<String<A>>::with_capacity(self.len());
for buf in self {
vec.push(String::from_str(buf, journal));
}
vec
}
}
pub trait ToPString<A: MemPool> {
fn to_pstring(&self, journal: &Journal<A>) -> String<A>;
}
impl<T: fmt::Display + ?Sized, A: MemPool> ToPString<A> for T {
#[inline]
default fn to_pstring(&self, journal: &Journal<A>) -> String<A> {
use fmt::Write;
let mut buf = StdString::new();
buf.write_fmt(format_args!("{}", self))
.expect("a Display implementation returned an error unexpectedly");
buf.shrink_to_fit();
String::from_str(&buf, journal)
}
}
impl<A: MemPool> ToPString<A> for str {
#[inline]
fn to_pstring(&self, journal: &Journal<A>) -> String<A> {
String::from_str(self, journal)
}
}
impl<A: MemPool> ToPString<A> for Cow<'_, str> {
#[inline]
fn to_pstring(&self, journal: &Journal<A>) -> String<A> {
String::from_str(&self[..].to_owned(), journal)
}
}
impl<A: MemPool> ToPString<A> for StdString {
#[inline]
fn to_pstring(&self, journal: &Journal<A>) -> String<A> {
String::from_str(self, journal)
}
}
impl<A: MemPool> StdToString for String<A> {
#[inline]
fn to_string(&self) -> StdString {
self.as_str().to_owned()
}
}
impl<A: MemPool> AsRef<str> for String<A> {
#[inline]
fn as_ref(&self) -> &str {
self
}
}
impl<A: MemPool> AsMut<str> for String<A> {
#[inline]
fn as_mut(&mut self) -> &mut str {
self
}
}
impl<A: MemPool> AsRef<[u8]> for String<A> {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl<A: MemPool> PFrom<&str, A> for String<A> {
#[inline]
fn pfrom(s: &str, j: &Journal<A>) -> String<A> {
Self::from_str(s, j)
}
}
impl<'a, A: MemPool> From<&'a String<A>> for Cow<'a, str> {
#[inline]
fn from(s: &'a String<A>) -> Cow<'a, str> {
Cow::Borrowed(s)
}
}
impl<A: MemPool> From<String<A>> for Vec<u8, A> {
fn from(string: String<A>) -> Vec<u8, A> {
string.into_bytes()
}
}
impl<A: MemPool> fmt::Write for String<A> {
#[inline]
fn write_str(&mut self, s: &str) -> fmt::Result {
let j = Journal::try_current()
.expect("This function should be called only inside a transaction")
.0;
self.push_str(s, unsafe { &*j });
Ok(())
}
#[inline]
fn write_char(&mut self, c: char) -> fmt::Result {
let j = Journal::try_current()
.expect("This function should be called only inside a transaction")
.0;
self.push(c, unsafe { &*j });
Ok(())
}
}
#[cfg(test)]
mod test {
use crate::default::*;
type A = Allocator;
#[test]
fn test_pstring() {
let root = A::open::<Pbox<PRefCell<PString>>>("sb6.pool", open_flags::O_CFNE).unwrap();
let _ = A::transaction(|j| {
println!("RootObj = {}", root);
let mut root = root.borrow_mut(j);
*root = 5129483505_u64.to_pstring(j);
println!("RootObj = {}", root);
});
println!("Usage = {}", A::used());
}
#[test]
fn test_list_pstring() {}
}