#[cfg(feature = "serde")]
use ::serde::{Deserialize, Deserializer};
#[cfg(feature = "arbitrary")]
use arbitrary::{Arbitrary, Unstructured};
use core::fmt::{self, Debug, Display, Formatter};
use core::mem;
use core::num::NonZeroUsize;
use core::ops::{Deref, DerefMut, Index, IndexMut};
use core::slice::SliceIndex;
use core::str::{
self, Bytes, CharIndices, Chars, EncodeUtf16, Lines, Split, SplitInclusive, SplitTerminator,
Utf8Error,
};
#[cfg(feature = "rayon")]
use rayon::str::ParallelString;
#[cfg(feature = "schemars")]
use {
alloc::borrow::Cow,
schemars::{JsonSchema, Schema, SchemaGenerator},
};
#[cfg(feature = "alloc")]
use {alloc::borrow::ToOwned, alloc::string::String};
use crate::iter1::Iterator1;
#[cfg(feature = "rayon")]
use crate::iter1::ParallelIterator1;
use crate::safety;
use crate::slice1::Slice1;
use crate::{Cardinality, EmptyError, FromMaybeEmpty, MaybeEmpty, NonEmpty};
#[cfg(feature = "alloc")]
use {crate::boxed1::BoxedStr1, crate::string1::String1};
unsafe impl MaybeEmpty for str {
fn cardinality(&self) -> Option<Cardinality<(), ()>> {
match self.chars().take(2).count() {
0 => None,
1 => Some(Cardinality::One(())),
_ => Some(Cardinality::Many(())),
}
}
}
pub type Str1 = NonEmpty<str>;
impl Str1 {
pub const unsafe fn from_str_unchecked(items: &str) -> &Self {
unsafe { mem::transmute::<&'_ str, &'_ Str1>(items) }
}
pub const unsafe fn from_mut_str_unchecked(items: &mut str) -> &mut Self {
unsafe { mem::transmute::<&'_ mut str, &'_ mut Str1>(items) }
}
pub fn try_from_str(items: &str) -> Result<&Self, EmptyError<&str>> {
items.try_into()
}
pub fn try_from_mut_str(items: &mut str) -> Result<&mut Self, EmptyError<&mut str>> {
items.try_into()
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub fn to_string1(&self) -> String1 {
String1::from(self)
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub fn into_string1(self: BoxedStr1) -> String1 {
String1::from(self)
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub fn once_and_then_repeat(&self, n: usize) -> String1 {
unsafe {
String1::from_string_unchecked(
self.items
.repeat(n.checked_add(1).expect("overflow in slice repetition")),
)
}
}
pub fn encode1_utf16(&self) -> Iterator1<EncodeUtf16<'_>> {
unsafe { Iterator1::from_iter_unchecked(self.encode_utf16()) }
}
pub fn split1<'a, P>(&'a self, separator: &'a P) -> Iterator1<Split<'a, &'a [char]>>
where
P: 'a + AsRef<[char]>,
{
unsafe { Iterator1::from_iter_unchecked(self.split(separator.as_ref())) }
}
pub fn split1_inclusive<'a, P>(
&'a self,
separator: &'a P,
) -> Iterator1<SplitInclusive<'a, &'a [char]>>
where
P: 'a + AsRef<[char]>,
{
unsafe { Iterator1::from_iter_unchecked(self.split_inclusive(separator.as_ref())) }
}
pub fn split1_terminator<'a, P>(
&'a self,
separator: &'a P,
) -> Iterator1<SplitTerminator<'a, &'a [char]>>
where
P: 'a + AsRef<[char]>,
{
unsafe { Iterator1::from_iter_unchecked(self.split_terminator(separator.as_ref())) }
}
#[cfg(feature = "alloc")]
pub(crate) fn first(&self) -> char {
use crate::safety::OptionExt as _;
unsafe { self.items.chars().next().unwrap_maybe_unchecked() }
}
pub fn chars1(&self) -> Iterator1<Chars<'_>> {
unsafe { Iterator1::from_iter_unchecked(self.as_str().chars()) }
}
pub fn char_indices1(&self) -> Iterator1<CharIndices<'_>> {
unsafe { Iterator1::from_iter_unchecked(self.as_str().char_indices()) }
}
pub fn bytes1(&self) -> Iterator1<Bytes<'_>> {
unsafe { Iterator1::from_iter_unchecked(self.as_str().bytes()) }
}
pub fn lines1(&self) -> Iterator1<Lines<'_>> {
unsafe { Iterator1::from_iter_unchecked(self.as_str().lines()) }
}
pub const fn len(&self) -> NonZeroUsize {
unsafe { safety::non_zero_from_usize_maybe_unchecked(self.items.len()) }
}
pub const fn as_bytes1(&self) -> &Slice1<u8> {
unsafe { Slice1::from_slice_unchecked(self.as_str().as_bytes()) }
}
pub const fn as_bytes1_mut(&mut self) -> &mut Slice1<u8> {
unsafe { Slice1::from_mut_slice_unchecked(self.as_mut_str().as_bytes_mut()) }
}
pub const fn as_str(&self) -> &'_ str {
&self.items
}
pub const fn as_mut_str(&mut self) -> &'_ mut str {
&mut self.items
}
}
#[cfg(feature = "rayon")]
#[cfg_attr(docsrs, doc(cfg(feature = "rayon")))]
impl Str1 {
pub fn par_encode1_utf16(&self) -> ParallelIterator1<rayon::str::EncodeUtf16<'_>> {
unsafe { ParallelIterator1::from_par_iter_unchecked(self.par_encode_utf16()) }
}
pub fn par_split1<'a, P>(
&'a self,
separator: &'a P,
) -> ParallelIterator1<rayon::str::Split<'a, &'a [char]>>
where
P: 'a + AsRef<[char]>,
{
unsafe { ParallelIterator1::from_par_iter_unchecked(self.par_split(separator.as_ref())) }
}
pub fn par_split1_inclusive<'a, P>(
&'a self,
separator: &'a P,
) -> ParallelIterator1<rayon::str::SplitInclusive<'a, &'a [char]>>
where
P: 'a + AsRef<[char]>,
{
unsafe {
ParallelIterator1::from_par_iter_unchecked(self.par_split_inclusive(separator.as_ref()))
}
}
pub fn par_split1_terminator<'a, P>(
&'a self,
separator: &'a P,
) -> ParallelIterator1<rayon::str::SplitTerminator<'a, &'a [char]>>
where
P: 'a + AsRef<[char]>,
{
unsafe {
ParallelIterator1::from_par_iter_unchecked(
self.par_split_terminator(separator.as_ref()),
)
}
}
pub fn par_chars1(&self) -> ParallelIterator1<rayon::str::Chars<'_>> {
unsafe { ParallelIterator1::from_par_iter_unchecked(self.par_chars()) }
}
pub fn par_char_indices1(&self) -> ParallelIterator1<rayon::str::CharIndices<'_>> {
unsafe { ParallelIterator1::from_par_iter_unchecked(self.par_char_indices()) }
}
pub fn par_bytes1(&self) -> ParallelIterator1<rayon::str::Bytes<'_>> {
unsafe { ParallelIterator1::from_par_iter_unchecked(self.par_bytes()) }
}
pub fn par_lines1(&self) -> ParallelIterator1<rayon::str::Lines<'_>> {
unsafe { ParallelIterator1::from_par_iter_unchecked(self.par_lines()) }
}
}
#[cfg(feature = "arbitrary")]
#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))]
impl<'a> Arbitrary<'a> for &'a Str1 {
fn arbitrary(unstructured: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
loop {
if let Ok(items) = Str1::try_from_str(<&'a str>::arbitrary(unstructured)?) {
break Ok(items);
}
}
}
fn size_hint(_: usize) -> (usize, Option<usize>) {
(1, None)
}
}
impl AsMut<str> for Str1 {
fn as_mut(&mut self) -> &mut str {
&mut self.items
}
}
impl Debug for Str1 {
fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
write!(formatter, "{:?}", &self.items)
}
}
impl Deref for Str1 {
type Target = str;
fn deref(&self) -> &Self::Target {
self.as_str()
}
}
impl DerefMut for Str1 {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut_str()
}
}
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
impl<'a, 'de> Deserialize<'de> for &'a Str1
where
'de: 'a,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
use ::serde::de::Error;
let items = <&str>::deserialize(deserializer)?;
<&Str1>::try_from(items).map_err(D::Error::custom)
}
}
impl Display for Str1 {
fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
write!(formatter, "{}", &self.items)
}
}
impl<'a> From<&'a Str1> for &'a str {
fn from(items: &'a Str1) -> Self {
&items.items
}
}
impl<'a> From<&'a mut Str1> for &'a mut str {
fn from(items: &'a mut Str1) -> Self {
&mut items.items
}
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl<'a> From<&'a Str1> for String {
fn from(items: &'a Str1) -> Self {
String::from(items.as_str())
}
}
impl<I> Index<I> for Str1
where
I: SliceIndex<str>,
{
type Output = <I as SliceIndex<str>>::Output;
fn index(&self, at: I) -> &Self::Output {
self.items.index(at)
}
}
impl<I> IndexMut<I> for Str1
where
I: SliceIndex<str>,
{
fn index_mut(&mut self, at: I) -> &mut Self::Output {
self.items.index_mut(at)
}
}
#[cfg(feature = "schemars")]
#[cfg_attr(docsrs, doc(cfg(feature = "schemars")))]
impl JsonSchema for Str1 {
fn schema_name() -> Cow<'static, str> {
<str>::schema_name()
}
fn json_schema(generator: &mut SchemaGenerator) -> Schema {
use crate::schemars;
schemars::json_subschema_with_non_empty_property_for::<str>(
schemars::NON_EMPTY_KEY_STRING,
generator,
)
}
fn inline_schema() -> bool {
<str>::inline_schema()
}
fn schema_id() -> Cow<'static, str> {
<str>::schema_id()
}
}
crate::impl_partial_eq_for_non_empty!([in str] <= [in Str1]);
crate::impl_partial_eq_for_non_empty!([in Str1] => [in str]);
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl ToOwned for Str1 {
type Owned = String1;
fn to_owned(&self) -> Self::Owned {
String1::from(self)
}
}
impl<'a> TryFrom<&'a str> for &'a Str1 {
type Error = EmptyError<&'a str>;
fn try_from(items: &'a str) -> Result<Self, Self::Error> {
FromMaybeEmpty::try_from_maybe_empty(items)
}
}
impl<'a> TryFrom<&'a mut str> for &'a mut Str1 {
type Error = EmptyError<&'a mut str>;
fn try_from(items: &'a mut str) -> Result<Self, Self::Error> {
FromMaybeEmpty::try_from_maybe_empty(items)
}
}
pub const fn from_utf8(items: &Slice1<u8>) -> Result<&Str1, Utf8Error> {
match str::from_utf8(items.as_slice()) {
Ok(items) => Ok(unsafe { Str1::from_str_unchecked(items) }),
Err(error) => Err(error),
}
}
pub fn from_utf8_mut(items: &mut Slice1<u8>) -> Result<&mut Str1, Utf8Error> {
match str::from_utf8_mut(items.as_mut_slice()) {
Ok(items) => Ok(unsafe { Str1::from_mut_str_unchecked(items) }),
Err(error) => Err(error),
}
}
#[cfg(test)]
pub mod harness {
use rstest::fixture;
use crate::str1::Str1;
#[fixture]
pub fn xs1() -> &'static Str1 {
Str1::try_from_str("non-empty").unwrap()
}
}
#[cfg(all(
test,
any(feature = "schemars", all(feature = "alloc", feature = "serde"))
))]
mod tests {
use rstest::rstest;
#[cfg(feature = "serde")]
use {alloc::vec::Vec, serde_test::Token};
#[cfg(feature = "schemars")]
use crate::schemars;
use crate::str1::Str1;
#[cfg(feature = "serde")]
use {
crate::serde::{self, harness::borrowed_str},
crate::str1::harness::xs1,
};
#[cfg(feature = "schemars")]
#[rstest]
fn str1_json_schema_has_non_empty_property() {
schemars::harness::assert_json_schema_has_non_empty_property::<Str1>(
schemars::NON_EMPTY_KEY_STRING,
);
}
#[cfg(feature = "serde")]
#[rstest]
fn deserialize_ref_slice1_u8_from_tokens_eq(
xs1: &Str1,
#[with(xs1)] borrowed_str: impl Iterator<Item = Token>,
) {
let borrowed_str: Vec<_> = borrowed_str.collect();
let borrowed_str = borrowed_str.as_slice();
serde::harness::assert_ref_from_tokens_eq(xs1, borrowed_str)
}
}