#[cfg(feature = "serde")]
mod serde;
pub use self::try_to_string::TryToString;
pub(crate) mod try_to_string;
#[cfg(feature = "alloc")]
use core::alloc::Layout;
use core::borrow::Borrow;
use core::cmp::Ordering;
use core::fmt;
use core::hash;
use core::iter::FusedIterator;
#[cfg(feature = "alloc")]
use core::mem::ManuallyDrop;
use core::ops::Bound::{Excluded, Included, Unbounded};
use core::ops::{self, Index, IndexMut, Range, RangeBounds};
use core::ptr;
use core::slice;
use core::str::{from_utf8, from_utf8_unchecked, from_utf8_unchecked_mut};
use core::str::{Chars, Utf8Error};
use crate::alloc::{Allocator, Global};
use crate::borrow::Cow;
use crate::boxed::Box;
use crate::clone::TryClone;
use crate::error::Error;
use crate::fmt::TryWrite;
use crate::iter::{TryExtend, TryFromIteratorIn, TryJoin};
use crate::slice::range as slice_range;
#[cfg(test)]
use crate::testing::*;
use crate::vec::Vec;
pub struct String<A: Allocator = Global> {
vec: Vec<u8, A>,
}
impl String {
#[inline]
#[must_use]
pub const fn new() -> Self {
String { vec: Vec::new() }
}
#[inline]
pub fn try_with_capacity(capacity: usize) -> Result<Self, Error> {
Ok(String {
vec: Vec::try_with_capacity_in(capacity, Global)?,
})
}
#[cfg(feature = "alloc")]
pub fn into_std(self) -> ::rust_alloc::string::String {
unsafe { ::rust_alloc::string::String::from_utf8_unchecked(self.vec.into_std()) }
}
#[cfg(test)]
pub fn from(value: &str) -> Self {
Self::try_from(value).abort()
}
}
pub struct FromUtf8Error<A: Allocator = Global> {
bytes: Vec<u8, A>,
error: Utf8Error,
}
impl<A: Allocator> fmt::Debug for FromUtf8Error<A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FromUtf8Error")
.field("bytes", &self.bytes)
.field("error", &self.error)
.finish()
}
}
impl<A: Allocator> PartialEq for FromUtf8Error<A> {
fn eq(&self, other: &Self) -> bool {
self.bytes == other.bytes && self.error == other.error
}
}
impl<A: Allocator> Eq for FromUtf8Error<A> {}
impl<A: Allocator> String<A> {
#[inline]
#[must_use]
pub fn new_in(alloc: A) -> String<A> {
String {
vec: Vec::new_in(alloc),
}
}
#[inline]
pub fn allocator(&self) -> &A {
self.vec.allocator()
}
#[inline]
pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result<String<A>, Error> {
Ok(String {
vec: Vec::try_with_capacity_in(capacity, alloc)?,
})
}
#[inline]
pub fn from_utf8(vec: Vec<u8, A>) -> Result<String<A>, FromUtf8Error<A>> {
match from_utf8(&vec) {
Ok(..) => Ok(String { vec }),
Err(e) => Err(FromUtf8Error {
bytes: vec,
error: e,
}),
}
}
#[inline]
pub unsafe fn from_raw_parts_in(
buf: *mut u8,
length: usize,
capacity: usize,
alloc: A,
) -> String<A> {
unsafe {
String {
vec: Vec::from_raw_parts_in(buf, length, capacity, alloc),
}
}
}
#[inline]
#[must_use]
pub unsafe fn from_utf8_unchecked(bytes: Vec<u8, A>) -> String<A> {
String { vec: bytes }
}
#[inline]
#[must_use = "`self` will be dropped if the result is not used"]
pub fn into_bytes(self) -> Vec<u8, A> {
self.vec
}
#[inline]
#[must_use]
pub fn as_str(&self) -> &str {
self
}
#[inline]
#[must_use]
pub fn as_mut_str(&mut self) -> &mut str {
self
}
#[inline]
pub fn try_push_str(&mut self, string: &str) -> Result<(), Error> {
self.vec.try_extend_from_slice(string.as_bytes())
}
#[cfg(test)]
pub(crate) fn push_str(&mut self, string: &str) {
self.try_push_str(string).abort()
}
#[inline]
#[must_use]
pub fn capacity(&self) -> usize {
self.vec.capacity()
}
pub fn try_reserve(&mut self, additional: usize) -> Result<(), Error> {
self.vec.try_reserve(additional)
}
pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), Error> {
self.vec.try_reserve_exact(additional)
}
#[inline]
pub fn try_shrink_to_fit(&mut self) -> Result<(), Error> {
self.vec.try_shrink_to_fit()
}
#[inline]
pub fn try_shrink_to(&mut self, min_capacity: usize) -> Result<(), Error> {
self.vec.try_shrink_to(min_capacity)
}
#[inline]
pub fn try_push(&mut self, ch: char) -> Result<(), Error> {
match ch.len_utf8() {
1 => self.vec.try_push(ch as u8),
_ => self
.vec
.try_extend_from_slice(ch.encode_utf8(&mut [0; 4]).as_bytes()),
}
}
#[inline]
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
&self.vec
}
#[inline]
pub fn truncate(&mut self, new_len: usize) {
if new_len <= self.len() {
assert!(self.is_char_boundary(new_len));
self.vec.truncate(new_len)
}
}
#[inline]
pub fn pop(&mut self) -> Option<char> {
let ch = self.chars().next_back()?;
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[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.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,
{
struct SetLenOnDrop<'a, A: Allocator> {
s: &'a mut String<A>,
idx: usize,
del_bytes: usize,
}
impl<A: Allocator> Drop for SetLenOnDrop<'_, A> {
fn drop(&mut self) {
let new_len = self.idx - self.del_bytes;
debug_assert!(new_len <= self.s.len());
unsafe { self.s.vec.set_len(new_len) };
}
}
let len = self.len();
let mut guard = SetLenOnDrop {
s: self,
idx: 0,
del_bytes: 0,
};
while guard.idx < len {
let ch =
unsafe { guard.s.get_unchecked(guard.idx..len).chars().next().unwrap_unchecked() };
let ch_len = ch.len_utf8();
if !f(ch) {
guard.del_bytes += ch_len;
} else if guard.del_bytes > 0 {
ch.encode_utf8(unsafe {
slice::from_raw_parts_mut(
guard.s.as_mut_ptr().add(guard.idx - guard.del_bytes),
ch.len_utf8(),
)
});
}
guard.idx += ch_len;
}
drop(guard);
}
#[inline]
pub fn try_insert(&mut self, idx: usize, ch: char) -> Result<(), Error> {
assert!(self.is_char_boundary(idx));
let mut bits = [0; 4];
let bits = ch.encode_utf8(&mut bits).as_bytes();
unsafe {
self.insert_bytes(idx, bits)?;
}
Ok(())
}
unsafe fn insert_bytes(&mut self, idx: usize, bytes: &[u8]) -> Result<(), Error> {
let len = self.len();
let amt = bytes.len();
self.vec.try_reserve(amt)?;
unsafe {
ptr::copy(
self.vec.as_ptr().add(idx),
self.vec.as_mut_ptr().add(idx + amt),
len - idx,
);
ptr::copy_nonoverlapping(bytes.as_ptr(), self.vec.as_mut_ptr().add(idx), amt);
self.vec.set_len(len + amt);
}
Ok(())
}
#[inline]
pub fn try_insert_str(&mut self, idx: usize, string: &str) -> Result<(), Error> {
assert!(self.is_char_boundary(idx));
unsafe {
self.insert_bytes(idx, string.as_bytes())?;
}
Ok(())
}
#[inline]
pub unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8, A> {
&mut self.vec
}
#[inline]
#[must_use]
pub fn len(&self) -> usize {
self.vec.len()
}
#[inline]
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
#[must_use = "use `.truncate()` if you don't need the other half"]
pub fn try_split_off(&mut self, at: usize) -> Result<String<A>, Error>
where
A: Clone,
{
assert!(self.is_char_boundary(at));
let other = self.vec.try_split_off(at)?;
Ok(unsafe { String::from_utf8_unchecked(other) })
}
#[inline]
pub fn clear(&mut self) {
self.vec.clear()
}
pub fn drain<R>(&mut self, range: R) -> Drain<'_, A>
where
R: RangeBounds<usize>,
{
let Range { start, end } = slice_range(range, ..self.len());
assert!(self.is_char_boundary(start));
assert!(self.is_char_boundary(end));
let self_ptr = self as *mut _;
let chars_iter = unsafe { self.get_unchecked(start..end) }.chars();
Drain {
start,
end,
iter: chars_iter,
string: self_ptr,
}
}
pub fn try_replace_range<R>(&mut self, range: R, replace_with: &str) -> Result<(), Error>
where
R: RangeBounds<usize>,
{
let start = range.start_bound();
match start {
Included(&n) => assert!(self.is_char_boundary(n)),
Excluded(&n) => assert!(self.is_char_boundary(n + 1)),
Unbounded => {}
};
let end = range.end_bound();
match end {
Included(&n) => assert!(self.is_char_boundary(n + 1)),
Excluded(&n) => assert!(self.is_char_boundary(n)),
Unbounded => {}
};
unsafe { self.as_mut_vec() }.try_splice_in_place((start, end), replace_with.bytes())?;
Ok(())
}
#[must_use = "`self` will be dropped if the result is not used"]
#[inline]
pub fn try_into_boxed_str(self) -> Result<Box<str, A>, Error> {
let slice = self.vec.try_into_boxed_slice()?;
Ok(unsafe { crate::str::from_boxed_utf8_unchecked(slice) })
}
#[inline]
pub fn leak<'a>(self) -> &'a mut str
where
A: 'a,
{
let slice = self.vec.leak();
unsafe { from_utf8_unchecked_mut(slice) }
}
}
impl<A: Allocator> FromUtf8Error<A> {
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
&self.bytes[..]
}
#[must_use = "`self` will be dropped if the result is not used"]
pub fn into_bytes(self) -> Vec<u8, A> {
self.bytes
}
#[must_use]
pub fn utf8_error(&self) -> Utf8Error {
self.error
}
}
impl<A: Allocator> Default for String<A>
where
A: Default,
{
fn default() -> Self {
Self::new_in(A::default())
}
}
impl<A: Allocator> Borrow<str> for String<A> {
#[inline]
fn borrow(&self) -> &str {
&self[..]
}
}
impl<A: Allocator> fmt::Display for FromUtf8Error<A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.error, f)
}
}
impl<A: Allocator> core::error::Error for FromUtf8Error<A> {}
impl<A: Allocator + Clone> TryClone for String<A> {
fn try_clone(&self) -> Result<Self, Error> {
Ok(String {
vec: self.vec.try_clone()?,
})
}
}
#[cfg(test)]
impl<A: Allocator + Clone> Clone for String<A> {
fn clone(&self) -> Self {
self.try_clone().abort()
}
}
impl<A: Allocator> PartialEq for String<A> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.vec == other.vec
}
}
impl<A: Allocator> Eq for String<A> {}
impl<A: Allocator> PartialOrd for String<A> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<A: Allocator> Ord for String<A> {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
self.vec.cmp(&other.vec)
}
}
macro_rules! impl_eq {
($lhs:ty, $rhs: ty) => {
#[allow(unused_lifetimes)]
#[allow(clippy::partialeq_ne_impl)]
impl<'a, 'b> 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)]
#[allow(clippy::partialeq_ne_impl)]
impl<'a, 'b> 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, str }
impl_eq! { String, &'a str }
impl_eq! { Cow<'a, str>, str }
impl_eq! { Cow<'a, str>, &'b str }
impl_eq! { Cow<'a, str>, String }
impl<A: Allocator> fmt::Display for String<A> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&**self, f)
}
}
impl<A: Allocator> fmt::Debug for String<A> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<A: Allocator> hash::Hash for String<A> {
#[inline]
fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
(**self).hash(hasher)
}
}
impl<A: Allocator> ops::Index<ops::Range<usize>> for String<A> {
type Output = str;
#[inline]
fn index(&self, index: ops::Range<usize>) -> &str {
&self[..][index]
}
}
impl<A: Allocator> ops::Index<ops::RangeTo<usize>> for String<A> {
type Output = str;
#[inline]
fn index(&self, index: ops::RangeTo<usize>) -> &str {
&self[..][index]
}
}
impl<A: Allocator> ops::Index<ops::RangeFrom<usize>> for String<A> {
type Output = str;
#[inline]
fn index(&self, index: ops::RangeFrom<usize>) -> &str {
&self[..][index]
}
}
impl<A: Allocator> ops::Index<ops::RangeFull> for String<A> {
type Output = str;
#[inline]
fn index(&self, _index: ops::RangeFull) -> &str {
unsafe { from_utf8_unchecked(&self.vec) }
}
}
impl<A: Allocator> 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: Allocator> 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: Allocator> 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: Allocator> 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: Allocator> 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: Allocator> ops::IndexMut<ops::RangeFull> for String<A> {
#[inline]
fn index_mut(&mut self, _index: ops::RangeFull) -> &mut str {
unsafe { from_utf8_unchecked_mut(&mut self.vec) }
}
}
impl<A: Allocator> 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: Allocator> 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: Allocator> ops::Deref for String<A> {
type Target = str;
#[inline]
fn deref(&self) -> &str {
unsafe { from_utf8_unchecked(&self.vec) }
}
}
impl<A: Allocator> ops::DerefMut for String<A> {
#[inline]
fn deref_mut(&mut self) -> &mut str {
unsafe { from_utf8_unchecked_mut(&mut self.vec) }
}
}
impl<A: Allocator> AsRef<str> for String<A> {
#[inline]
fn as_ref(&self) -> &str {
self
}
}
impl<A: Allocator> AsMut<str> for String<A> {
#[inline]
fn as_mut(&mut self) -> &mut str {
self
}
}
#[cfg(feature = "std")]
impl<A: Allocator> AsRef<std::ffi::OsStr> for String<A> {
#[inline]
fn as_ref(&self) -> &std::ffi::OsStr {
(**self).as_ref()
}
}
impl<A: Allocator> AsRef<[u8]> for String<A> {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl<A: Allocator> From<Box<str, A>> for String<A> {
fn from(s: Box<str, A>) -> String<A> {
crate::str::into_string(s)
}
}
#[cfg(feature = "alloc")]
impl TryFrom<::rust_alloc::boxed::Box<str>> for String<Global> {
type Error = Error;
fn try_from(s: ::rust_alloc::boxed::Box<str>) -> Result<Self, Error> {
Self::try_from(s.as_ref())
}
}
#[cfg(feature = "alloc")]
impl TryFrom<::rust_alloc::string::String> for String<Global> {
type Error = Error;
fn try_from(string: ::rust_alloc::string::String) -> Result<Self, Error> {
let mut string = ManuallyDrop::new(string.into_bytes());
let buf = string.as_mut_ptr();
let length = string.len();
let capacity = string.capacity();
if let Ok(layout) = Layout::array::<u8>(capacity) {
Global.take(layout)?;
}
unsafe { Ok(String::from_raw_parts_in(buf, length, capacity, Global)) }
}
}
#[cfg(feature = "alloc")]
impl<A: Allocator> From<String<A>> for ::rust_alloc::string::String {
fn from(s: String<A>) -> Self {
Self::from(s.as_str())
}
}
#[cfg(feature = "alloc")]
impl<A: Allocator> From<&String<A>> for ::rust_alloc::string::String {
fn from(s: &String<A>) -> Self {
Self::from(s.as_str())
}
}
impl TryFrom<&str> for String<Global> {
type Error = Error;
fn try_from(s: &str) -> Result<Self, Error> {
let mut out = String::try_with_capacity_in(s.len(), Global)?;
out.try_push_str(s)?;
Ok(out)
}
}
impl TryFrom<Cow<'_, str>> for String<Global> {
type Error = Error;
fn try_from(s: Cow<'_, str>) -> Result<Self, Error> {
match s {
Cow::Borrowed(s) => Self::try_from(s),
Cow::Owned(s) => Ok(s),
}
}
}
impl<A: Allocator + Clone> TryFrom<&String<A>> for String<A> {
type Error = Error;
#[inline]
fn try_from(s: &String<A>) -> Result<Self, Error> {
let mut this = String::new_in(s.allocator().clone());
this.try_push_str(s.as_str())?;
Ok(this)
}
}
impl<A: Allocator> TryFrom<String<A>> for Box<str, A> {
type Error = Error;
#[inline]
fn try_from(s: String<A>) -> Result<Self, Error> {
s.try_into_boxed_str()
}
}
impl TryFrom<Cow<'_, str>> for Box<str> {
type Error = Error;
#[inline]
fn try_from(s: Cow<'_, str>) -> Result<Self, Error> {
Self::try_from(s.as_ref())
}
}
impl<A: Allocator> From<String<A>> for Vec<u8, A> {
#[inline]
fn from(string: String<A>) -> Vec<u8, A> {
string.into_bytes()
}
}
pub struct Drain<'a, A: Allocator> {
string: *mut String<A>,
start: usize,
end: usize,
iter: Chars<'a>,
}
impl<A: Allocator> fmt::Debug for Drain<'_, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Drain").field(&self.as_str()).finish()
}
}
unsafe impl<A: Allocator> Sync for Drain<'_, A> {}
unsafe impl<A: Allocator> Send for Drain<'_, A> {}
impl<A: Allocator> Drop for Drain<'_, A> {
fn drop(&mut self) {
unsafe {
let self_vec = (*self.string).as_mut_vec();
if self.start <= self.end && self.end <= self_vec.len() {
self_vec.drain(self.start..self.end);
}
}
}
}
impl<A: Allocator> Drain<'_, A> {
#[must_use]
pub fn as_str(&self) -> &str {
self.iter.as_str()
}
}
impl<A: Allocator> AsRef<str> for Drain<'_, A> {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl<A: Allocator> AsRef<[u8]> for Drain<'_, A> {
fn as_ref(&self) -> &[u8] {
self.as_str().as_bytes()
}
}
impl<A: Allocator> Iterator for Drain<'_, A> {
type Item = char;
#[inline]
fn next(&mut self) -> Option<char> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
#[inline]
fn last(mut self) -> Option<char> {
self.next_back()
}
}
impl<A: Allocator> DoubleEndedIterator for Drain<'_, A> {
#[inline]
fn next_back(&mut self) -> Option<char> {
self.iter.next_back()
}
}
impl<A: Allocator> FusedIterator for Drain<'_, A> {}
impl<A: Allocator> TryWrite for String<A> {
#[inline]
fn try_write_str(&mut self, s: &str) -> Result<(), Error> {
self.try_push_str(s)
}
#[inline]
fn try_write_char(&mut self, c: char) -> Result<(), Error> {
self.try_push(c)
}
}
impl<A: Allocator> TryFromIteratorIn<char, A> for String<A> {
fn try_from_iter_in<I>(iter: I, alloc: A) -> Result<Self, Error>
where
I: IntoIterator<Item = char>,
{
let mut this = String::new_in(alloc);
this.try_extend(iter)?;
Ok(this)
}
}
impl<'a, A: Allocator> TryFromIteratorIn<&'a str, A> for String<A> {
fn try_from_iter_in<I>(iter: I, alloc: A) -> Result<Self, Error>
where
I: IntoIterator<Item = &'a str>,
{
let mut this = String::new_in(alloc);
this.try_extend(iter)?;
Ok(this)
}
}
impl<T, A: Allocator> TryJoin<char, T, A> for String<A>
where
T: AsRef<str>,
{
fn try_join_in<I>(iter: I, sep: char, alloc: A) -> Result<Self, Error>
where
I: IntoIterator<Item = T>,
{
let mut string = String::new_in(alloc);
let mut iter = iter.into_iter().peekable();
while let Some(value) = iter.next() {
string.try_push_str(value.as_ref())?;
if iter.peek().is_some() {
string.try_push(sep)?;
}
}
Ok(string)
}
}
impl<T, A: Allocator> TryJoin<&str, T, A> for String<A>
where
T: AsRef<str>,
{
fn try_join_in<I>(iter: I, sep: &str, alloc: A) -> Result<Self, Error>
where
I: IntoIterator<Item = T>,
{
let mut string = String::new_in(alloc);
let mut iter = iter.into_iter().peekable();
while let Some(value) = iter.next() {
string.try_push_str(value.as_ref())?;
if iter.peek().is_some() {
string.try_push_str(sep)?;
}
}
Ok(string)
}
}
impl<A: Allocator> TryExtend<char> for String<A> {
#[inline]
fn try_extend<I: IntoIterator<Item = char>>(&mut self, iter: I) -> Result<(), Error> {
for value in iter {
self.try_push(value)?;
}
Ok(())
}
}
impl<'a, A: Allocator> TryExtend<&'a str> for String<A> {
#[inline]
fn try_extend<I: IntoIterator<Item = &'a str>>(&mut self, iter: I) -> Result<(), Error> {
for value in iter {
self.try_push_str(value)?;
}
Ok(())
}
}