use crate::VecA;
use crate::alloc::{Allocator, Global};
use std::borrow::Borrow;
use std::fmt::Debug;
use std::ops;
pub type String = StringA<Global>;
#[derive(Clone)]
pub struct StringA<A: Allocator = Global>(VecA<u8, A>);
impl<A: Allocator> StringA<A> {
pub fn new() -> Self
where
A: Default,
{
Self(VecA::new())
}
pub fn with_capacity(cap: usize) -> Self
where
A: Default,
{
Self(VecA::with_capacity(cap))
}
pub fn from_vec(v: VecA<u8, A>) -> Self {
Self(v)
}
#[allow(clippy::should_implement_trait)]
pub fn from_str(s: &str) -> Self
where
A: Default,
{
let mut v = VecA::with_capacity(s.len());
v.extend_from_slice(s.as_bytes());
Self(v)
}
pub fn from_str_in(s: &str, alloc: A) -> Self {
let mut v = VecA::with_capacity_in(s.len(), alloc);
v.extend_from_slice(s.as_bytes());
Self(v)
}
pub fn push_str(&mut self, string: &str) {
self.0.extend_from_slice(string.as_bytes())
}
pub fn as_str(&self) -> &str {
unsafe { str::from_utf8_unchecked(self.0.as_slice()) }
}
pub fn as_mut_str(&mut self) -> &mut str {
unsafe { str::from_utf8_unchecked_mut(self.0.as_mut_slice()) }
}
pub fn replace(&self, pat: &str, with: &str) -> Self
where
A: Default,
{
let mut result = Self::new();
let mut last_end = 0;
for (start, part) in self.match_indices(pat) {
result.push_str(unsafe { self.get_unchecked(last_end..start) });
result.push_str(with);
last_end = start + part.len();
}
result.push_str(unsafe { self.get_unchecked(last_end..self.len()) });
result
}
}
impl<A: Allocator> ops::Deref for StringA<A> {
type Target = str;
fn deref(&self) -> &str {
self.as_str()
}
}
impl<A: Allocator> ops::DerefMut for StringA<A> {
fn deref_mut(&mut self) -> &mut str {
self.as_mut_str()
}
}
impl<A: Allocator> Borrow<str> for StringA<A> {
fn borrow(&self) -> &str {
self.as_str()
}
}
impl<A: Allocator> std::fmt::Display for StringA<A> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&**self, f)
}
}
impl<A: Allocator> Debug for StringA<A> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
std::fmt::Debug::fmt(&**self, f)
}
}
impl<A: Allocator> std::hash::Hash for StringA<A> {
fn hash<H: std::hash::Hasher>(&self, hasher: &mut H) {
(**self).hash(hasher)
}
}
impl<A: Allocator> Eq for StringA<A> {}
impl<A1: Allocator, A2: Allocator> PartialEq<StringA<A2>> for StringA<A1> {
fn eq(&self, other: &StringA<A2>) -> bool {
**self == **other
}
}
impl<A1, A2> PartialOrd<StringA<A2>> for StringA<A1>
where
A1: Allocator,
A2: Allocator,
{
fn partial_cmp(&self, other: &StringA<A2>) -> Option<std::cmp::Ordering> {
PartialOrd::partial_cmp(&**self, &**other)
}
}
impl<A: Allocator> Ord for StringA<A> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
std::cmp::Ord::cmp(&**self, &**other)
}
}
impl<A: Allocator> Default for StringA<A>
where
A: Default,
{
fn default() -> Self {
Self::new()
}
}
impl<A: Allocator> PartialEq<StringA<A>> for str {
fn eq(&self, s: &StringA<A>) -> bool {
self == &**s
}
}
impl<A: Allocator> PartialEq<str> for StringA<A> {
fn eq(&self, s: &str) -> bool {
s == &**self
}
}
impl<A: Allocator> PartialEq<&str> for StringA<A> {
fn eq(&self, s: &&str) -> bool {
&**self == *s
}
}
impl<A: Allocator> PartialEq<StringA<A>> for &str {
fn eq(&self, s: &StringA<A>) -> bool {
&**s == *self
}
}
impl<A: Allocator> std::fmt::Write for StringA<A> {
fn write_str(&mut self, s: &str) -> Result<(), std::fmt::Error> {
self.push_str(s);
Ok(())
}
}
#[cfg(feature = "serde")]
use {
serde::{
Deserialize, Deserializer, Serialize, Serializer,
de::{Error, Visitor},
},
std::fmt,
};
#[cfg(feature = "serde")]
impl<A: Allocator> Serialize for StringA<A> {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(self)
}
}
#[cfg(feature = "serde")]
impl<'de, A: Allocator + Default> Deserialize<'de> for StringA<A> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let v: MyVisitor<A> = MyVisitor {
pd: std::marker::PhantomData,
};
let s = deserializer.deserialize_string(v).unwrap();
Ok(Self::from_str(&s))
}
}
#[cfg(feature = "serde")]
struct MyVisitor<A: Allocator> {
pd: std::marker::PhantomData<A>,
}
#[cfg(feature = "serde")]
impl<'a, A: Allocator + Default> Visitor<'a> for MyVisitor<A> {
type Value = StringA<A>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a string")
}
fn visit_string<E>(self, v: std::string::String) -> Result<Self::Value, E>
where
E: Error,
{
Ok(Self::Value::from_str(&v))
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: Error,
{
Ok(Self::Value::from_str(v))
}
}
#[test]
fn test_string() {
use crate::localalloc::Local;
let mut s: StringA<Local> = StringA::new();
s.push_str("George");
assert!(s == "George");
assert!("George" == s);
}
#[test]
fn test_string_replace() {
use crate::localalloc::Temp;
let mut s = StringA::<Temp>::from_str("George");
s = s.replace("eorge", "raham");
assert!(s == "Graham");
println!("s={}", s);
}
#[test]
fn test_string_write() {
use crate::localalloc::Temp;
let mut output = StringA::<Temp>::new();
use std::fmt::Write;
let x: i64 = -319;
write!(&mut output, "Hello {}! {}", "world", x).unwrap();
assert_eq!(output, "Hello world! -319");
println!("output={}", output);
}