use super::{Assert, EStr, Encoder, Utf8Chunks};
use alloc::{borrow::ToOwned, string::String};
use core::{borrow::Borrow, cmp::Ordering, hash, marker::PhantomData, ops::Deref};
#[derive(Clone, Default)]
pub struct EString<E: Encoder> {
pub(crate) buf: String,
encoder: PhantomData<E>,
}
impl<E: Encoder> Deref for EString<E> {
type Target = EStr<E>;
fn deref(&self) -> &EStr<E> {
EStr::new_validated(&self.buf)
}
}
impl<E: Encoder> EString<E> {
pub(crate) fn new_validated(buf: String) -> Self {
EString {
buf,
encoder: PhantomData,
}
}
#[must_use]
pub fn new() -> Self {
Self::new_validated(String::new())
}
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self::new_validated(String::with_capacity(capacity))
}
#[must_use]
pub fn as_estr(&self) -> &EStr<E> {
self
}
#[must_use]
pub fn capacity(&self) -> usize {
self.buf.capacity()
}
pub fn encode<SubE: Encoder>(&mut self, s: &(impl AsRef<[u8]> + ?Sized)) {
let () = Assert::<SubE, E>::L_IS_SUB_ENCODER_OF_R;
let () = EStr::<SubE>::ASSERT_ALLOWS_PCT_ENCODED;
for chunk in Utf8Chunks::new(s.as_ref()) {
for ch in chunk.valid().chars() {
SubE::TABLE.encode(ch, &mut self.buf);
}
for &x in chunk.invalid() {
super::encode_byte(x, &mut self.buf);
}
}
}
pub fn push(&mut self, ch: char) {
assert!(E::TABLE.allows(ch), "table does not allow the char");
self.buf.push(ch);
}
pub fn push_estr(&mut self, s: &EStr<E>) {
self.buf.push_str(s.as_str());
}
pub fn clear(&mut self) {
self.buf.clear();
}
#[must_use]
pub fn into_string(self) -> String {
self.buf
}
}
impl<E: Encoder> AsRef<EStr<E>> for EString<E> {
fn as_ref(&self) -> &EStr<E> {
self
}
}
impl<E: Encoder> AsRef<str> for EString<E> {
fn as_ref(&self) -> &str {
&self.buf
}
}
impl<E: Encoder> Borrow<EStr<E>> for EString<E> {
fn borrow(&self) -> &EStr<E> {
self
}
}
impl<E: Encoder> From<&EStr<E>> for EString<E> {
fn from(s: &EStr<E>) -> Self {
s.to_owned()
}
}
impl<E: Encoder> PartialEq for EString<E> {
fn eq(&self, other: &Self) -> bool {
self.as_str() == other.as_str()
}
}
impl<E: Encoder> PartialEq<EStr<E>> for EString<E> {
fn eq(&self, other: &EStr<E>) -> bool {
self.as_str() == other.as_str()
}
}
impl<E: Encoder> PartialEq<EString<E>> for EStr<E> {
fn eq(&self, other: &EString<E>) -> bool {
self.as_str() == other.as_str()
}
}
impl<E: Encoder> PartialEq<&EStr<E>> for EString<E> {
fn eq(&self, other: &&EStr<E>) -> bool {
self.as_str() == other.as_str()
}
}
impl<E: Encoder> PartialEq<EString<E>> for &EStr<E> {
fn eq(&self, other: &EString<E>) -> bool {
self.as_str() == other.as_str()
}
}
impl<E: Encoder> PartialEq<str> for EString<E> {
fn eq(&self, other: &str) -> bool {
self.as_str() == other
}
}
impl<E: Encoder> PartialEq<EString<E>> for str {
fn eq(&self, other: &EString<E>) -> bool {
self == other.as_str()
}
}
impl<E: Encoder> PartialEq<&str> for EString<E> {
fn eq(&self, other: &&str) -> bool {
self.as_str() == *other
}
}
impl<E: Encoder> PartialEq<EString<E>> for &str {
fn eq(&self, other: &EString<E>) -> bool {
*self == other.as_str()
}
}
impl<E: Encoder> Eq for EString<E> {}
impl<E: Encoder> hash::Hash for EString<E> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.buf.hash(state);
}
}
impl<E: Encoder> PartialOrd for EString<E> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<E: Encoder> Ord for EString<E> {
fn cmp(&self, other: &Self) -> Ordering {
self.inner.cmp(&other.inner)
}
}