use crate::{CharIter, Digits, InvalidUtf8, is, slice, whilst};
#[allow(unused_imports, reason = "±unsafe")]
use {
crate::{sf, unwrap},
::core::str::{from_utf8_unchecked, from_utf8_unchecked_mut},
};
use ::core::str::from_utf8_mut;
#[doc = crate::_tags!(text namespace)]
#[doc = crate::_doc_location!("text/str")]
#[derive(Debug)]
pub struct Str;
impl Str {
#[allow(rustdoc::broken_intra_doc_links, reason = "±unsafe")]
pub const fn from_utf8(v: &[u8]) -> Result<&str, InvalidUtf8> {
match ::core::str::from_utf8(v) {
Ok(v) => Ok(v),
Err(e) => Err(InvalidUtf8::from_utf8_error(e)),
}
}
pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, InvalidUtf8> {
match from_utf8_mut(v) {
Ok(v) => Ok(v),
Err(e) => Err(InvalidUtf8::from_utf8_error(e)),
}
}
#[must_use]
#[cfg(all(not(feature = "safe_text"), unsafe··))]
#[cfg_attr(nightly_doc, doc(cfg(unsafe··)))]
pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str {
unsafe { from_utf8_unchecked(v) }
}
#[must_use]
#[cfg(all(not(feature = "safe_text"), unsafe··))]
#[cfg_attr(nightly_doc, doc(cfg(unsafe··)))]
pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str {
unsafe { from_utf8_unchecked_mut(v) }
}
#[doc(hidden)] #[rustfmt::skip]
pub const fn __utf8_bytes_to_str(bytes: &[u8]) -> &str {
#[cfg(any(feature = "safe_text", not(unsafe··)))]
{ unwrap![ok ::core::str::from_utf8(bytes)] }
#[cfg(all(not(feature = "safe_text"), unsafe··))]
unsafe { ::core::str::from_utf8_unchecked(bytes) }
}
}
impl Str {
#[inline(always)]
pub const fn chars(string: &str) -> CharIter<'_, &str> {
CharIter::<&str>::new(string)
}
#[must_use]
#[inline(always)]
pub const fn char_count(string: &str) -> usize {
CharIter::<&str>::new(string).count()
}
#[doc = crate::doclink!(custom devela "[`StrExt::repeat_into`]"
"text/str/trait.StrExt.html#method.repeat_into")]
#[must_use]
pub const fn repeat_into<'input, const CAP: usize>(
string: &str,
n: usize,
buffer: &'input mut [u8; CAP],
) -> &'input str {
Self::repeat_into_slice(string, n, buffer)
}
#[must_use]
pub const fn repeat_into_slice<'input>(
string: &str,
n: usize,
buffer: &'input mut [u8],
) -> &'input str {
let s_bytes = string.as_bytes();
let s_len = s_bytes.len();
let mut index = 0;
whilst! { count in 0..n; {
is![index + s_len > buffer.len(), break];
slice![mut buffer, index, ..index + s_len].copy_from_slice(s_bytes);
index += s_len;
}}
#[cfg(any(feature = "safe_text", not(feature = "unsafe_str")))]
return unwrap![ok Str::from_utf8(slice![buffer, ..index])];
#[cfg(all(not(feature = "safe_text"), feature = "unsafe_str"))]
sf! { unsafe { Str::from_utf8_unchecked(slice![buffer, ..index]) }}
}
#[doc = crate::doclink!(custom devela "[`StrExt::new_counter`]"
"text/str/trait.StrExt.html#method.new_counter")]
pub const fn new_counter(buffer: &mut [u8], length: usize, separator: char) -> &str {
assert![buffer.len() >= length];
assert![separator.is_ascii()];
if length == 0 {
Str::new_cold_empty()
} else {
let separator = separator as u8;
let mut index = length - 1; let mut num = length; let mut separator_turn = true; let mut digits = Digits(num).count_digits10() as usize;
loop {
if separator_turn {
buffer[index] = separator;
} else {
let start = index + 1 - digits;
let _ = Digits(num).write_digits10(buffer, start);
index = start;
num = index;
digits = Digits(num).count_digits10() as usize;
}
is![index == 0, break, index -= 1];
separator_turn = !separator_turn;
}
#[cfg(any(feature = "safe_text", not(feature = "unsafe_str")))]
return unwrap![ok Str::from_utf8(slice![buffer, ..length])];
#[cfg(all(not(feature = "safe_text"), feature = "unsafe_str"))]
sf! { unsafe { Str::from_utf8_unchecked(slice![buffer, ..length]) }}
}
}
#[doc(hidden)]
#[cold] #[rustfmt::skip]
pub const fn new_cold_empty() -> &'static str { "" }
}