1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#![feature(pattern)]
#![cfg_attr(not(test), no_std)]

//! Little crate implementing the [`slice::split_mut`] method on [`str`].

extern crate alloc;

use core::str::pattern::{Pattern, Searcher, ReverseSearcher};
use core::mem;
use core::str::from_utf8_unchecked_mut;
use core::slice;
use core::iter::FusedIterator;
use alloc::string::String;

/// Trait implementing [`slice::split_mut`] on [`str`].
pub trait SplitMutStr<'a, T: Pattern<'a> + Copy, I: Iterator<Item = &'a mut str>> {
    fn split_mut(&'a mut self, pattern: T) -> I;
}

impl<'a, T: Pattern<'a> + Copy> SplitMutStr<'a, T, SplitMut<'a, T>> for str {
    fn split_mut(&'a mut self, pattern: T) -> SplitMut<'a, T> {
        SplitMut { v: self, pattern, finished: false }
    }
}

impl<'a, T: Pattern<'a> + Copy> SplitMutStr<'a, T, SplitMut<'a, T>> for String {
    fn split_mut(&'a mut self, pattern: T) -> SplitMut<'a, T> {
        SplitMut { v: self, pattern, finished: false }
    }
}

/// Struct created with the [`SplitMutStr::split_mut`] method.
pub struct SplitMut<'a, T: Pattern<'a> + Copy> {
    v: &'a mut str,
    pattern: T,
    finished: bool
}

impl<'a, T: Pattern<'a> + Copy> SplitMut<'a, T> {
    fn v(&mut self) -> &'a mut str {
        mem::replace(&mut self.v, unsafe { from_utf8_unchecked_mut(slice::from_raw_parts_mut(1 as *mut u8, 0)) })
    }
}

impl<'a, T: Pattern<'a> + Copy> Iterator for SplitMut<'a, T> {
    type Item = &'a mut str;

    #[inline]
    fn next(&mut self) -> Option<&'a mut str> {
        if self.finished {
            return None;
        }

        let tmp1 = self.v();

        // SAFETY: after tmp1 it's used as inmmutable in `into_searcher` and the searcher it's dropped
        // the reference must count as "dead" and then available to use it again as mutable but instead
        // fails to compile and forces me to reborrow it
        let tmp = unsafe { &*(tmp1 as *mut str) };

        match self.pattern.into_searcher(tmp).next_match() {
            None => {
               self.finished = true;
               Some(tmp1) 
            },
            Some((idx1, idx2)) => {
                let len = idx2 - idx1;
                let (head, tail) = tmp1.split_at_mut(idx1);
                self.v = &mut tail[len..];
                Some(head)  
            }
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        if self.finished {
            (0, Some(0))
        } else {
            (1, Some(self.v.len() + 1))
        }
    }
}

impl<'a, U: ReverseSearcher<'a>, T: Pattern<'a, Searcher = U> + Copy> DoubleEndedIterator for SplitMut<'a, T>
{
    #[inline]
    fn next_back(&mut self) -> Option<&'a mut str> {
        if self.finished {
            return None;
        }

        let tmp1 = self.v();

        let tmp = unsafe { &*(tmp1 as *mut str) };

        match self.pattern.into_searcher(tmp).next_match_back() {
            None => {
               self.finished = true;
               Some(tmp1) 
            },
            Some((idx1, idx2)) => {
                let len = idx2 - idx1;
                let (head, tail) = tmp1.split_at_mut(idx1);
                self.v = head;
                Some(&mut tail[len..])
            }
        }
    }
}

impl<'a, T: Pattern<'a> + Copy> FusedIterator for SplitMut<'a, T> {}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn a() {
        assert_eq!(format!("sdasdasd").split_mut("a").collect::<Vec<&mut str>>(), ["sd", "sd", "sd"]);
        assert_eq!(format!("sdasdasd").split_mut(|c: char| c == 'a').collect::<Vec<&mut str>>(), ["sd", "sd", "sd"]);
        assert_eq!(format!("sdasdasd").split_mut('a').collect::<Vec<&mut str>>(), ["sd", "sd", "sd"]);
        assert_eq!(format!("sdasdasd").split_mut(&['a', 'b'][..]).collect::<Vec<&mut str>>(), ["sd", "sd", "sd"]);
        assert_eq!(format!("sdasdasdads").split_mut("a").rev().collect::<Vec<&mut str>>(), ["ds", "sd", "sd", "sd"]);
    }
}