hipstr 0.8.0

Yet another string for Rust: zero-cost borrow and slicing, inline representation for small strings, (atomic) reference counting
Documentation
#![allow(clippy::module_name_repetitions)]

use alloc::string::String;

use super::HipStr;
use crate::Backend;

pub trait Adopt<'borrow, B>
where
    B: Backend,
{
    type Output;
    unsafe fn adopt_unchecked(self, source: &HipStr<'borrow, B>) -> Self::Output;
}

impl<'borrow, B: Backend> Adopt<'borrow, B> for &str {
    type Output = HipStr<'borrow, B>;
    #[inline]
    unsafe fn adopt_unchecked(self, source: &HipStr<'borrow, B>) -> Self::Output {
        unsafe { source.slice_ref_unchecked(self) }
    }
}

impl<'borrow, B: Backend> Adopt<'borrow, B> for (usize, &str) {
    type Output = (usize, HipStr<'borrow, B>);
    #[inline]
    unsafe fn adopt_unchecked(self, source: &HipStr<'borrow, B>) -> Self::Output {
        (self.0, unsafe { source.slice_ref_unchecked(self.1) })
    }
}

#[must_use]
pub struct IterWrapper<'haystack, 'borrow, B, I>
where
    B: Backend,
{
    source: &'haystack HipStr<'borrow, B>,
    inner: I,
}

impl<B, I: Clone> Clone for IterWrapper<'_, '_, B, I>
where
    B: Backend,
{
    fn clone(&self) -> Self {
        Self {
            source: self.source,
            inner: self.inner.clone(),
        }
    }
}

impl<'haystack, 'borrow, B, I> IterWrapper<'haystack, 'borrow, B, I>
where
    B: Backend,
{
    pub(crate) const fn new(source: &'haystack HipStr<'borrow, B>, inner: I) -> Self {
        Self { source, inner }
    }
}

impl<'borrow, B, S> Iterator for IterWrapper<'_, 'borrow, B, S>
where
    B: Backend,
    S: Iterator,
    S::Item: Adopt<'borrow, B>,
{
    type Item = <S::Item as Adopt<'borrow, B>>::Output;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.inner
            .next()
            .map(|item| unsafe { item.adopt_unchecked(self.source) })
    }
}

impl<'borrow, B, S> DoubleEndedIterator for IterWrapper<'_, 'borrow, B, S>
where
    B: Backend,
    S: Iterator + DoubleEndedIterator,
    S::Item: Adopt<'borrow, B>,
{
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item> {
        self.inner
            .next_back()
            .map(|item| unsafe { item.adopt_unchecked(self.source) })
    }
}

pub trait Pattern: Sized {
    type Split<'a>;
    fn split(self, haystack: &str) -> Self::Split<'_>;

    type SplitInclusive<'a>;
    fn split_inclusive(self, haystack: &str) -> Self::SplitInclusive<'_>;

    type SplitTerminator<'a>;
    fn split_terminator(self, haystack: &str) -> Self::SplitTerminator<'_>;

    type SplitN<'a>;
    fn splitn(self, n: usize, haystack: &str) -> Self::SplitN<'_>;
    fn split_once(self, haystack: &str) -> Option<(&str, &str)>;

    type Matches<'a>;
    fn matches(self, haystack: &str) -> Self::Matches<'_>;

    type MatchIndices<'a>;
    fn match_indices(self, haystack: &str) -> Self::MatchIndices<'_>;

    fn trim_start_matches(self, s: &str) -> &str;

    fn strip_prefix(self, haystack: &str) -> Option<&str>;
}

pub trait ReversePattern: Pattern {
    fn strip_suffix(self, haystack: &str) -> Option<&str>;

    fn trim_end_matches(self, haystack: &str) -> &str;

    type RSplit<'a>;
    fn rsplit(self, haystack: &str) -> Self::RSplit<'_>;

    type RSplitTerminator<'a>;
    fn rsplit_terminator(self, haystack: &str) -> Self::RSplitTerminator<'_>;

    type RSplitN<'a>;
    fn rsplitn(self, n: usize, haystack: &str) -> Self::RSplitN<'_>;

    fn rsplit_once(self, haystack: &str) -> Option<(&str, &str)>;

    type RMatches<'a>;
    fn rmatches(self, haystack: &str) -> Self::RMatches<'_>;

    type RMatchIndices<'a>;
    fn rmatch_indices(self, haystack: &str) -> Self::RMatchIndices<'_>;
}

pub trait DoubleEndedPattern: ReversePattern {
    fn trim_matches(self, s: &str) -> &str;
}

macro_rules! impl_pat {
    (reverse $( < $( $gl:lifetime ),* $(,)? > <$($gt:ident),* $(,)?> <$(const $gc:ident: $gct:ty),* $(,)?> )? for $t:ty $(where $($w:tt)*)?) => {
        impl_pat!(
            $( < $( $gl ),* > < $( $gt ),* > <$(const  $gc : $gct ),* > )?
            for $t $(where $($w)* )?
        );

        impl$(<$($gl,)* $($gt,)* $( const $gc: $gct, )* >)? ReversePattern for $t $(where $($w)*)? {
            fn strip_suffix(self, haystack: &str) -> Option<&str>{
                haystack.strip_suffix(self)
            }

            fn trim_end_matches(self, haystack: &str) -> &str {
                haystack.trim_end_matches(self)
            }

            type RSplit<'haystack> = core::str::RSplit<'haystack, Self>;
            #[inline]
            fn rsplit(self, haystack: &str) -> Self::RSplit<'_> {
                haystack.rsplit(self)
            }

            type RSplitTerminator<'haystack> = core::str::RSplitTerminator<'haystack, Self>;
            #[inline]
            fn rsplit_terminator(self, haystack: &str) -> Self::RSplitTerminator<'_> {
                haystack.rsplit_terminator(self)
            }

            type RSplitN<'haystack> = core::str::RSplitN<'haystack, Self>;
            #[inline]
            fn rsplitn(self, n:usize, haystack: &str) -> Self::RSplitN<'_> {
                haystack.rsplitn(n, self)
            }

            #[inline]
            fn rsplit_once(self, haystack: &str) -> Option<(&str, &str)> {
                haystack.rsplit_once(self)
            }

            type RMatches<'haystack> = core::str::RMatches<'haystack, Self>;
            #[inline]
            fn rmatches(self, haystack: &str) -> Self::RMatches<'_> {
                haystack.rmatches(self)
            }

            type RMatchIndices<'haystack> = core::str::RMatchIndices<'haystack, Self>;
            #[inline]
            fn rmatch_indices(self, haystack: &str) -> Self::RMatchIndices<'_> {
                haystack.rmatch_indices(self)
            }

        }
    };
    (double_ended $( < $( $gl:lifetime ),* $(,)? > <$($gt:ident),* $(,)?> <$(const $gc:ident: $gct:ty),* $(,)?> )? for $t:ty $(where $($w:tt)*)?) => {
        impl_pat!(reverse
            $( < $( $gl ),* > < $( $gt ),* > <$(const  $gc : $gct ),* > )?
            for $t $(where $($w)* )?
        );

        impl$(<$($gl,)* $($gt,)* $( const $gc: $gct, )* >)? DoubleEndedPattern for $t $(where $($w)*)? {
            fn trim_matches(self, haystack: &str) -> &str {
                haystack.trim_matches(self)
            }
        }
    };
    ($( < $( $gl:lifetime ),* $(,)? > <$($gt:ident),* $(,)?> <$(const $gc:ident: $gct:ty),* $(,)?> )? for $t:ty $(where $($w:tt)*)?) => {
        impl$(<$($gl,)* $($gt,)* $( const $gc: $gct, )* >)? Pattern for $t $(where $($w)*)? {
            type Split<'haystack> = core::str::Split<'haystack, Self>;
            #[inline]
            fn split(self, haystack: &str) -> Self::Split<'_> {
                haystack.split(self)
            }

            type SplitInclusive<'haystack> = core::str::SplitInclusive<'haystack, Self>;
            #[inline]
            fn split_inclusive(self, haystack: &str) -> Self::SplitInclusive<'_> {
                haystack.split_inclusive(self)
            }

            type SplitTerminator<'haystack> = core::str::SplitTerminator<'haystack, Self>;
            #[inline]
            fn split_terminator(self, haystack: &str) -> Self::SplitTerminator<'_> {
                haystack.split_terminator(self)
            }
            type SplitN<'haystack> = core::str::SplitN<'haystack, Self>;
            #[inline]
            fn splitn(self, n:usize, haystack: &str) -> Self::SplitN<'_> {
                haystack.splitn(n, self)
            }

            #[inline]
            fn split_once(self, haystack: &str) -> Option<(&str, &str)> {
                haystack.split_once(self)
            }
            type Matches<'haystack> = core::str::Matches<'haystack, Self>;
            #[inline]
            fn matches(self, haystack: &str) -> Self::Matches<'_> {
                haystack.matches(self)
            }

            type MatchIndices<'haystack> = core::str::MatchIndices<'haystack, Self>;
            #[inline]
            fn match_indices(self, haystack: &str) -> Self::MatchIndices<'_> {
                haystack.match_indices(self)
            }

            #[inline]
            fn trim_start_matches(self, haystack: &str) -> &str {
                haystack.trim_start_matches(self)
            }


            #[inline]
            fn strip_prefix(self, haystack: &str) -> Option<&str> {
                haystack.strip_prefix(self)
            }
        }
    };
}

impl_pat!(reverse <'a> <> <> for &'a str);
impl_pat!(reverse <'a, 'b> <> <> for &'a &'b str);
impl_pat!(reverse <'a> <> <> for &'a String);
impl_pat!(double_ended for char);
impl_pat!(double_ended <'a> <> <> for &'a [char]);
impl_pat!(double_ended <'a> <F> <> for F where F: (FnMut(char) -> bool) + Sized);
impl_pat!(reverse <'a> <> <const N: usize> for &'a [char; N]);