1#![cfg(feature = "alloc")]
6#![cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
7
8use alloc::borrow::{Borrow, BorrowMut, Cow};
9use alloc::string::{FromUtf8Error, FromUtf16Error, String};
10#[cfg(feature = "arbitrary")]
11use arbitrary::{Arbitrary, Unstructured};
12use core::fmt::{self, Debug, Display, Formatter, Write};
13use core::mem;
14use core::num::NonZeroUsize;
15use core::ops::{Deref, DerefMut, Index, IndexMut};
16use core::slice::SliceIndex;
17#[cfg(feature = "schemars")]
18use schemars::{JsonSchema, Schema, SchemaGenerator};
19
20use crate::borrow1::{CowStr1, CowStr1Ext as _};
21use crate::boxed1::{BoxedStr1, BoxedStr1Ext as _};
22use crate::iter1::{Extend1, FromIterator1, IntoIterator1};
23use crate::safety::{NonZeroExt as _, OptionExt as _};
24use crate::slice1::Slice1;
25use crate::str1::Str1;
26use crate::take;
27use crate::vec1::Vec1;
28use crate::{Cardinality, EmptyError, FromMaybeEmpty, MaybeEmpty, NonEmpty};
29
30impl<'a> Extend<&'a Str1> for String {
31 fn extend<I>(&mut self, items: I)
32 where
33 I: IntoIterator<Item = &'a Str1>,
34 {
35 self.extend(items.into_iter().map(Str1::as_str))
36 }
37}
38
39impl Extend<String1> for String {
40 fn extend<I>(&mut self, items: I)
41 where
42 I: IntoIterator<Item = String1>,
43 {
44 self.extend(items.into_iter().map(String1::into_string))
45 }
46}
47
48impl Extend1<char> for String {
49 fn extend_non_empty<I>(mut self, items: I) -> String1
50 where
51 I: IntoIterator1<Item = char>,
52 {
53 self.extend(items);
54 unsafe { String1::from_maybe_empty_unchecked(self) }
57 }
58}
59
60unsafe impl MaybeEmpty for String {
61 fn cardinality(&self) -> Option<Cardinality<(), ()>> {
62 self.as_str().cardinality()
63 }
64}
65
66type TakeIfMany<'a, N = ()> = take::TakeIfMany<'a, String, char, N>;
67
68pub type PopIfMany<'a> = TakeIfMany<'a, ()>;
69
70pub type RemoveIfMany<'a> = TakeIfMany<'a, usize>;
71
72impl<N> TakeIfMany<'_, N> {
73 pub fn or_get_only(self) -> Result<char, char> {
74 self.take_or_else(|items, _| items.first())
75 }
76
77 pub fn or_replace_only(self, replacement: char) -> Result<char, char> {
78 self.or_else_replace_only(move || replacement)
79 }
80
81 pub fn or_else_replace_only<F>(self, f: F) -> Result<char, char>
82 where
83 F: FnOnce() -> char,
84 {
85 self.take_or_else(move |items, _| {
86 let target = items.first();
87 items.items.clear();
88 items.items.push(f());
89 target
90 })
91 }
92}
93
94impl TakeIfMany<'_, usize> {
95 pub fn or_get(self) -> Result<char, char> {
96 self.take_or_else(|items, index| {
97 if items.is_char_boundary(index) {
98 items.first()
99 }
100 else {
101 self::panic_index_is_not_char_boundary()
102 }
103 })
104 }
105
106 pub fn or_replace(self, replacement: char) -> Result<char, char> {
107 self.or_else_replace(move || replacement)
108 }
109
110 pub fn or_else_replace<F>(self, f: F) -> Result<char, char>
111 where
112 F: FnOnce() -> char,
113 {
114 self.take_or_else(move |items, index| {
115 if items.is_char_boundary(index) {
116 let target = items.items.remove(index);
117 items.items.push(f());
118 target
119 }
120 else {
121 self::panic_index_is_not_char_boundary()
122 }
123 })
124 }
125}
126
127pub type String1 = NonEmpty<String>;
128
129impl String1 {
130 pub unsafe fn from_string_unchecked(items: String) -> Self {
137 unsafe { FromMaybeEmpty::from_maybe_empty_unchecked(items) }
138 }
139
140 pub fn from_one_with_capacity<U>(item: char, capacity: usize) -> Self {
141 String1::from_iter1_with_capacity([item], capacity)
142 }
143
144 pub fn from_iter1_with_capacity<U>(items: U, capacity: usize) -> Self
145 where
146 String: Extend1<U::Item>,
147 U: IntoIterator1,
148 {
149 String::with_capacity(capacity).extend_non_empty(items)
150 }
151
152 pub fn from_utf8(items: Vec1<u8>) -> Result<Self, FromUtf8Error> {
153 String::from_utf8(items.into_vec())
156 .map(|items| unsafe { String1::from_string_unchecked(items) })
157 }
158
159 pub fn from_utf8_lossy(items: &Slice1<u8>) -> CowStr1<'_> {
160 unsafe {
163 match String::from_utf8_lossy(items.as_slice()) {
164 Cow::Borrowed(items) => Cow::Borrowed(Str1::from_str_unchecked(items)),
165 Cow::Owned(items) => Cow::Owned(String1::from_string_unchecked(items)),
166 }
167 }
168 }
169
170 pub fn from_utf16(items: &Slice1<u16>) -> Result<Self, FromUtf16Error> {
171 String::from_utf16(items.as_slice())
174 .map(|items| unsafe { String1::from_string_unchecked(items) })
175 }
176
177 pub fn from_utf16_lossy(items: &Slice1<u16>) -> String1 {
178 unsafe { String1::from_string_unchecked(String::from_utf16_lossy(items.as_slice())) }
181 }
182
183 pub fn into_string(self) -> String {
184 self.items
185 }
186
187 pub fn into_boxed_str1(self) -> BoxedStr1 {
188 unsafe { BoxedStr1::from_boxed_str_unchecked(self.items.into_boxed_str()) }
190 }
191
192 pub fn leak<'a>(self) -> &'a mut Str1 {
193 unsafe { Str1::from_mut_str_unchecked(self.items.leak()) }
195 }
196
197 pub fn try_retain<F>(self, f: F) -> Result<Self, EmptyError<String>>
198 where
199 F: FnMut(char) -> bool,
200 {
201 self.and_then_try(|items| items.retain(f))
202 }
203
204 pub fn reserve(&mut self, additional: usize) {
205 self.items.reserve(additional)
206 }
207
208 pub fn reserve_exact(&mut self, additional: usize) {
209 self.items.reserve_exact(additional)
210 }
211
212 pub fn shrink_to(&mut self, capacity: usize) {
213 self.items.shrink_to(capacity)
214 }
215
216 pub fn shrink_to_fit(&mut self) {
217 self.items.shrink_to_fit()
218 }
219
220 pub fn split_off_tail(&mut self) -> String {
221 let index = unsafe {
222 self.items
224 .char_indices()
225 .take(2)
226 .last()
227 .map(|(index, _)| index)
228 .unwrap_maybe_unchecked()
229 };
230 self.items.split_off(index)
231 }
232
233 pub fn push(&mut self, item: char) {
234 self.items.push(item)
235 }
236
237 pub fn push_str(&mut self, items: &str) {
238 self.items.push_str(items)
239 }
240
241 pub fn pop_if_many(&mut self) -> PopIfMany<'_> {
242 TakeIfMany::with(self, (), |items, ()| unsafe {
244 items.items.pop().unwrap_maybe_unchecked()
245 })
246 }
247
248 pub fn insert(&mut self, index: usize, item: char) {
249 self.items.insert(index, item)
250 }
251
252 pub fn remove_if_many(&mut self, index: usize) -> RemoveIfMany<'_> {
253 TakeIfMany::with(self, index, |items, index| items.items.remove(index))
254 }
255
256 pub fn len(&self) -> NonZeroUsize {
257 unsafe { NonZeroUsize::new_maybe_unchecked(self.items.len()) }
259 }
260
261 pub fn capacity(&self) -> NonZeroUsize {
262 unsafe { NonZeroUsize::new_maybe_unchecked(self.items.capacity()) }
264 }
265
266 pub const fn as_string(&self) -> &String {
267 &self.items
268 }
269
270 pub const unsafe fn as_mut_string(&mut self) -> &mut String {
287 &mut self.items
288 }
289
290 pub unsafe fn as_mut_vec1(&mut self) -> &mut Vec1<u8> {
296 unsafe { mem::transmute(self.items.as_mut_vec()) }
297 }
298
299 pub fn as_str1(&self) -> &Str1 {
300 unsafe { Str1::from_str_unchecked(self.items.as_str()) }
302 }
303
304 pub fn as_mut_str1(&mut self) -> &mut Str1 {
305 unsafe { Str1::from_mut_str_unchecked(self.items.as_mut_str()) }
307 }
308
309 pub fn as_ptr(&self) -> *const u8 {
310 self.items.as_ptr()
311 }
312
313 pub fn as_mut_ptr(&mut self) -> *mut u8 {
314 self.items.as_mut_ptr()
315 }
316}
317
318#[cfg(feature = "arbitrary")]
319#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))]
320impl<'a> Arbitrary<'a> for String1 {
321 fn arbitrary(unstructured: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
322 <&'a Str1>::arbitrary(unstructured).map(String1::from)
323 }
324
325 fn size_hint(depth: usize) -> (usize, Option<usize>) {
326 (<&'a Str1>::size_hint(depth).0, None)
327 }
328}
329
330impl AsMut<str> for String1 {
331 fn as_mut(&mut self) -> &mut str {
332 self.items.as_mut()
333 }
334}
335
336impl AsMut<Str1> for String1 {
337 fn as_mut(&mut self) -> &mut Str1 {
338 self.as_mut_str1()
339 }
340}
341
342impl AsRef<str> for String1 {
343 fn as_ref(&self) -> &str {
344 self.items.as_ref()
345 }
346}
347
348impl AsRef<Str1> for String1 {
349 fn as_ref(&self) -> &Str1 {
350 self.as_str1()
351 }
352}
353
354impl Borrow<str> for String1 {
355 fn borrow(&self) -> &str {
356 self.items.borrow()
357 }
358}
359
360impl Borrow<Str1> for String1 {
361 fn borrow(&self) -> &Str1 {
362 self.as_str1()
363 }
364}
365
366impl BorrowMut<str> for String1 {
367 fn borrow_mut(&mut self) -> &mut str {
368 self.items.borrow_mut()
369 }
370}
371
372impl BorrowMut<Str1> for String1 {
373 fn borrow_mut(&mut self) -> &mut Str1 {
374 self.as_mut_str1()
375 }
376}
377
378impl Debug for String1 {
379 fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
380 write!(formatter, "{:?}", &self.items)
381 }
382}
383
384impl Deref for String1 {
385 type Target = Str1;
386
387 fn deref(&self) -> &Self::Target {
388 self.as_str1()
389 }
390}
391
392impl DerefMut for String1 {
393 fn deref_mut(&mut self) -> &mut Self::Target {
394 self.as_mut_str1()
395 }
396}
397
398impl Display for String1 {
399 fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
400 write!(formatter, "{}", &self.items)
401 }
402}
403
404impl<T> Extend<T> for String1
408where
409 String: Extend<T>,
410{
411 fn extend<I>(&mut self, extension: I)
412 where
413 I: IntoIterator<Item = T>,
414 {
415 self.items.extend(extension)
416 }
417}
418
419impl From<BoxedStr1> for String1 {
420 fn from(items: BoxedStr1) -> Self {
421 unsafe { String1::from_string_unchecked(String::from(items.into_boxed_str())) }
423 }
424}
425
426impl From<char> for String1 {
427 fn from(point: char) -> Self {
428 unsafe { String1::from_string_unchecked(String::from(point)) }
430 }
431}
432
433impl<'a> From<CowStr1<'a>> for String1 {
434 fn from(items: CowStr1<'a>) -> Self {
435 items.into_owned()
436 }
437}
438
439impl<'a> From<&'a Str1> for String1 {
440 fn from(items: &'a Str1) -> Self {
441 unsafe { String1::from_string_unchecked(String::from(items.as_str())) }
443 }
444}
445
446impl<'a> From<&'a mut Str1> for String1 {
447 fn from(items: &'a mut Str1) -> Self {
448 unsafe { String1::from_string_unchecked(String::from(items.as_str())) }
450 }
451}
452
453impl From<String1> for String {
454 fn from(items: String1) -> Self {
455 items.items
456 }
457}
458
459impl FromIterator1<char> for String1 {
460 fn from_iter1<I>(items: I) -> Self
461 where
462 I: IntoIterator1<Item = char>,
463 {
464 unsafe { String1::from_string_unchecked(items.into_iter().collect()) }
467 }
468}
469
470impl<'a> FromIterator1<&'a char> for String1 {
471 fn from_iter1<I>(items: I) -> Self
472 where
473 I: IntoIterator1<Item = &'a char>,
474 {
475 String1::from_iter1(items.into_iter1().cloned())
476 }
477}
478
479impl<'a> FromIterator1<CowStr1<'a>> for String1 {
480 fn from_iter1<I>(items: I) -> Self
481 where
482 I: IntoIterator1<Item = CowStr1<'a>>,
483 {
484 let (head, tail) = items.into_iter1().into_head_and_tail();
485 let mut head = head.into_owned();
486 head.items.extend(tail.map(CowStr1::into_cow_str));
487 head
488 }
489}
490
491impl<'a> FromIterator1<&'a Str1> for String1 {
492 fn from_iter1<I>(items: I) -> Self
493 where
494 I: IntoIterator1<Item = &'a Str1>,
495 {
496 let (head, tail) = items.into_iter1().into_head_and_tail();
497 let mut head = String1::from(head);
498 head.extend(tail);
499 head
500 }
501}
502
503impl FromIterator1<String1> for String1 {
504 fn from_iter1<I>(items: I) -> Self
505 where
506 I: IntoIterator1<Item = String1>,
507 {
508 let (mut head, tail) = items.into_iter1().into_head_and_tail();
509 head.extend(tail);
510 head
511 }
512}
513
514impl<I> Index<I> for String1
515where
516 I: SliceIndex<str>,
517{
518 type Output = I::Output;
519
520 fn index(&self, at: I) -> &Self::Output {
521 self.items.index(at)
522 }
523}
524
525impl<I> IndexMut<I> for String1
526where
527 I: SliceIndex<str>,
528{
529 fn index_mut(&mut self, at: I) -> &mut Self::Output {
530 self.items.index_mut(at)
531 }
532}
533
534#[cfg(feature = "schemars")]
535#[cfg_attr(docsrs, doc(cfg(feature = "schemars")))]
536impl JsonSchema for String1 {
537 fn schema_name() -> Cow<'static, str> {
538 String::schema_name()
539 }
540
541 fn json_schema(generator: &mut SchemaGenerator) -> Schema {
542 use crate::schemars;
543
544 schemars::json_subschema_with_non_empty_property_for::<String>(
545 schemars::NON_EMPTY_KEY_STRING,
546 generator,
547 )
548 }
549
550 fn inline_schema() -> bool {
551 String::inline_schema()
552 }
553
554 fn schema_id() -> Cow<'static, str> {
555 String::schema_id()
556 }
557}
558
559crate::impl_partial_eq_for_non_empty!([in str] <= [in String1]);
560crate::impl_partial_eq_for_non_empty!([in &str] <= [in String1]);
561crate::impl_partial_eq_for_non_empty!([in &Str1] == [in String1]);
562crate::impl_partial_eq_for_non_empty!([in CowStr1<'_>] == [in String1]);
563crate::impl_partial_eq_for_non_empty!([in String1] => [in str]);
564crate::impl_partial_eq_for_non_empty!([in String1] => [in &str]);
565crate::impl_partial_eq_for_non_empty!([in String1] == [in &Str1]);
566
567impl<'a> TryFrom<&'a str> for String1 {
568 type Error = EmptyError<&'a str>;
569
570 fn try_from(items: &'a str) -> Result<Self, Self::Error> {
571 Str1::try_from_str(items).map(String1::from)
572 }
573}
574
575impl<'a> TryFrom<&'a mut str> for String1 {
576 type Error = EmptyError<&'a mut str>;
577
578 fn try_from(items: &'a mut str) -> Result<Self, Self::Error> {
579 Str1::try_from_mut_str(items).map(String1::from)
580 }
581}
582
583impl TryFrom<String> for String1 {
584 type Error = EmptyError<String>;
585
586 fn try_from(items: String) -> Result<Self, Self::Error> {
587 FromMaybeEmpty::try_from_maybe_empty(items)
588 }
589}
590
591impl TryFrom<Vec1<u8>> for String1 {
592 type Error = FromUtf8Error;
593
594 fn try_from(items: Vec1<u8>) -> Result<Self, Self::Error> {
595 String1::from_utf8(items)
596 }
597}
598
599impl Write for String1 {
600 fn write_str(&mut self, items: &str) -> fmt::Result {
601 self.items.write_str(items)
602 }
603
604 fn write_char(&mut self, item: char) -> fmt::Result {
605 self.items.write_char(item)
606 }
607}
608
609const fn panic_index_is_not_char_boundary() -> ! {
610 panic!("index is not at a UTF-8 code point boundary")
611}
612
613#[cfg(test)]
614pub mod harness {
615 use rstest::fixture;
616
617 use crate::iter1;
618 use crate::string1::String1;
619
620 #[fixture]
621 pub fn xs1(#[default(4)] end: u8) -> String1 {
622 iter1::one('x')
623 .first_and_then_take(usize::from(end))
624 .collect1()
625 }
626}
627
628#[cfg(all(test, feature = "schemars"))]
629mod tests {
630 use rstest::rstest;
631
632 use crate::schemars;
633 use crate::string1::String1;
634
635 #[rstest]
636 fn string1_json_schema_has_non_empty_property() {
637 schemars::harness::assert_json_schema_has_non_empty_property::<String1>(
638 schemars::NON_EMPTY_KEY_STRING,
639 );
640 }
641}