use std::{
borrow::{Borrow, BorrowMut},
convert::TryFrom,
fmt::{Debug, Display},
hash::Hash,
ops::{Deref, DerefMut},
str::Utf8Error,
};
use bytes::BytesMut;
use crate::Text;
#[derive(Default)]
pub struct TextMut(BytesMut);
impl TextMut {
pub fn new() -> Self {
Self(BytesMut::new())
}
pub fn with_capacity(capacity: usize) -> Self {
Self(BytesMut::with_capacity(capacity))
}
pub fn copy_from(s: impl AsRef<str>) -> Self {
let s = s.as_ref();
let mut t = Self::with_capacity(s.len());
t.push_str(s);
t
}
pub fn from_utf8(b: BytesMut) -> Result<Self, Utf8Error> {
let _ = std::str::from_utf8(b.as_ref())?;
Ok(Self(b))
}
#[inline]
pub const unsafe fn from_utf8_unchecked(b: BytesMut) -> Self {
Self(b)
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn capacity(&self) -> usize {
self.0.capacity()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn freeze(self) -> Text {
unsafe { Text::from_utf8_unchecked(self.0.freeze()) }
}
pub fn reserve(&mut self, additional: usize) {
self.0.reserve(additional)
}
pub fn clear(&mut self) {
self.0.clear()
}
pub const fn as_bytes(&self) -> &BytesMut {
&self.0
}
pub unsafe fn as_bytes_mut(&mut self) -> &mut BytesMut {
&mut self.0
}
pub fn into_bytes_mut(self) -> BytesMut {
self.0
}
pub fn split_at(mut self, index: usize) -> Result<(Self, Self), Self> {
soft_assert::soft_assert!(self.is_char_boundary(index), Err(self));
let right = self.0.split_off(index);
Ok((Self(self.0), Self(right)))
}
pub fn split_off(&mut self, index: usize) -> Option<Self> {
soft_assert::soft_assert!(self.is_char_boundary(index));
let right = self.0.split_off(index);
Some(Self(right))
}
pub fn split_to(&mut self, index: usize) -> Option<Self> {
soft_assert::soft_assert!(self.is_char_boundary(index));
let right = self.0.split_to(index);
Some(Self(right))
}
pub fn push_str(&mut self, s: impl AsRef<str>) {
self.0.extend_from_slice(s.as_ref().as_bytes())
}
pub fn push(&mut self, c: char) {
let mut buf = [0; 4];
let s = c.encode_utf8(&mut buf);
self.push_str(s);
}
pub fn join(mut self, other: TextMut) -> TextMut {
self.0.unsplit(other.0);
self
}
fn as_str(&self) -> &str {
unsafe { std::str::from_utf8_unchecked(self.0.as_ref()) }
}
fn as_str_mut(&mut self) -> &mut str {
unsafe { std::str::from_utf8_unchecked_mut(self.0.as_mut()) }
}
}
impl AsRef<str> for TextMut {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl AsMut<str> for TextMut {
fn as_mut(&mut self) -> &mut str {
self.as_str_mut()
}
}
impl Borrow<str> for TextMut {
fn borrow(&self) -> &str {
self.as_str()
}
}
impl BorrowMut<str> for TextMut {
fn borrow_mut(&mut self) -> &mut str {
self.as_str_mut()
}
}
impl Deref for TextMut {
type Target = str;
fn deref(&self) -> &Self::Target {
self.as_str()
}
}
impl DerefMut for TextMut {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_str_mut()
}
}
impl TryFrom<BytesMut> for TextMut {
type Error = Utf8Error;
fn try_from(b: BytesMut) -> Result<Self, Self::Error> {
Self::from_utf8(b)
}
}
impl From<TextMut> for BytesMut {
fn from(t: TextMut) -> Self {
t.into_bytes_mut()
}
}
impl From<TextMut> for Text {
fn from(t: TextMut) -> Self {
t.freeze()
}
}
impl Display for TextMut {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Display::fmt(self.as_str(), f)
}
}
impl Debug for TextMut {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Debug::fmt(self.as_str(), f)
}
}
impl PartialEq for TextMut {
fn eq(&self, other: &Self) -> bool {
(&**self).eq(&**other)
}
}
impl Eq for TextMut {}
impl PartialEq<&TextMut> for TextMut {
fn eq(&self, other: &&TextMut) -> bool {
(&**self).eq(&***other)
}
}
impl PartialEq<&mut TextMut> for TextMut {
fn eq(&self, other: &&mut TextMut) -> bool {
(&**self).eq(&***other)
}
}
impl PartialOrd for TextMut {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq<str> for TextMut {
fn eq(&self, other: &str) -> bool {
(&**self).eq(other)
}
}
impl PartialEq<&str> for TextMut {
fn eq(&self, other: &&str) -> bool {
(&**self).eq(*other)
}
}
impl PartialEq<&mut str> for TextMut {
fn eq(&self, other: &&mut str) -> bool {
(&**self).eq(*other)
}
}
impl PartialOrd<str> for TextMut {
fn partial_cmp(&self, other: &str) -> Option<std::cmp::Ordering> {
(&**self).partial_cmp(other)
}
}
impl PartialOrd<&str> for TextMut {
fn partial_cmp(&self, other: &&str) -> Option<std::cmp::Ordering> {
(&**self).partial_cmp(*other)
}
}
impl PartialOrd<&mut str> for TextMut {
fn partial_cmp(&self, other: &&mut str) -> Option<std::cmp::Ordering> {
(&**self).partial_cmp(*other)
}
}
impl PartialEq<String> for TextMut {
fn eq(&self, other: &String) -> bool {
(&**self).eq(other)
}
}
impl PartialEq<&String> for TextMut {
fn eq(&self, other: &&String) -> bool {
(&**self).eq(*other)
}
}
impl PartialEq<&mut String> for TextMut {
fn eq(&self, other: &&mut String) -> bool {
(&**self).eq(*other)
}
}
impl PartialOrd<String> for TextMut {
fn partial_cmp(&self, other: &String) -> Option<std::cmp::Ordering> {
(&**self).partial_cmp(&**other)
}
}
impl PartialOrd<&String> for TextMut {
fn partial_cmp(&self, other: &&String) -> Option<std::cmp::Ordering> {
(&**self).partial_cmp(&***other)
}
}
impl PartialOrd<&mut String> for TextMut {
fn partial_cmp(&self, other: &&mut String) -> Option<std::cmp::Ordering> {
(&**self).partial_cmp(&***other)
}
}
impl PartialEq<Text> for TextMut {
fn eq(&self, other: &Text) -> bool {
(&**self).eq(&**other)
}
}
impl PartialEq<&Text> for TextMut {
fn eq(&self, other: &&Text) -> bool {
(&**self).eq(&***other)
}
}
impl PartialEq<&mut Text> for TextMut {
fn eq(&self, other: &&mut Text) -> bool {
(&**self).eq(&***other)
}
}
impl PartialOrd<Text> for TextMut {
fn partial_cmp(&self, other: &Text) -> Option<std::cmp::Ordering> {
(&**self).partial_cmp(&**other)
}
}
impl PartialOrd<&Text> for TextMut {
fn partial_cmp(&self, other: &&Text) -> Option<std::cmp::Ordering> {
(&**self).partial_cmp(&***other)
}
}
impl PartialOrd<&mut Text> for TextMut {
fn partial_cmp(&self, other: &&mut Text) -> Option<std::cmp::Ordering> {
(&**self).partial_cmp(&***other)
}
}
impl Hash for TextMut {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
(&**self).hash(state);
}
}
impl Extend<char> for TextMut {
fn extend<T>(&mut self, iter: T)
where
T: IntoIterator<Item = char>,
{
let iterator = iter.into_iter();
let (lower_bound, _) = iterator.size_hint();
self.reserve(lower_bound);
iterator.for_each(move |c| self.push(c));
}
}
impl<'a> Extend<&'a str> for TextMut {
fn extend<T>(&mut self, iter: T)
where
T: IntoIterator<Item = &'a str>,
{
iter.into_iter().for_each(move |s| self.push_str(s));
}
}
impl Extend<String> for TextMut {
fn extend<T>(&mut self, iter: T)
where
T: IntoIterator<Item = String>,
{
iter.into_iter().for_each(move |s| self.push_str(s));
}
}
impl<'a> Extend<&'a String> for TextMut {
fn extend<T>(&mut self, iter: T)
where
T: IntoIterator<Item = &'a String>,
{
iter.into_iter().for_each(move |s| self.push_str(s));
}
}
impl Extend<Text> for TextMut {
fn extend<T>(&mut self, iter: T)
where
T: IntoIterator<Item = Text>,
{
iter.into_iter().for_each(move |s| self.push_str(s));
}
}
impl<'a> Extend<&'a Text> for TextMut {
fn extend<T>(&mut self, iter: T)
where
T: IntoIterator<Item = &'a Text>,
{
iter.into_iter().for_each(move |s| self.push_str(s));
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn text_mut_create() {
let mut buf = TextMut::new();
buf.push_str("Hello, ");
buf.push_str("world!");
assert_eq!(buf, "Hello, world!");
buf.push(' ');
buf.extend(vec!["Woo, ", "unit tests!"]);
assert_eq!(buf, "Hello, world! Woo, unit tests!");
buf.extend(vec![String::from(" I'm in a String.")]);
buf.extend(vec![Text::from(" Ooo, text")]);
assert_eq!(
format!("{}", buf),
String::from("Hello, world! Woo, unit tests! I'm in a String. Ooo, text")
);
buf.clear();
assert_eq!(buf, "");
}
}