use core::borrow::Borrow;
use core::cmp::Ordering;
use core::error::Error;
use core::fmt;
use core::ops::Deref;
use core::str::{self, Utf8Error};
#[cfg(feature = "alloc")]
use rust_alloc::borrow::Cow;
use crate::de::UnsizedVisitor;
use crate::{Context, Decode, Decoder, Encode, Encoder};
use super::{AllocError, Allocator, GlobalAllocator, Vec};
#[inline]
pub(crate) fn collect_string<A>(alloc: A, value: impl fmt::Display) -> Result<String<A>, AllocError>
where
A: Allocator,
{
use core::fmt::Write;
let mut string = String::new_in(alloc);
if write!(string, "{value}").is_err() {
return Err(AllocError);
}
Ok(string)
}
pub struct String<A>
where
A: Allocator,
{
vec: Vec<u8, A>,
}
pub struct FromUtf8Error<A>
where
A: Allocator,
{
bytes: Vec<u8, A>,
error: Utf8Error,
}
impl<A> String<A>
where
A: Allocator,
{
#[inline]
pub fn new_in(alloc: A) -> Self {
Self {
vec: Vec::new_in(alloc),
}
}
#[inline]
pub fn with_capacity_in(capacity: usize, alloc: A) -> Result<Self, AllocError> {
Ok(Self {
vec: Vec::with_capacity_in(capacity, alloc)?,
})
}
#[cfg(feature = "alloc")]
pub fn into_std(self) -> Result<rust_alloc::string::String, Self> {
match self.vec.into_std() {
Ok(vec) => {
unsafe { Ok(rust_alloc::string::String::from_utf8_unchecked(vec)) }
}
Err(vec) => Err(Self { vec }),
}
}
#[inline]
pub fn from_utf8(vec: Vec<u8, A>) -> Result<String<A>, FromUtf8Error<A>> {
match str::from_utf8(&vec) {
Ok(..) => Ok(String { vec }),
Err(e) => Err(FromUtf8Error {
bytes: vec,
error: e,
}),
}
}
#[inline]
#[must_use]
pub unsafe fn from_utf8_unchecked(vec: Vec<u8, A>) -> String<A> {
String { vec }
}
#[inline]
#[must_use = "`self` will be dropped if the result is not used"]
pub fn into_bytes(self) -> Vec<u8, A> {
self.vec
}
#[inline]
pub fn as_str(&self) -> &str {
unsafe { str::from_utf8_unchecked(self.vec.as_slice()) }
}
#[inline]
pub fn push(&mut self, c: char) -> Result<(), AllocError> {
self.vec
.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes())
}
#[inline]
pub fn push_str(&mut self, s: &str) -> Result<(), AllocError> {
self.vec.extend_from_slice(s.as_bytes())
}
#[inline]
#[must_use]
pub fn capacity(&self) -> usize {
self.vec.capacity()
}
#[inline]
#[must_use]
pub fn len(&self) -> usize {
self.vec.len()
}
#[inline]
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<A> Clone for String<A>
where
A: GlobalAllocator,
{
#[inline]
fn clone(&self) -> Self {
Self {
vec: self.vec.clone(),
}
}
}
impl<A> fmt::Write for String<A>
where
A: Allocator,
{
#[inline]
fn write_char(&mut self, c: char) -> fmt::Result {
self.push(c).map_err(|_| fmt::Error)
}
#[inline]
fn write_str(&mut self, s: &str) -> fmt::Result {
self.push_str(s).map_err(|_| fmt::Error)
}
}
impl<A> Deref for String<A>
where
A: Allocator,
{
type Target = str;
#[inline]
fn deref(&self) -> &str {
unsafe { str::from_utf8_unchecked(self.vec.as_slice()) }
}
}
impl<A> fmt::Display for String<A>
where
A: Allocator,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_str().fmt(f)
}
}
impl<A> fmt::Debug for String<A>
where
A: Allocator,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_str().fmt(f)
}
}
impl<A> AsRef<str> for String<A>
where
A: Allocator,
{
#[inline]
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl<A> PartialEq for String<A>
where
A: Allocator,
{
#[inline]
fn eq(&self, other: &Self) -> bool {
self.as_str().eq(other.as_str())
}
}
impl<A> Eq for String<A> where A: Allocator {}
impl<A> PartialOrd for String<A>
where
A: Allocator,
{
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<A> Ord for String<A>
where
A: Allocator,
{
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
self.as_str().cmp(other.as_str())
}
}
impl<A> Borrow<str> for String<A>
where
A: Allocator,
{
#[inline]
fn borrow(&self) -> &str {
self
}
}
macro_rules! impl_eq {
($lhs:ty, $rhs: ty) => {
#[allow(unused_lifetimes)]
impl<'a, 'b, A> PartialEq<$rhs> for $lhs
where
A: Allocator,
{
#[inline]
fn eq(&self, other: &$rhs) -> bool {
PartialEq::eq(&self[..], &other[..])
}
#[inline]
#[allow(clippy::partialeq_ne_impl)]
fn ne(&self, other: &$rhs) -> bool {
PartialEq::ne(&self[..], &other[..])
}
}
#[allow(unused_lifetimes)]
impl<'a, 'b, A> PartialEq<$lhs> for $rhs
where
A: Allocator,
{
#[inline]
fn eq(&self, other: &$lhs) -> bool {
PartialEq::eq(&self[..], &other[..])
}
#[inline]
#[allow(clippy::partialeq_ne_impl)]
fn ne(&self, other: &$lhs) -> bool {
PartialEq::ne(&self[..], &other[..])
}
}
};
}
impl_eq! { String<A>, str }
impl_eq! { String<A>, &'a str }
#[cfg(feature = "alloc")]
impl_eq! { Cow<'a, str>, String<A> }
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
impl<A> From<rust_alloc::string::String> for String<A>
where
A: GlobalAllocator,
{
#[inline]
fn from(value: rust_alloc::string::String) -> Self {
Self {
vec: Vec::from(value.into_bytes()),
}
}
}
impl<A> fmt::Display for FromUtf8Error<A>
where
A: Allocator,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.error, f)
}
}
impl<A> Error for FromUtf8Error<A> where A: Allocator {}
impl<A, B> PartialEq<FromUtf8Error<B>> for FromUtf8Error<A>
where
A: Allocator,
B: Allocator,
{
#[inline]
fn eq(&self, other: &FromUtf8Error<B>) -> bool {
self.bytes == other.bytes && self.error == other.error
}
}
impl<A> fmt::Debug for FromUtf8Error<A>
where
A: Allocator,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FromUtf8Error")
.field("bytes", &self.bytes)
.field("error", &self.error)
.finish()
}
}
impl<A> FromUtf8Error<A>
where
A: Allocator,
{
#[inline]
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
&self.bytes[..]
}
#[inline]
#[must_use = "`self` will be dropped if the result is not used"]
pub fn into_bytes(self) -> Vec<u8, A> {
self.bytes
}
#[inline]
#[must_use]
pub fn utf8_error(&self) -> Utf8Error {
self.error
}
}
impl<M, A> Encode<M> for String<A>
where
A: Allocator,
{
type Encode = str;
const IS_BITWISE_ENCODE: bool = false;
#[inline]
fn encode<E>(&self, encoder: E) -> Result<(), E::Error>
where
E: Encoder<Mode = M>,
{
self.as_str().encode(encoder)
}
#[inline]
fn as_encode(&self) -> &Self::Encode {
self
}
}
impl<'de, M, A> Decode<'de, M, A> for String<A>
where
A: Allocator,
{
const IS_BITWISE_DECODE: bool = false;
#[inline]
fn decode<D>(decoder: D) -> Result<Self, D::Error>
where
D: Decoder<'de, Mode = M, Allocator = A>,
{
struct Visitor;
#[crate::trait_defaults(crate)]
impl<C> UnsizedVisitor<'_, C, str> for Visitor
where
C: Context,
{
type Ok = String<Self::Allocator>;
#[inline]
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "string")
}
#[inline]
fn visit_owned(
self,
_: C,
value: String<Self::Allocator>,
) -> Result<Self::Ok, C::Error> {
Ok(value)
}
#[inline]
fn visit_ref(self, cx: C, string: &str) -> Result<Self::Ok, C::Error> {
let mut s = String::new_in(cx.alloc());
s.push_str(string).map_err(cx.map())?;
Ok(s)
}
}
decoder.decode_string(Visitor)
}
}