Skip to main content

morphix/impls/slices/
str.rs

1use std::fmt::Debug;
2use std::ops::{Index, IndexMut};
3use std::slice::SliceIndex;
4
5use crate::Observe;
6use crate::general::UnsizeObserver;
7use crate::helper::macros::{delegate_methods, shallow_observer};
8use crate::helper::{AsDeref, AsDerefMut, QuasiObserver, Unsigned};
9use crate::impls::slices::shallow::ShallowMut;
10use crate::observe::{DefaultSpec, RefObserve};
11
12shallow_observer! {
13    impl StrObserver for str;
14}
15
16impl RefObserve for str {
17    type Observer<'ob, S, D>
18        = UnsizeObserver<'ob, S, D>
19    where
20        Self: 'ob,
21        D: Unsigned,
22        S: AsDeref<D, Target = Self> + ?Sized + 'ob;
23
24    type Spec = DefaultSpec;
25}
26
27impl<'ob, S: ?Sized, D> StrObserver<'ob, S, D>
28where
29    D: Unsigned,
30    S: AsDerefMut<D, Target = str>,
31{
32    fn nonempty_mut(&mut self) -> &mut str {
33        if (*self).untracked_ref().is_empty() {
34            self.untracked_mut()
35        } else {
36            self.tracked_mut()
37        }
38    }
39
40    delegate_methods! { nonempty_mut() as str =>
41        pub fn as_mut_ptr(&mut self) -> *mut u8;
42        pub fn make_ascii_uppercase(&mut self);
43        pub fn make_ascii_lowercase(&mut self);
44    }
45
46    /// See [`str::as_bytes_mut`].
47    pub unsafe fn as_bytes_mut(&mut self) -> ShallowMut<'_, [u8]> {
48        let inner = unsafe { (*self.ptr).as_deref_mut().as_bytes_mut() };
49        ShallowMut::new(inner, &raw mut self.mutated)
50    }
51
52    /// See [`str::get_mut`].
53    pub fn get_mut<I: SliceIndex<str, Output = str>>(&mut self, i: I) -> Option<ShallowMut<'_, str>> {
54        let output = (*self.ptr).as_deref_mut().get_mut(i)?;
55        Some(ShallowMut::new(output, &raw mut self.mutated))
56    }
57
58    /// See [`str::get_unchecked_mut`].
59    pub unsafe fn get_unchecked_mut<I: SliceIndex<str, Output = str>>(&mut self, i: I) -> ShallowMut<'_, str> {
60        let output = unsafe { (*self.ptr).as_deref_mut().get_unchecked_mut(i) };
61        ShallowMut::new(output, &raw mut self.mutated)
62    }
63
64    /// See [`str::split_at_mut`].
65    pub fn split_at_mut(&mut self, mid: usize) -> (ShallowMut<'_, str>, ShallowMut<'_, str>) {
66        let (left, right) = (*self.ptr).as_deref_mut().split_at_mut(mid);
67        (
68            ShallowMut::new(left, &raw mut self.mutated),
69            ShallowMut::new(right, &raw mut self.mutated),
70        )
71    }
72
73    /// See [`str::split_at_mut_checked`].
74    pub fn split_at_mut_checked(&mut self, mid: usize) -> Option<(ShallowMut<'_, str>, ShallowMut<'_, str>)> {
75        let (left, right) = (*self.ptr).as_deref_mut().split_at_mut_checked(mid)?;
76        Some((
77            ShallowMut::new(left, &raw mut self.mutated),
78            ShallowMut::new(right, &raw mut self.mutated),
79        ))
80    }
81}
82
83impl<'ob, S: ?Sized, D> AsMut<str> for StrObserver<'ob, S, D>
84where
85    D: Unsigned,
86    S: AsDerefMut<D, Target = str>,
87{
88    fn as_mut(&mut self) -> &mut str {
89        self.tracked_mut()
90    }
91}
92
93impl<'ob, S: ?Sized, D> Debug for StrObserver<'ob, S, D>
94where
95    D: Unsigned,
96    S: AsDerefMut<D, Target = str>,
97{
98    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99        f.debug_tuple("StrObserver").field(&self.untracked_ref()).finish()
100    }
101}
102
103impl<'ob, S1: ?Sized, S2: ?Sized, D1, D2> PartialEq<StrObserver<'ob, S2, D2>> for StrObserver<'ob, S1, D1>
104where
105    D1: Unsigned,
106    D2: Unsigned,
107    S1: AsDeref<D1>,
108    S2: AsDeref<D2>,
109    S1::Target: PartialEq<S2::Target>,
110{
111    fn eq(&self, other: &StrObserver<'ob, S2, D2>) -> bool {
112        self.untracked_ref().eq(other.untracked_ref())
113    }
114}
115
116impl<'ob, S: ?Sized, D> Eq for StrObserver<'ob, S, D>
117where
118    D: Unsigned,
119    S: AsDerefMut<D, Target = str>,
120{
121}
122
123impl<'ob, S1: ?Sized, S2: ?Sized, D1, D2> PartialOrd<StrObserver<'ob, S2, D2>> for StrObserver<'ob, S1, D1>
124where
125    D1: Unsigned,
126    D2: Unsigned,
127    S1: AsDeref<D1>,
128    S2: AsDeref<D2>,
129    S1::Target: PartialOrd<S2::Target>,
130{
131    fn partial_cmp(&self, other: &StrObserver<'ob, S2, D2>) -> Option<std::cmp::Ordering> {
132        self.untracked_ref().partial_cmp(other.untracked_ref())
133    }
134}
135
136impl<'ob, S: ?Sized, D> Ord for StrObserver<'ob, S, D>
137where
138    D: Unsigned,
139    S: AsDerefMut<D, Target = str>,
140{
141    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
142        self.untracked_ref().cmp(other.untracked_ref())
143    }
144}
145
146impl<'ob, S: ?Sized, D, I> Index<I> for StrObserver<'ob, S, D>
147where
148    D: Unsigned,
149    S: AsDerefMut<D, Target = str>,
150    I: SliceIndex<str>,
151{
152    type Output = I::Output;
153
154    fn index(&self, index: I) -> &Self::Output {
155        self.untracked_ref().index(index)
156    }
157}
158
159impl<'ob, S: ?Sized, D, I> IndexMut<I> for StrObserver<'ob, S, D>
160where
161    D: Unsigned,
162    S: AsDerefMut<D, Target = str>,
163    I: SliceIndex<str>,
164{
165    fn index_mut(&mut self, index: I) -> &mut Self::Output {
166        self.tracked_mut().index_mut(index)
167    }
168}
169
170macro_rules! generic_impl_cmp {
171    ($(impl $([$($gen:tt)*])? _ for $ty:ty);* $(;)?) => {
172        $(
173            impl<'ob, $($($gen)*,)? S: ?Sized, D> PartialEq<$ty> for StrObserver<'ob, S, D>
174            where
175                D: Unsigned,
176                S: AsDeref<D>,
177                S::Target: PartialEq<$ty>,
178            {
179                fn eq(&self, other: &$ty) -> bool {
180                    (***self).as_deref().eq(other)
181                }
182            }
183
184            impl<'ob, $($($gen)*,)? S: ?Sized, D> PartialOrd<$ty> for StrObserver<'ob, S, D>
185            where
186                D: Unsigned,
187                S: AsDeref<D>,
188                S::Target: PartialOrd<$ty>,
189            {
190                fn partial_cmp(&self, other: &$ty) -> Option<std::cmp::Ordering> {
191                    (***self).as_deref().partial_cmp(other)
192                }
193            }
194        )*
195    };
196}
197
198generic_impl_cmp! {
199    impl _ for str;
200    impl _ for String;
201    impl _ for std::ffi::OsStr;
202    impl _ for std::ffi::OsString;
203    impl _ for std::path::Path;
204    impl _ for std::path::PathBuf;
205    impl ['a] _ for std::borrow::Cow<'a, str>;
206}
207
208impl<'ob> ShallowMut<'ob, str> {
209    fn nonempty_mut(&mut self) -> &mut str {
210        if !self.inner.is_empty() {
211            unsafe { *self.mutated = true }
212        }
213        self.inner
214    }
215
216    delegate_methods! { nonempty_mut() as str =>
217        pub fn as_mut_ptr(&mut self) -> *mut u8;
218        pub fn make_ascii_uppercase(&mut self);
219        pub fn make_ascii_lowercase(&mut self);
220    }
221
222    /// See [`str::as_bytes_mut`].
223    pub unsafe fn as_bytes_mut(&mut self) -> ShallowMut<'_, [u8]> {
224        let inner = unsafe { self.inner.as_bytes_mut() };
225        ShallowMut::new(inner, self.mutated)
226    }
227
228    /// See [`str::get_mut`].
229    pub fn get_mut<I: SliceIndex<str, Output = str>>(&mut self, i: I) -> Option<ShallowMut<'_, str>> {
230        let output = self.inner.get_mut(i)?;
231        Some(ShallowMut::new(output, self.mutated))
232    }
233
234    /// See [`str::get_unchecked_mut`].
235    pub unsafe fn get_unchecked_mut<I: SliceIndex<str, Output = str>>(&mut self, i: I) -> ShallowMut<'_, str> {
236        let output = unsafe { self.inner.get_unchecked_mut(i) };
237        ShallowMut::new(output, self.mutated)
238    }
239
240    /// See [`str::split_at_mut`].
241    pub fn split_at_mut(&mut self, mid: usize) -> (ShallowMut<'_, str>, ShallowMut<'_, str>) {
242        let (left, right) = self.inner.split_at_mut(mid);
243        (
244            ShallowMut::new(left, self.mutated),
245            ShallowMut::new(right, self.mutated),
246        )
247    }
248
249    /// See [`str::split_at_mut_checked`].
250    pub fn split_at_mut_checked(&mut self, mid: usize) -> Option<(ShallowMut<'_, str>, ShallowMut<'_, str>)> {
251        let (left, right) = self.inner.split_at_mut_checked(mid)?;
252        Some((
253            ShallowMut::new(left, self.mutated),
254            ShallowMut::new(right, self.mutated),
255        ))
256    }
257}