yz_string_utils/
shard.rs

1use crate::Cow;
2use alloc::string::{String, ToString};
3
4pub enum Shard<'a> {
5    Borrowed { whole: &'a str, slen: usize },
6    Owned(String),
7}
8
9impl<'a> Shard<'a> {
10    #[inline]
11    pub fn new(whole: &'a str) -> Self {
12        Self::Borrowed { whole, slen: 0 }
13    }
14
15    #[inline]
16    pub fn len(&self) -> usize {
17        match self {
18            Self::Borrowed { ref slen, .. } => *slen,
19            Self::Owned(ref owned) => owned.len(),
20        }
21    }
22
23    #[inline]
24    pub fn is_empty(&self) -> bool {
25        self.len() == 0
26    }
27
28    fn to_mut(&mut self) -> &mut String {
29        if let Self::Borrowed { whole, slen } = *self {
30            *self = Self::Owned(whole[..slen].to_string());
31        }
32        match *self {
33            Self::Borrowed { .. } => unreachable!(),
34            Self::Owned(ref mut x) => x,
35        }
36    }
37
38    #[inline]
39    pub fn skip(&mut self, len: usize) {
40        if let Self::Borrowed { whole, slen: 0 } = self {
41            *whole = &whole[len..];
42        }
43    }
44
45    // promotes self to owned
46    #[inline]
47    pub fn push_owned(&mut self, ch: char) {
48        self.to_mut().push(ch);
49    }
50
51    pub fn push(&mut self, ch: char) {
52        match self {
53            Self::Borrowed { whole, slen } => {
54                let slen = *slen;
55                let new_len = slen + ch.len_utf8();
56                *self = if !whole[slen..].starts_with(ch) {
57                    // promote to owned
58                    let mut owned = whole[..slen].to_string();
59                    owned.push(ch);
60                    Self::Owned(owned)
61                } else {
62                    // remain borrowed
63                    Self::Borrowed {
64                        whole,
65                        slen: new_len,
66                    }
67                };
68            }
69            Self::Owned(ref mut x) => x.push(ch),
70        }
71    }
72
73    pub fn finish(self) -> Cow<'a, str> {
74        if self.is_empty() {
75            Cow::Borrowed("")
76        } else {
77            match self {
78                Self::Borrowed { whole, slen } => Cow::Borrowed(&whole[..slen]),
79                Self::Owned(x) => Cow::Owned(x),
80            }
81        }
82    }
83
84    pub(crate) fn finish_cvg(self) -> Option<Cow<'a, str>> {
85        if self.is_empty() {
86            None
87        } else {
88            Some(self.finish())
89        }
90    }
91}