1#![cfg(feature = "alloc")]
6#![cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
7
8use alloc::borrow::{Borrow, BorrowMut, Cow};
9use alloc::string::{FromUtf16Error, FromUtf8Error, String};
10#[cfg(feature = "arbitrary")]
11use arbitrary::{Arbitrary, Unstructured};
12use core::fmt::{self, Debug, Formatter, Write};
13use core::mem;
14use core::num::NonZeroUsize;
15use core::ops::{Deref, DerefMut, Index, IndexMut};
16use core::slice::SliceIndex;
17
18use crate::borrow1::CowStr1;
19use crate::boxed1::{BoxedStr1, BoxedStr1Ext as _};
20use crate::iter1::{Extend1, FromIterator1, IntoIterator1};
21use crate::safety::{NonZeroExt as _, OptionExt as _};
22use crate::slice1::Slice1;
23use crate::str1::Str1;
24use crate::take;
25use crate::vec1::Vec1;
26use crate::{Cardinality, FromMaybeEmpty, MaybeEmpty, NonEmpty};
27
28impl Extend1<char> for String {
29 fn extend_non_empty<I>(mut self, items: I) -> String1
30 where
31 I: IntoIterator1<Item = char>,
32 {
33 self.extend(items);
34 unsafe { String1::from_maybe_empty_unchecked(self) }
37 }
38}
39
40unsafe impl MaybeEmpty for String {
41 fn cardinality(&self) -> Option<Cardinality<(), ()>> {
42 self.as_str().cardinality()
43 }
44}
45
46type TakeOr<'a, N = ()> = take::TakeOr<'a, String, char, N>;
47
48pub type PopOr<'a> = TakeOr<'a, ()>;
49
50pub type RemoveOr<'a> = TakeOr<'a, usize>;
51
52impl<N> TakeOr<'_, N> {
53 pub fn get_only(self) -> Result<char, char> {
54 self.take_or_else(|items, _| items.first())
55 }
56
57 pub fn replace_only(self, replacement: char) -> Result<char, char> {
58 self.else_replace_only(move || replacement)
59 }
60
61 pub fn else_replace_only<F>(self, f: F) -> Result<char, char>
62 where
63 F: FnOnce() -> char,
64 {
65 self.take_or_else(move |items, _| {
66 let target = items.first();
67 items.items.clear();
68 items.items.push(f());
69 target
70 })
71 }
72}
73
74impl TakeOr<'_, usize> {
75 pub fn get(self) -> Result<char, char> {
76 self.take_or_else(|items, index| {
77 if items.is_char_boundary(index) {
78 items.first()
79 }
80 else {
81 self::panic_index_is_not_char_boundary()
82 }
83 })
84 }
85
86 pub fn replace(self, replacement: char) -> Result<char, char> {
87 self.else_replace(move || replacement)
88 }
89
90 pub fn else_replace<F>(self, f: F) -> Result<char, char>
91 where
92 F: FnOnce() -> char,
93 {
94 self.take_or_else(move |items, index| {
95 if items.is_char_boundary(index) {
96 let target = items.items.remove(index);
97 items.items.push(f());
98 target
99 }
100 else {
101 self::panic_index_is_not_char_boundary()
102 }
103 })
104 }
105}
106
107pub type String1 = NonEmpty<String>;
108
109impl String1 {
110 pub unsafe fn from_string_unchecked(items: String) -> Self {
117 FromMaybeEmpty::from_maybe_empty_unchecked(items)
118 }
119
120 pub fn from_one_with_capacity<U>(item: char, capacity: usize) -> Self {
121 String1::from_iter1_with_capacity([item], capacity)
122 }
123
124 pub fn from_iter1_with_capacity<U>(items: U, capacity: usize) -> Self
125 where
126 String: Extend1<U::Item>,
127 U: IntoIterator1,
128 {
129 String::with_capacity(capacity).extend_non_empty(items)
130 }
131
132 pub fn from_utf8(items: Vec1<u8>) -> Result<Self, FromUtf8Error> {
133 String::from_utf8(items.into_vec())
136 .map(|items| unsafe { String1::from_string_unchecked(items) })
137 }
138
139 pub fn from_utf8_lossy(items: &Slice1<u8>) -> CowStr1 {
140 unsafe {
143 match String::from_utf8_lossy(items.as_slice()) {
144 Cow::Borrowed(items) => Cow::Borrowed(Str1::from_str_unchecked(items)),
145 Cow::Owned(items) => Cow::Owned(String1::from_string_unchecked(items)),
146 }
147 }
148 }
149
150 pub fn from_utf16(items: &Slice1<u16>) -> Result<Self, FromUtf16Error> {
151 String::from_utf16(items.as_slice())
154 .map(|items| unsafe { String1::from_string_unchecked(items) })
155 }
156
157 pub fn from_utf16_lossy(items: &Slice1<u16>) -> String1 {
158 unsafe { String1::from_string_unchecked(String::from_utf16_lossy(items.as_slice())) }
161 }
162
163 pub fn into_string(self) -> String {
164 self.items
165 }
166
167 pub fn into_boxed_str1(self) -> BoxedStr1 {
168 unsafe { BoxedStr1::from_boxed_str_unchecked(self.items.into_boxed_str()) }
170 }
171
172 pub fn leak<'a>(self) -> &'a mut Str1 {
173 unsafe { Str1::from_mut_str_unchecked(self.items.leak()) }
175 }
176
177 pub fn reserve(&mut self, additional: usize) {
178 self.items.reserve(additional)
179 }
180
181 pub fn reserve_exact(&mut self, additional: usize) {
182 self.items.reserve_exact(additional)
183 }
184
185 pub fn shrink_to(&mut self, capacity: usize) {
186 self.items.shrink_to(capacity)
187 }
188
189 pub fn shrink_to_fit(&mut self) {
190 self.items.shrink_to_fit()
191 }
192
193 pub fn split_off_tail(&mut self) -> String {
194 let index = unsafe {
195 self.items
197 .char_indices()
198 .take(2)
199 .last()
200 .map(|(index, _)| index)
201 .unwrap_maybe_unchecked()
202 };
203 self.items.split_off(index)
204 }
205
206 pub fn push(&mut self, item: char) {
207 self.items.push(item)
208 }
209
210 pub fn push_str(&mut self, items: &str) {
211 self.items.push_str(items)
212 }
213
214 pub fn pop_or(&mut self) -> PopOr<'_> {
215 TakeOr::with(self, (), |items, ()| unsafe {
217 items.items.pop().unwrap_maybe_unchecked()
218 })
219 }
220
221 pub fn insert(&mut self, index: usize, item: char) {
222 self.items.insert(index, item)
223 }
224
225 pub fn remove_or(&mut self, index: usize) -> RemoveOr<'_> {
226 TakeOr::with(self, index, |items, index| items.items.remove(index))
227 }
228
229 pub fn len(&self) -> NonZeroUsize {
230 unsafe { NonZeroUsize::new_maybe_unchecked(self.items.len()) }
232 }
233
234 pub fn capacity(&self) -> NonZeroUsize {
235 unsafe { NonZeroUsize::new_maybe_unchecked(self.items.capacity()) }
237 }
238
239 pub const fn as_string(&self) -> &String {
240 &self.items
241 }
242
243 pub unsafe fn as_mut_vec1(&mut self) -> &mut Vec1<u8> {
249 unsafe { mem::transmute(self.items.as_mut_vec()) }
250 }
251
252 pub fn as_str1(&self) -> &Str1 {
253 unsafe { Str1::from_str_unchecked(self.items.as_str()) }
255 }
256
257 pub fn as_mut_str1(&mut self) -> &mut Str1 {
258 unsafe { Str1::from_mut_str_unchecked(self.items.as_mut_str()) }
260 }
261
262 pub fn as_ptr(&self) -> *const u8 {
263 self.items.as_ptr()
264 }
265
266 pub fn as_mut_ptr(&mut self) -> *mut u8 {
267 self.items.as_mut_ptr()
268 }
269}
270
271#[cfg(feature = "arbitrary")]
272#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))]
273impl<'a> Arbitrary<'a> for String1 {
274 fn arbitrary(unstructured: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
275 <&'a Str1>::arbitrary(unstructured).map(String1::from)
276 }
277
278 fn size_hint(depth: usize) -> (usize, Option<usize>) {
279 (<&'a Str1>::size_hint(depth).0, None)
280 }
281}
282
283impl AsMut<str> for String1 {
284 fn as_mut(&mut self) -> &mut str {
285 self.items.as_mut()
286 }
287}
288
289impl AsMut<Str1> for String1 {
290 fn as_mut(&mut self) -> &mut Str1 {
291 self.as_mut_str1()
292 }
293}
294
295impl AsRef<str> for String1 {
296 fn as_ref(&self) -> &str {
297 self.items.as_ref()
298 }
299}
300
301impl AsRef<Str1> for String1 {
302 fn as_ref(&self) -> &Str1 {
303 self.as_str1()
304 }
305}
306
307impl Borrow<str> for String1 {
308 fn borrow(&self) -> &str {
309 self.items.borrow()
310 }
311}
312
313impl Borrow<Str1> for String1 {
314 fn borrow(&self) -> &Str1 {
315 self.as_str1()
316 }
317}
318
319impl BorrowMut<str> for String1 {
320 fn borrow_mut(&mut self) -> &mut str {
321 self.items.borrow_mut()
322 }
323}
324
325impl BorrowMut<Str1> for String1 {
326 fn borrow_mut(&mut self) -> &mut Str1 {
327 self.as_mut_str1()
328 }
329}
330
331impl Debug for String1 {
332 fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
333 write!(formatter, "{:?}", &self.items)
334 }
335}
336
337impl Deref for String1 {
338 type Target = Str1;
339
340 fn deref(&self) -> &Self::Target {
341 self.as_str1()
342 }
343}
344
345impl DerefMut for String1 {
346 fn deref_mut(&mut self) -> &mut Self::Target {
347 self.as_mut_str1()
348 }
349}
350
351impl<T> Extend<T> for String1
352where
353 String: Extend<T>,
354{
355 fn extend<I>(&mut self, extension: I)
356 where
357 I: IntoIterator<Item = T>,
358 {
359 self.items.extend(extension)
360 }
361}
362
363impl From<BoxedStr1> for String1 {
364 fn from(items: BoxedStr1) -> Self {
365 unsafe { String1::from_string_unchecked(String::from(items.into_boxed_str())) }
367 }
368}
369
370impl<'a> From<CowStr1<'a>> for String1 {
371 fn from(items: CowStr1<'a>) -> Self {
372 items.into_owned()
373 }
374}
375
376impl<'a> From<&'a Str1> for String1 {
377 fn from(items: &'a Str1) -> Self {
378 unsafe { String1::from_string_unchecked(String::from(items.as_str())) }
380 }
381}
382
383impl<'a> From<&'a mut Str1> for String1 {
384 fn from(items: &'a mut Str1) -> Self {
385 unsafe { String1::from_string_unchecked(String::from(items.as_str())) }
387 }
388}
389
390impl From<String1> for String {
391 fn from(items: String1) -> Self {
392 items.items
393 }
394}
395
396impl FromIterator1<char> for String1 {
397 fn from_iter1<I>(items: I) -> Self
398 where
399 I: IntoIterator1<Item = char>,
400 {
401 unsafe { String1::from_string_unchecked(items.into_iter().collect()) }
403 }
404}
405
406impl<I> Index<I> for String1
407where
408 I: SliceIndex<str>,
409{
410 type Output = I::Output;
411
412 fn index(&self, at: I) -> &Self::Output {
413 self.items.index(at)
414 }
415}
416
417impl<I> IndexMut<I> for String1
418where
419 I: SliceIndex<str>,
420{
421 fn index_mut(&mut self, at: I) -> &mut Self::Output {
422 self.items.index_mut(at)
423 }
424}
425
426impl<'a> TryFrom<&'a str> for String1 {
427 type Error = &'a str;
428
429 fn try_from(items: &'a str) -> Result<Self, Self::Error> {
430 Str1::try_from_str(items).map(String1::from)
431 }
432}
433
434impl<'a> TryFrom<&'a mut str> for String1 {
435 type Error = &'a mut str;
436
437 fn try_from(items: &'a mut str) -> Result<Self, Self::Error> {
438 Str1::try_from_mut_str(items).map(String1::from)
439 }
440}
441
442impl TryFrom<String> for String1 {
443 type Error = String;
444
445 fn try_from(items: String) -> Result<Self, Self::Error> {
446 FromMaybeEmpty::try_from_maybe_empty(items)
447 }
448}
449
450impl Write for String1 {
451 fn write_str(&mut self, items: &str) -> fmt::Result {
452 self.items.write_str(items)
453 }
454
455 fn write_char(&mut self, item: char) -> fmt::Result {
456 self.items.write_char(item)
457 }
458}
459
460const fn panic_index_is_not_char_boundary() -> ! {
461 panic!("index is not at a UTF-8 code point boundary")
462}
463
464#[cfg(test)]
465pub mod harness {
466 use rstest::fixture;
467
468 use crate::iter1;
469 use crate::string1::String1;
470
471 #[fixture]
472 pub fn xs1(#[default(4)] end: u8) -> String1 {
473 iter1::one('x')
474 .first_and_then_take(usize::from(end))
475 .collect1()
476 }
477}
478
479#[cfg(test)]
480mod tests {}