janetrs/types/string.rs
1//! Janet String type.
2use core::{
3    convert::Infallible,
4    fmt::{self, Debug, Display},
5    marker::PhantomData,
6    ops::Index,
7    str::FromStr,
8};
9
10use alloc::borrow::Cow;
11
12use alloc::string::String;
13
14#[cfg(feature = "std")]
15use std::{ffi::OsStr, path::Path};
16
17use bstr::{
18    BStr, ByteSlice, Bytes, CharIndices, Chars, FieldsWith, Find, FindReverse, Lines,
19    LinesWithTerminator, Split, SplitN, SplitNReverse, SplitReverse, Utf8Chunks, Utf8Error,
20};
21
22#[cfg(feature = "unicode")]
23use bstr::{
24    Fields, GraphemeIndices, Graphemes, SentenceIndices, Sentences, WordIndices, Words,
25    WordsWithBreakIndices, WordsWithBreaks,
26};
27
28use super::{DeepEq, JanetBuffer};
29
30/// Builder for [`JanetString`]s.
31#[derive(Debug)]
32pub struct JanetStringBuilder<'data> {
33    raw:     *mut u8,
34    len:     i32,
35    added:   i32,
36    phantom: PhantomData<&'data ()>,
37}
38
39impl<'data> JanetStringBuilder<'data> {
40    /// Add data to the string builder.
41    #[cfg_attr(feature = "inline-more", inline)]
42    #[must_use]
43    pub fn put(mut self, data: impl AsRef<[u8]>) -> Self {
44        let data = data.as_ref();
45
46        let space_left = self.len - self.added;
47
48        if space_left == 0 {
49            return self;
50        }
51
52        let max_len = if (data.len() as i32) > space_left {
53            space_left as usize
54        } else {
55            data.len()
56        };
57
58        for &byte in &data[..max_len] {
59            // SAFETY: We asserted that the amount of data we are trying to add fit in the allocated
60            // space for the string. The only thing that could go wrong is insert the
61            // data in the wrong order, making the encoding wrong.
62            unsafe {
63                let val_ptr = self.raw.offset(self.added as isize);
64                *val_ptr = byte;
65            }
66
67            self.added += 1;
68        }
69
70        self
71    }
72
73    /// Add a [`char`] to the string builder.
74    #[inline]
75    #[must_use]
76    pub fn put_char(self, ch: char) -> Self {
77        let mut buff = [0; 4];
78        let s = ch.encode_utf8(&mut buff);
79        self.put(s)
80    }
81
82    /// Finalize the build process and create [`JanetString`].
83    ///
84    /// If the build is finalized and not all the allocated space was inserted with a
85    /// item, the unused space will all be Null characters.
86    #[inline]
87    pub fn finalize(self) -> JanetString<'data> {
88        JanetString {
89            raw:     unsafe { evil_janet::janet_string_end(self.raw) },
90            phantom: PhantomData,
91        }
92    }
93}
94
95/// Janet strings are a immutable type that are similar to [Janet buffers].
96///
97/// # Example
98/// You can easily create a Janet string from Rust [`str`] and bytes slice with [`new`]:
99/// ```
100/// use janetrs::JanetString;
101/// # let _client = janetrs::client::JanetClient::init().unwrap();
102///
103/// let jstr = JanetString::new("Hello, World");
104/// let jstr2 = JanetString::new(b"Janet! A bottle of water please!");
105/// ```
106///
107/// You can also use the [`builder`] API to create a in a more dynamic way
108/// ```
109/// use janetrs::JanetString;
110/// # let _client = janetrs::client::JanetClient::init().unwrap();
111///
112/// let size = 13;
113/// let jstr = JanetString::builder(size)
114///     .put("H")
115///     .put("ello, ")
116///     .put(b"World!")
117///     .finalize();
118/// ```
119///
120/// [Janet buffers]: ./../buffer/struct.JanetBuffer.html
121/// [`builder`]: #method.builder
122/// [`new`]: #method.new
123#[repr(transparent)]
124pub struct JanetString<'data> {
125    pub(crate) raw: *const u8,
126    phantom: PhantomData<&'data ()>,
127}
128
129impl<'data> JanetString<'data> {
130    /// Create a [`JanetString`] from a given `buffer`.
131    ///
132    /// # Examples
133    /// ```
134    /// use janetrs::JanetString;
135    /// # let _client = janetrs::client::JanetClient::init().unwrap();
136    ///
137    /// let s = JanetString::new("Hey there!");
138    /// ```
139    #[inline]
140    pub fn new(buffer: impl AsRef<[u8]>) -> Self {
141        let buffer = buffer.as_ref();
142
143        let len = if buffer.len() > i32::MAX as usize {
144            i32::MAX
145        } else {
146            buffer.len() as i32
147        };
148
149        Self {
150            raw:     unsafe { evil_janet::janet_string(buffer.as_ptr(), len) },
151            phantom: PhantomData,
152        }
153    }
154
155    /// Create a new [`JanetString`] with a `raw` pointer.
156    ///
157    /// # Safety
158    /// This function do not check if the given `raw` is `NULL` or not. Use at your
159    /// own risk.
160    #[inline]
161    pub const unsafe fn from_raw(raw: *const u8) -> Self {
162        Self {
163            raw,
164            phantom: PhantomData,
165        }
166    }
167
168    /// Created a builder for creating the [`JanetString`].
169    ///
170    /// If the given `len` is lesser than zero it behaves the same as if `len` is zero.
171    #[inline]
172    pub fn builder(len: usize) -> JanetStringBuilder<'data> {
173        let len = i32::try_from(len).unwrap_or(i32::MAX);
174
175        JanetStringBuilder {
176            raw: unsafe { evil_janet::janet_string_begin(len) },
177            len,
178            added: 0,
179            phantom: PhantomData,
180        }
181    }
182
183    /// Returns the length of this [`JanetString`], in bytes, not [`char`]s or graphemes.
184    /// In other words, it may not be what a human considers the length of the string.
185    ///
186    /// # Examples
187    /// ```
188    /// use janetrs::JanetString;
189    /// # let _client = janetrs::client::JanetClient::init().unwrap();
190    ///
191    /// let s = JanetString::new("Hey there!");
192    /// assert_eq!(s.len(), 10);
193    /// ```
194    #[inline]
195    pub fn len(&self) -> usize {
196        unsafe { (*evil_janet::janet_string_head(self.raw)).length as usize }
197    }
198
199    /// Returns `true` if this [`JanetString`] has a length of zero, and `false`
200    /// otherwise.
201    ///
202    /// # Examples
203    /// ```
204    /// use janetrs::JanetString;
205    /// # let _client = janetrs::client::JanetClient::init().unwrap();
206    ///
207    /// let s = JanetString::new("Hey there!");
208    /// assert!(!s.is_empty());
209    ///
210    /// let s = JanetString::new("");
211    /// assert!(s.is_empty());
212    /// ```
213    #[inline]
214    pub fn is_empty(&self) -> bool {
215        self.len() == 0
216    }
217
218    /// Returns a byte slice of the [`JanetString`] contents.
219    ///
220    /// # Examples
221    /// ```
222    /// use janetrs::JanetString;
223    /// # let _client = janetrs::client::JanetClient::init().unwrap();
224    ///
225    /// let s = JanetString::new("hello");
226    ///
227    /// assert_eq!(&[104, 101, 108, 108, 111], s.as_bytes());
228    /// ```
229    #[inline]
230    pub fn as_bytes(&self) -> &[u8] {
231        unsafe { core::slice::from_raw_parts(self.raw, self.len()) }
232    }
233
234    /// Returns `true` if and only if this string contains the given `needle`.
235    ///
236    /// # Examples
237    /// ```
238    /// use janetrs::JanetString;
239    /// # let _client = janetrs::client::JanetClient::init().unwrap();
240    ///
241    /// let s = JanetString::new("Hey there");
242    ///
243    /// assert!(s.contains("the"))
244    /// ```
245    #[cfg_attr(feature = "inline-more", inline)]
246    pub fn contains(&self, needle: impl AsRef<[u8]>) -> bool {
247        self.as_bytes().contains_str(needle)
248    }
249
250    /// Returns `true` if and only if this string has the given `prefix`.
251    ///
252    /// # Examples
253    /// ```
254    /// use janetrs::JanetString;
255    /// # let _client = janetrs::client::JanetClient::init().unwrap();
256    ///
257    /// assert!(JanetString::new("foo bar").starts_with("foo"));
258    /// assert!(!JanetString::new("foo bar").starts_with("bar"));
259    /// assert!(!JanetString::new("foo bar").starts_with("foobar"));
260    /// ```
261    #[cfg_attr(feature = "inline-more", inline)]
262    pub fn starts_with(&self, prefix: impl AsRef<[u8]>) -> bool {
263        self.as_bytes().starts_with_str(prefix)
264    }
265
266    /// Returns `true` if and only if this string has the given `suffix`.
267    ///
268    /// # Examples
269    /// ```
270    /// use janetrs::JanetString;
271    /// # let _client = janetrs::client::JanetClient::init().unwrap();
272    ///
273    /// assert!(!JanetString::new("foo bar").ends_with("foo"));
274    /// assert!(JanetString::new("foo bar").ends_with("bar"));
275    /// assert!(!JanetString::new("foo bar").ends_with("foobar"));
276    /// ```
277    #[cfg_attr(feature = "inline-more", inline)]
278    pub fn ends_with(&self, suffix: impl AsRef<[u8]>) -> bool {
279        self.as_bytes().ends_with_str(suffix)
280    }
281
282    /// Returns `true` if and only if every byte in this string is ASCII.
283    ///
284    /// ASCII is an encoding that defines 128 codepoints. A byte corresponds to
285    /// an ASCII codepoint if and only if it is in the inclusive range
286    /// `[0, 127]`.
287    ///
288    /// # Examples
289    /// ```
290    /// use janetrs::JanetString;
291    /// # let _client = janetrs::client::JanetClient::init().unwrap();
292    ///
293    /// assert!(JanetString::new("abc").is_ascii());
294    /// assert!(!JanetString::new("☃βツ").is_ascii());
295    /// ```
296    #[inline]
297    pub fn is_ascii(&self) -> bool {
298        self.as_bytes().is_ascii()
299    }
300
301    /// Returns `true` if and only if the entire string is valid UTF-8.
302    ///
303    /// If you need location information about where a string's first
304    /// invalid UTF-8 byte is, then use the [`to_str`](#method.to_str) method.
305    ///
306    /// # Examples
307    /// ```
308    /// use janetrs::JanetString;
309    /// # let _client = janetrs::client::JanetClient::init().unwrap();
310    ///
311    /// assert!(JanetString::new("abc").is_utf8());
312    /// assert!(JanetString::new("☃βツ").is_utf8());
313    /// // invalid bytes
314    /// assert!(!JanetString::new(&b"abc\xFF"[..]).is_utf8());
315    /// // surrogate encoding
316    /// assert!(!JanetString::new(&b"\xED\xA0\x80"[..]).is_utf8());
317    /// // incomplete sequence
318    /// assert!(!JanetString::new(&b"\xF0\x9D\x9Ca"[..]).is_utf8());
319    /// // overlong sequence
320    /// assert!(!JanetString::new(&b"\xF0\x82\x82\xAC"[..]).is_utf8());
321    /// ```
322    #[inline]
323    pub fn is_utf8(&self) -> bool {
324        self.as_bytes().is_utf8()
325    }
326
327    /// Returns a new `JanetString` containing the lowercase equivalent of this
328    /// string.
329    ///
330    /// In this case, lowercase is defined according to the `Lowercase` Unicode
331    /// property.
332    ///
333    /// If invalid UTF-8 is seen, or if a character has no lowercase variant,
334    /// then it is written to the given buffer unchanged.
335    ///
336    /// Note that some characters in this string may expand into multiple
337    /// characters when changing the case, so the number of bytes written to
338    /// the given string may not be equivalent to the number of bytes in
339    /// this string.
340    ///
341    /// If you'd like to reuse an allocation for performance reasons, then use
342    /// [`to_lowercase_into`](#method.to_lowercase_into) instead.
343    ///
344    /// # Examples
345    ///
346    /// Basic usage:
347    ///
348    /// ```
349    /// use janetrs::JanetString;
350    /// # let _client = janetrs::client::JanetClient::init().unwrap();
351    ///
352    /// let s = JanetString::new("HELLO Β");
353    /// assert_eq!(s.to_lowercase(), JanetString::new("hello β"));
354    /// ```
355    ///
356    /// Scripts without case are not changed:
357    ///
358    /// ```
359    /// use janetrs::JanetString;
360    /// # let _client = janetrs::client::JanetClient::init().unwrap();
361    ///
362    /// let s = JanetString::new("农历新年");
363    /// assert_eq!(s.to_lowercase(), JanetString::new("农历新年"));
364    /// ```
365    ///
366    /// Invalid UTF-8 remains as is:
367    ///
368    /// ```
369    /// use janetrs::JanetString;
370    /// # let _client = janetrs::client::JanetClient::init().unwrap();
371    ///
372    /// let s = JanetString::new(&b"FOO\xFFBAR\xE2\x98BAZ"[..]);
373    /// assert_eq!(
374    ///     s.to_lowercase(),
375    ///     JanetString::new(&b"foo\xFFbar\xE2\x98baz"[..])
376    /// );
377    /// ```
378    #[cfg(feature = "unicode")]
379    #[cfg_attr(docsrs, doc(cfg(feature = "unicode")))]
380    #[allow(clippy::return_self_not_must_use)]
381    #[inline]
382    pub fn to_lowercase(&self) -> Self {
383        self.as_bytes().to_lowercase().into()
384    }
385
386    /// Writes the lowercase equivalent of this string into the given
387    /// buffer. The buffer is not cleared before written to.
388    ///
389    /// In this case, lowercase is defined according to the `Lowercase`
390    /// Unicode property.
391    ///
392    /// If invalid UTF-8 is seen, or if a character has no lowercase variant,
393    /// then it is written to the given buffer unchanged.
394    ///
395    /// Note that some characters in this string may expand into multiple
396    /// characters when changing the case, so the number of bytes written to
397    /// the given buffer may not be equivalent to the number of bytes in
398    /// this string.
399    ///
400    /// If you don't need to amortize allocation and instead prefer
401    /// convenience, then use [`to_lowercase`](#method.to_lowercase) instead.
402    ///
403    /// # Examples
404    ///
405    /// Basic usage:
406    ///
407    /// ```
408    /// use janetrs::{JanetBuffer, JanetString};
409    /// # let _client = janetrs::client::JanetClient::init().unwrap();
410    ///
411    /// let s = JanetString::new("HELLO Β");
412    ///
413    /// let mut buf = JanetBuffer::new();
414    /// s.to_lowercase_into(&mut buf);
415    /// assert_eq!("hello β".as_bytes(), buf.as_bytes());
416    /// ```
417    ///
418    /// Scripts without case are not changed:
419    ///
420    /// ```
421    /// use janetrs::{JanetBuffer, JanetString};
422    /// # let _client = janetrs::client::JanetClient::init().unwrap();
423    ///
424    /// let s = JanetString::new("农历新年");
425    ///
426    /// let mut buf = JanetBuffer::new();
427    /// s.to_lowercase_into(&mut buf);
428    /// assert_eq!("农历新年".as_bytes(), buf.as_bytes());
429    /// ```
430    ///
431    /// Invalid UTF-8 remains as is:
432    ///
433    /// ```
434    /// use janetrs::{JanetBuffer, JanetString};
435    /// # let _client = janetrs::client::JanetClient::init().unwrap();
436    ///
437    /// let s = JanetString::new(&b"FOO\xFFBAR\xE2\x98BAZ"[..]);
438    ///
439    /// let mut buf = JanetBuffer::new();
440    /// s.to_lowercase_into(&mut buf);
441    /// assert_eq!(
442    ///     JanetBuffer::from(&b"foo\xFFbar\xE2\x98baz"[..]).as_bytes(),
443    ///     buf.as_bytes()
444    /// );
445    /// ```
446    #[cfg(feature = "unicode")]
447    #[cfg_attr(docsrs, doc(cfg(feature = "unicode")))]
448    #[inline]
449    pub fn to_lowercase_into(&self, buf: &mut JanetBuffer) {
450        buf.reserve(self.len());
451
452        for (s, e, ch) in self.char_indices() {
453            if ch == '\u{FFFD}' {
454                buf.push_bytes(&self.as_bytes()[s..e]);
455            } else if ch.is_ascii() {
456                buf.push_char(ch.to_ascii_lowercase());
457            } else {
458                for upper in ch.to_lowercase() {
459                    buf.push_char(upper);
460                }
461            }
462        }
463    }
464
465    /// Returns a new `JanetBuffer` containing the ASCII lowercase equivalent of
466    /// this buffer.
467    ///
468    /// In this case, lowercase is only defined in ASCII letters. Namely, the
469    /// letters `A-Z` are converted to `a-z`. All other bytes remain unchanged.
470    /// In particular, the length of the buffer returned is always
471    /// equivalent to the length of this buffer.
472    ///
473    /// # Examples
474    ///
475    /// Basic usage:
476    ///
477    /// ```
478    /// use janetrs::JanetString;
479    /// # let _client = janetrs::client::JanetClient::init().unwrap();
480    ///
481    /// let s = JanetString::new("HELLO Β");
482    /// assert_eq!(s.to_ascii_lowercase(), JanetString::new("hello Β"));
483    /// ```
484    ///
485    /// Invalid UTF-8 remains as is:
486    ///
487    /// ```
488    /// use janetrs::JanetString;
489    /// # let _client = janetrs::client::JanetClient::init().unwrap();
490    ///
491    /// let s = JanetString::new(&b"FOO\xFFBAR\xE2\x98BAZ"[..]);
492    /// assert_eq!(
493    ///     s.to_ascii_lowercase(),
494    ///     JanetString::new(&b"foo\xFFbar\xE2\x98baz"[..])
495    /// );
496    /// ```
497    #[allow(clippy::return_self_not_must_use)]
498    pub fn to_ascii_lowercase(&self) -> Self {
499        Self::new(self.as_bytes().to_ascii_lowercase())
500    }
501
502    /// Returns a new `JanetString` containing the uppercase equivalent of this
503    /// string.
504    ///
505    /// In this case, uppercase is defined according to the `Uppercase`
506    /// Unicode property.
507    ///
508    /// If invalid UTF-8 is seen, or if a character has no uppercase variant,
509    /// then it is written to the given buffer unchanged.
510    ///
511    /// Note that some characters in this string may expand into multiple
512    /// characters when changing the case, so the number of bytes written to
513    /// the given buffer may not be equivalent to the number of bytes in
514    /// this string.
515    ///
516    /// If you'd like to reuse an allocation for performance reasons, then use
517    /// [`to_uppercase_into`](#method.to_uppercase_into) instead.
518    ///
519    /// # Examples
520    ///
521    /// Basic usage:
522    ///
523    /// ```
524    /// use janetrs::JanetString;
525    /// # let _client = janetrs::client::JanetClient::init().unwrap();
526    ///
527    /// let s = JanetString::new("hello β");
528    /// assert_eq!(s.to_uppercase(), JanetString::new("HELLO Β"));
529    /// ```
530    ///
531    /// Scripts without case are not changed:
532    ///
533    /// ```
534    /// use janetrs::JanetString;
535    /// # let _client = janetrs::client::JanetClient::init().unwrap();
536    ///
537    /// let s = JanetString::new("农历新年");
538    /// assert_eq!(s.to_uppercase(), JanetString::new("农历新年"));
539    /// ```
540    ///
541    /// Invalid UTF-8 remains as is:
542    ///
543    /// ```
544    /// use janetrs::JanetString;
545    /// # let _client = janetrs::client::JanetClient::init().unwrap();
546    ///
547    /// let s = JanetString::new(&b"foo\xFFbar\xE2\x98baz"[..]);
548    /// assert_eq!(
549    ///     s.to_uppercase(),
550    ///     JanetString::new(&b"FOO\xFFBAR\xE2\x98BAZ"[..])
551    /// );
552    /// ```
553    #[cfg(feature = "unicode")]
554    #[cfg_attr(docsrs, doc(cfg(feature = "unicode")))]
555    #[inline]
556    #[allow(clippy::return_self_not_must_use)]
557    pub fn to_uppercase(&self) -> Self {
558        self.as_bytes().to_uppercase().into()
559    }
560
561    /// Writes the uppercase equivalent of this string into the given
562    /// buffer. The buffer is not cleared before written to.
563    ///
564    /// In this case, uppercase is defined according to the `Uppercase`
565    /// Unicode property.
566    ///
567    /// If invalid UTF-8 is seen, or if a character has no uppercase variant,
568    /// then it is written to the given buffer unchanged.
569    ///
570    /// Note that some characters in this buffer may expand into multiple
571    /// characters when changing the case, so the number of bytes written to
572    /// the given buffer may not be equivalent to the number of bytes in
573    /// this buffer.
574    ///
575    /// If you don't need to amortize allocation and instead prefer
576    /// convenience, then use [`to_uppercase`](#method.to_uppercase) instead.
577    ///
578    /// # Examples
579    ///
580    /// Basic usage:
581    ///
582    /// ```
583    /// use janetrs::{JanetBuffer, JanetString};
584    /// # let _client = janetrs::client::JanetClient::init().unwrap();
585    ///
586    /// let s = JanetString::new("hello β");
587    ///
588    /// let mut buf = JanetBuffer::new();
589    /// s.to_uppercase_into(&mut buf);
590    /// assert_eq!(buf.as_bytes(), "HELLO Β".as_bytes());
591    /// ```
592    ///
593    /// Scripts without case are not changed:
594    ///
595    /// ```
596    /// use janetrs::{JanetBuffer, JanetString};
597    /// # let _client = janetrs::client::JanetClient::init().unwrap();
598    ///
599    /// let s = JanetString::new("农历新年");
600    ///
601    /// let mut buf = JanetBuffer::new();
602    /// s.to_uppercase_into(&mut buf);
603    /// assert_eq!(buf.as_bytes(), "农历新年".as_bytes());
604    /// ```
605    ///
606    /// Invalid UTF-8 remains as is:
607    ///
608    /// ```
609    /// use janetrs::{JanetBuffer, JanetString};
610    /// # let _client = janetrs::client::JanetClient::init().unwrap();
611    ///
612    /// let s = JanetString::new(&b"foo\xFFbar\xE2\x98baz"[..]);
613    ///
614    /// let mut buf = JanetBuffer::new();
615    /// s.to_uppercase_into(&mut buf);
616    /// assert_eq!(buf.as_bytes(), &b"FOO\xFFBAR\xE2\x98BAZ"[..]);
617    /// ```
618    #[cfg(feature = "unicode")]
619    #[cfg_attr(docsrs, doc(cfg(feature = "unicode")))]
620    #[inline]
621    pub fn to_uppercase_into(&self, buf: &mut JanetBuffer) {
622        // based on bstr version of the same function
623        buf.reserve(self.len());
624
625        for (s, e, ch) in self.char_indices() {
626            if ch == '\u{FFFD}' {
627                buf.push_bytes(&self.as_bytes()[s..e]);
628            } else if ch.is_ascii() {
629                buf.push_char(ch.to_ascii_uppercase());
630            } else {
631                for upper in ch.to_uppercase() {
632                    buf.push_char(upper);
633                }
634            }
635        }
636    }
637
638    /// Returns a new `JanetString` containing the ASCII uppercase equivalent of
639    /// this string.
640    ///
641    /// In this case, uppercase is only defined in ASCII letters. Namely, the
642    /// letters `a-z` are converted to `A-Z`. All other bytes remain unchanged.
643    /// In particular, the length of the string returned is always
644    /// equivalent to the length of this string.
645    ///
646    /// # Examples
647    ///
648    /// Basic usage:
649    ///
650    /// ```
651    /// use janetrs::JanetString;
652    /// # let _client = janetrs::client::JanetClient::init().unwrap();
653    ///
654    /// let s = JanetString::new("hello β");
655    /// assert_eq!(s.to_ascii_uppercase().as_bytes(), "HELLO β".as_bytes());
656    /// ```
657    ///
658    /// Invalid UTF-8 remains as is:
659    ///
660    /// ```
661    /// use janetrs::JanetString;
662    /// # let _client = janetrs::client::JanetClient::init().unwrap();
663    ///
664    /// let s = JanetString::new(&b"foo\xFFbar\xE2\x98baz"[..]);
665    /// assert_eq!(
666    ///     s.to_ascii_uppercase().as_bytes(),
667    ///     &b"FOO\xFFBAR\xE2\x98BAZ"[..]
668    /// );
669    /// ```
670    #[allow(clippy::return_self_not_must_use)]
671    #[inline]
672    pub fn to_ascii_uppercase(&self) -> Self {
673        self.as_bytes().to_ascii_uppercase().into()
674    }
675
676    /// Return a string with leading and trailing whitespace removed.
677    ///
678    /// Whitespace is defined according to the terms of the `White_Space`
679    /// Unicode property.
680    ///
681    /// # Examples
682    ///
683    /// Basic usage:
684    ///
685    /// ```
686    /// use janetrs::JanetString;
687    /// # let _client = janetrs::client::JanetClient::init().unwrap();
688    ///
689    /// let s = JanetString::new(" foo\tbar\t\u{2003}\n");
690    /// assert_eq!(s.trim(), JanetString::new("foo\tbar"));
691    /// ```
692    #[cfg(feature = "unicode")]
693    #[cfg_attr(docsrs, doc(cfg(feature = "unicode")))]
694    #[allow(clippy::return_self_not_must_use)]
695    #[inline]
696    pub fn trim(&self) -> Self {
697        self.as_bytes().trim().into()
698    }
699
700    /// Return a string with leading whitespace removed.
701    ///
702    /// Whitespace is defined according to the terms of the `White_Space`
703    /// Unicode property.
704    ///
705    /// # Examples
706    ///
707    /// Basic usage:
708    ///
709    /// ```
710    /// use janetrs::JanetString;
711    /// # let _client = janetrs::client::JanetClient::init().unwrap();
712    ///
713    /// let s = JanetString::new(" foo\tbar\t\u{2003}\n");
714    /// assert_eq!(s.trim_start(), JanetString::new("foo\tbar\t\u{2003}\n"));
715    /// ```
716    #[cfg(feature = "unicode")]
717    #[cfg_attr(docsrs, doc(cfg(feature = "unicode")))]
718    #[allow(clippy::return_self_not_must_use)]
719    #[inline]
720    pub fn trim_start(&self) -> Self {
721        self.as_bytes().trim_start().into()
722    }
723
724    /// Return a string with trailing whitespace removed.
725    ///
726    /// Whitespace is defined according to the terms of the `White_Space`
727    /// Unicode property.
728    ///
729    /// # Examples
730    ///
731    /// Basic usage:
732    ///
733    /// ```
734    /// use janetrs::JanetString;
735    /// # let _client = janetrs::client::JanetClient::init().unwrap();
736    ///
737    /// let s = JanetString::new(" foo\tbar\t\u{2003}\n");
738    /// assert_eq!(s.trim_end(), JanetString::new(" foo\tbar"));
739    /// ```
740    #[cfg(feature = "unicode")]
741    #[cfg_attr(docsrs, doc(cfg(feature = "unicode")))]
742    #[allow(clippy::return_self_not_must_use)]
743    #[inline]
744    pub fn trim_end(&self) -> Self {
745        self.as_bytes().trim_end().into()
746    }
747
748    /// Return a string with leading and trailing characters
749    /// satisfying the given predicate removed.
750    ///
751    /// # Examples
752    ///
753    /// Basic usage:
754    ///
755    /// ```
756    /// use janetrs::JanetString;
757    /// # let _client = janetrs::client::JanetClient::init().unwrap();
758    ///
759    /// let s = JanetString::new("123foo5bar789");
760    /// assert_eq!(s.trim_with(|c| c.is_numeric()), JanetString::new("foo5bar"),);
761    /// ```
762    #[allow(clippy::return_self_not_must_use)]
763    #[inline]
764    pub fn trim_with<F: FnMut(char) -> bool>(&self, trim: F) -> Self {
765        self.as_bytes().trim_with(trim).into()
766    }
767
768    /// Return a string with leading characters satisfying the given
769    /// predicate removed.
770    ///
771    /// # Examples
772    ///
773    /// Basic usage:
774    ///
775    /// ```
776    /// use janetrs::JanetString;
777    /// # let _client = janetrs::client::JanetClient::init().unwrap();
778    ///
779    /// let s = JanetString::new("123foo5bar789");
780    /// assert_eq!(
781    ///     s.trim_start_with(|c| c.is_numeric()),
782    ///     JanetString::new("foo5bar789")
783    /// );
784    /// ```
785    #[allow(clippy::return_self_not_must_use)]
786    #[inline]
787    pub fn trim_start_with<F: FnMut(char) -> bool>(&self, trim: F) -> Self {
788        self.as_bytes().trim_start_with(trim).into()
789    }
790
791    /// Return a string with trailing characters satisfying the
792    /// given predicate removed.
793    ///
794    /// # Examples
795    ///
796    /// Basic usage:
797    ///
798    /// ```
799    /// use janetrs::JanetString;
800    /// # let _client = janetrs::client::JanetClient::init().unwrap();
801    ///
802    /// let s = JanetString::new("123foo5bar");
803    /// assert_eq!(
804    ///     s.trim_end_with(|c| c.is_numeric()),
805    ///     JanetString::new("123foo5bar")
806    /// );
807    /// ```
808    #[allow(clippy::return_self_not_must_use)]
809    #[inline]
810    pub fn trim_end_with<F: FnMut(char) -> bool>(&self, trim: F) -> Self {
811        self.as_bytes().trim_end_with(trim).into()
812    }
813
814    /// Safely convert this string into a `&str` if it's valid UTF-8.
815    ///
816    /// If this string is not valid UTF-8, then an error is returned. The
817    /// error returned indicates the first invalid byte found and the length
818    /// of the error.
819    ///
820    /// In cases where a lossy conversion to `&str` is acceptable, then use one
821    /// of the [`to_str_lossy`](#method.to_str_lossy) or
822    /// [`to_str_lossy_into`](#method.to_str_lossy_into) methods.
823    #[inline]
824    pub fn to_str(&self) -> Result<&str, Utf8Error> {
825        self.as_bytes().to_str()
826    }
827
828    /// Unsafely convert this string into a `&str`, without checking for
829    /// valid UTF-8.
830    ///
831    /// # Safety
832    ///
833    /// Callers *must* ensure that this string is valid UTF-8 before
834    /// calling this method. Converting a string into a `&str` that is
835    /// not valid UTF-8 is considered undefined behavior.
836    ///
837    /// This routine is useful in performance sensitive contexts where the
838    /// UTF-8 validity of the string is already known and it is
839    /// undesirable to pay the cost of an additional UTF-8 validation check
840    /// that [`to_str`](#method.to_str) performs.
841    #[inline]
842    pub unsafe fn to_str_unchecked(&self) -> &str {
843        self.as_bytes().to_str_unchecked()
844    }
845
846    /// Convert this string to a valid UTF-8 string by replacing invalid
847    /// UTF-8 bytes with the Unicode replacement codepoint (`U+FFFD`).
848    ///
849    /// If the string is already valid UTF-8, then no copying or
850    /// allocation is performed and a borrowed string slice is returned. If
851    /// the string is not valid UTF-8, then an owned string string is
852    /// returned with invalid bytes replaced by the replacement codepoint.
853    ///
854    /// This method uses the "substitution of maximal subparts" (Unicode
855    /// Standard, Chapter 3, Section 9) strategy for inserting the replacement
856    /// codepoint. Specifically, a replacement codepoint is inserted whenever a
857    /// byte is found that cannot possibly lead to a valid code unit sequence.
858    /// If there were previous bytes that represented a prefix of a well-formed
859    /// code unit sequence, then all of those bytes are substituted with a
860    /// single replacement codepoint. The "substitution of maximal subparts"
861    /// strategy is the same strategy used by
862    /// [W3C's Encoding standard](https://www.w3.org/TR/encoding/).
863    /// For a more precise description of the maximal subpart strategy, see
864    /// the Unicode Standard, Chapter 3, Section 9. See also
865    /// [Public Review Issue #121](http://www.unicode.org/review/pr-121.html).
866    ///
867    /// N.B. Rust's standard library also appears to use the same strategy,
868    /// but it does not appear to be an API guarantee.
869    #[inline]
870    pub fn to_str_lossy(&self) -> Cow<str> {
871        self.as_bytes().to_str_lossy()
872    }
873
874    /// Copy the contents of this string into the given owned string
875    /// string, while replacing invalid UTF-8 code unit sequences with the
876    /// Unicode replacement codepoint (`U+FFFD`).
877    ///
878    /// This method uses the same "substitution of maximal subparts" strategy
879    /// for inserting the replacement codepoint as the
880    /// [`to_str_lossy`](trait.ByteSlice.html#method.to_str_lossy) method.
881    ///
882    /// This routine is useful for amortizing allocation. However, unlike
883    /// `to_str_lossy`, this routine will _always_ copy the contents of this
884    /// string into the destination string, even if this string is
885    /// valid UTF-8.
886    #[inline]
887    pub fn to_str_lossy_into(&self, dest: &mut String) {
888        self.as_bytes().to_str_lossy_into(dest)
889    }
890
891    /// Create an OS string slice from this string.
892    ///
893    /// On Unix, this always succeeds and is zero cost. On non-Unix systems,
894    /// this returns a UTF-8 decoding error if this string is not valid
895    /// UTF-8. (For example, on Windows, file paths are allowed to be a
896    /// sequence of arbitrary 16-bit integers. There is no obvious mapping from
897    /// an arbitrary sequence of 8-bit integers to an arbitrary sequence of
898    /// 16-bit integers.)
899    #[cfg(feature = "std")]
900    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
901    #[inline]
902    pub fn to_os_str(&self) -> Result<&OsStr, Utf8Error> {
903        self.as_bytes().to_os_str()
904    }
905
906    /// Lossily create an OS string slice from this string.
907    ///
908    /// On Unix, this always succeeds and is zero cost. On non-Unix systems,
909    /// this will perform a UTF-8 check and lossily convert this string
910    /// into valid UTF-8 using the Unicode replacement codepoint.
911    ///
912    /// Note that this can prevent the correct round-tripping of file paths on
913    /// non-Unix systems such as Windows, where file paths are an arbitrary
914    /// sequence of 16-bit integers.
915    #[cfg(feature = "std")]
916    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
917    #[inline]
918    pub fn to_os_str_lossy(&self) -> Cow<OsStr> {
919        self.as_bytes().to_os_str_lossy()
920    }
921
922    /// Create a path slice from this string.
923    ///
924    /// On Unix, this always succeeds and is zero cost. On non-Unix systems,
925    /// this returns a UTF-8 decoding error if this string is not valid
926    /// UTF-8. (For example, on Windows, file paths are allowed to be a
927    /// sequence of arbitrary 16-bit integers. There is no obvious mapping from
928    /// an arbitrary sequence of 8-bit integers to an arbitrary sequence of
929    /// 16-bit integers.)
930    #[cfg(feature = "std")]
931    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
932    #[inline]
933    pub fn to_path(&self) -> Result<&Path, Utf8Error> {
934        self.as_bytes().to_path()
935    }
936
937    /// Lossily create a path slice from this string.
938    ///
939    /// On Unix, this always succeeds and is zero cost. On non-Unix systems,
940    /// this will perform a UTF-8 check and lossily convert this string
941    /// into valid UTF-8 using the Unicode replacement codepoint.
942    ///
943    /// Note that this can prevent the correct round-tripping of file paths on
944    /// non-Unix systems such as Windows, where file paths are an arbitrary
945    /// sequence of 16-bit integers.
946    #[cfg(feature = "std")]
947    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
948    #[inline]
949    pub fn to_path_lossy(&self) -> Cow<Path> {
950        self.as_bytes().to_path_lossy()
951    }
952
953    /// Returns the index of the first occurrence of the given `needle`.
954    ///
955    /// The `needle` may be any type that can be cheaply converted into a
956    /// `&[u8]`. This includes, but is not limited to, `&str` and `&[u8]`.
957    ///
958    /// # Complexity
959    ///
960    /// This routine is guaranteed to have worst case linear time complexity
961    /// with respect to both the `needle` and the haystack. That is, this runs
962    /// in `O(needle.len() + haystack.len())` time.
963    ///
964    /// This routine is also guaranteed to have worst case constant space
965    /// complexity.
966    ///
967    /// # Examples
968    /// ```
969    /// use janetrs::JanetString;
970    /// # let _client = janetrs::client::JanetClient::init().unwrap();
971    ///
972    /// let s = JanetString::new("foo bar baz");
973    /// assert_eq!(Some(0), s.find("foo"));
974    /// assert_eq!(Some(4), s.find("bar"));
975    /// assert_eq!(None, s.find("quux"));
976    /// ```
977    #[inline]
978    pub fn find(&self, needle: impl AsRef<[u8]>) -> Option<usize> {
979        self.as_bytes().find(needle)
980    }
981
982    /// Returns the index of the last occurrence of the given `needle`.
983    ///
984    /// The `needle` may be any type that can be cheaply converted into a
985    /// `&[u8]`. This includes, but is not limited to, `&str` and `&[u8]`.
986    ///
987    /// # Complexity
988    ///
989    /// This routine is guaranteed to have worst case linear time complexity
990    /// with respect to both the `needle` and the haystack. That is, this runs
991    /// in `O(needle.len() + haystack.len())` time.
992    ///
993    /// This routine is also guaranteed to have worst case constant space
994    /// complexity.
995    ///
996    /// # Examples
997    /// ```
998    /// use janetrs::JanetString;
999    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1000    ///
1001    /// let s = JanetString::new("foo bar baz");
1002    /// assert_eq!(Some(0), s.rfind("foo"));
1003    /// assert_eq!(Some(4), s.rfind("bar"));
1004    /// assert_eq!(Some(8), s.rfind("ba"));
1005    /// assert_eq!(None, s.rfind("quux"));
1006    /// ```
1007    #[inline]
1008    pub fn rfind(&self, needle: impl AsRef<[u8]>) -> Option<usize> {
1009        self.as_bytes().rfind(needle)
1010    }
1011
1012    /// Returns the index of the first occurrence of the given byte. If the
1013    /// byte does not occur in this string, then `None` is returned.
1014    ///
1015    /// # Examples
1016    /// ```
1017    /// use janetrs::JanetString;
1018    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1019    ///
1020    /// assert_eq!(Some(10), JanetString::new("foo bar baz").find_byte(b'z'));
1021    /// assert_eq!(None, JanetString::new("foo bar baz").find_byte(b'y'));
1022    /// ```
1023    #[inline]
1024    pub fn find_byte(&self, byte: u8) -> Option<usize> {
1025        self.as_bytes().find_byte(byte)
1026    }
1027
1028    /// Returns the index of the last occurrence of the given `byte`. If the
1029    /// `byte` does not occur in this string, then `None` is returned.
1030    ///
1031    /// # Examples
1032    /// ```
1033    /// use janetrs::JanetString;
1034    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1035    ///
1036    /// assert_eq!(Some(10), JanetString::new("foo bar baz").rfind_byte(b'z'));
1037    /// assert_eq!(None, JanetString::new("foo bar baz").rfind_byte(b'y'));
1038    /// ```
1039    #[inline]
1040    pub fn rfind_byte(&self, byte: u8) -> Option<usize> {
1041        self.as_bytes().rfind_byte(byte)
1042    }
1043
1044    /// Returns the index of the first occurrence of the given codepoint.
1045    /// If the codepoint does not occur in this string, then `None` is
1046    /// returned.
1047    ///
1048    /// Note that if one searches for the replacement codepoint, `\u{FFFD}`,
1049    /// then only explicit occurrences of that encoding will be found. Invalid
1050    /// UTF-8 sequences will not be matched.
1051    ///
1052    /// # Examples
1053    /// ```
1054    /// use janetrs::JanetString;
1055    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1056    ///
1057    /// assert_eq!(Some(10), JanetString::new("foo bar baz").find_char('z'));
1058    /// assert_eq!(Some(4), JanetString::new("αβγγδ").find_char('γ'));
1059    /// assert_eq!(None, JanetString::new("foo bar baz").find_char('y'));
1060    /// ```
1061    #[inline]
1062    pub fn find_char(&self, ch: char) -> Option<usize> {
1063        self.find(ch.encode_utf8(&mut [0; 4]))
1064    }
1065
1066    /// Returns the index of the last occurrence of the given codepoint.
1067    /// If the codepoint does not occur in this string, then `None` is
1068    /// returned.
1069    ///
1070    /// Note that if one searches for the replacement codepoint, `\u{FFFD}`,
1071    /// then only explicit occurrences of that encoding will be found. Invalid
1072    /// UTF-8 sequences will not be matched.
1073    ///
1074    /// # Examples
1075    /// ```
1076    /// use janetrs::JanetString;
1077    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1078    ///
1079    /// assert_eq!(Some(10), JanetString::new("foo bar baz").rfind_char('z'));
1080    /// assert_eq!(Some(6), JanetString::new("αβγγδ").rfind_char('γ'));
1081    /// assert_eq!(None, JanetString::new("foo bar baz").rfind_char('y'));
1082    /// ```
1083    #[inline]
1084    pub fn rfind_char(&self, ch: char) -> Option<usize> {
1085        self.rfind(ch.encode_utf8(&mut [0; 4]))
1086    }
1087
1088    /// Returns the index of the first occurrence of any of the bytes in the
1089    /// provided set.
1090    ///
1091    /// The `byteset` may be any type that can be cheaply converted into a
1092    /// `&[u8]`. This includes, but is not limited to, `&str` and `&[u8]`, but
1093    /// note that passing a `&str` which contains multibyte characters may not
1094    /// behave as you expect: each byte in the `&str` is treated as an
1095    /// individual member of the byte set.
1096    ///
1097    /// Note that order is irrelevant for the `byteset` parameter, and
1098    /// duplicate bytes present in its body are ignored.
1099    ///
1100    /// # Complexity
1101    ///
1102    /// This routine is guaranteed to have worst case linear time complexity
1103    /// with respect to both the set of bytes and the haystack. That is, this
1104    /// runs in `O(byteset.len() + haystack.len())` time.
1105    ///
1106    /// This routine is also guaranteed to have worst case constant space
1107    /// complexity.
1108    ///
1109    /// # Examples
1110    /// ```
1111    /// use janetrs::JanetString;
1112    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1113    ///
1114    /// assert_eq!(JanetString::new("foo bar baz").find_byteset(b"zr"), Some(6));
1115    /// assert_eq!(
1116    ///     JanetString::new("foo baz bar").find_byteset(b"bzr"),
1117    ///     Some(4)
1118    /// );
1119    /// assert_eq!(None, JanetString::new("foo baz bar").find_byteset(b"\t\n"));
1120    /// ```
1121    #[inline]
1122    pub fn find_byteset(&self, byteset: impl AsRef<[u8]>) -> Option<usize> {
1123        self.as_bytes().find_byteset(byteset)
1124    }
1125
1126    /// Returns the index of the first occurrence of a byte that is not a member
1127    /// of the provided set.
1128    ///
1129    /// The `byteset` may be any type that can be cheaply converted into a
1130    /// `&[u8]`. This includes, but is not limited to, `&str` and `&[u8]`, but
1131    /// note that passing a `&str` which contains multibyte characters may not
1132    /// behave as you expect: each byte in the `&str` is treated as an
1133    /// individual member of the byte set.
1134    ///
1135    /// Note that order is irrelevant for the `byteset` parameter, and
1136    /// duplicate bytes present in its body are ignored.
1137    ///
1138    /// # Complexity
1139    ///
1140    /// This routine is guaranteed to have worst case linear time complexity
1141    /// with respect to both the set of bytes and the haystack. That is, this
1142    /// runs in `O(byteset.len() + haystack.len())` time.
1143    ///
1144    /// This routine is also guaranteed to have worst case constant space
1145    /// complexity.
1146    ///
1147    /// # Examples
1148    /// ```
1149    /// use janetrs::JanetString;
1150    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1151    ///
1152    /// assert_eq!(
1153    ///     JanetString::new("foo bar baz").find_not_byteset(b"fo "),
1154    ///     Some(4)
1155    /// );
1156    /// assert_eq!(
1157    ///     JanetString::new("\t\tbaz bar").find_not_byteset(b" \t\r\n"),
1158    ///     Some(2)
1159    /// );
1160    /// assert_eq!(
1161    ///     JanetString::new("foo\nbaz\tbar").find_not_byteset(b"\t\n"),
1162    ///     Some(0)
1163    /// );
1164    /// ```
1165    #[inline]
1166    pub fn find_not_byteset(&self, byteset: impl AsRef<[u8]>) -> Option<usize> {
1167        self.as_bytes().find_not_byteset(byteset)
1168    }
1169
1170    /// Returns the index of the last occurrence of any of the bytes in the
1171    /// provided set.
1172    ///
1173    /// The `byteset` may be any type that can be cheaply converted into a
1174    /// `&[u8]`. This includes, but is not limited to, `&str` and `&[u8]`, but
1175    /// note that passing a `&str` which contains multibyte characters may not
1176    /// behave as you expect: each byte in the `&str` is treated as an
1177    /// individual member of the byte set.
1178    ///
1179    /// Note that order is irrelevant for the `byteset` parameter, and duplicate
1180    /// bytes present in its body are ignored.
1181    ///
1182    /// # Complexity
1183    ///
1184    /// This routine is guaranteed to have worst case linear time complexity
1185    /// with respect to both the set of bytes and the haystack. That is, this
1186    /// runs in `O(byteset.len() + haystack.len())` time.
1187    ///
1188    /// This routine is also guaranteed to have worst case constant space
1189    /// complexity.
1190    ///
1191    /// # Examples
1192    /// ```
1193    /// use janetrs::JanetString;
1194    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1195    ///
1196    /// assert_eq!(
1197    ///     JanetString::new("foo bar baz").rfind_byteset(b"agb"),
1198    ///     Some(9)
1199    /// );
1200    /// assert_eq!(
1201    ///     JanetString::new("foo baz bar").rfind_byteset(b"rabz "),
1202    ///     Some(10)
1203    /// );
1204    /// assert_eq!(
1205    ///     JanetString::new("foo baz bar").rfind_byteset(b"\n123"),
1206    ///     None
1207    /// );
1208    /// ```
1209    #[inline]
1210    pub fn rfind_byteset(&self, byteset: impl AsRef<[u8]>) -> Option<usize> {
1211        self.as_bytes().rfind_byteset(byteset)
1212    }
1213
1214    /// Returns the index of the last occurrence of a byte that is not a member
1215    /// of the provided set.
1216    ///
1217    /// The `byteset` may be any type that can be cheaply converted into a
1218    /// `&[u8]`. This includes, but is not limited to, `&str` and `&[u8]`, but
1219    /// note that passing a `&str` which contains multibyte characters may not
1220    /// behave as you expect: each byte in the `&str` is treated as an
1221    /// individual member of the byte set.
1222    ///
1223    /// Note that order is irrelevant for the `byteset` parameter, and
1224    /// duplicate bytes present in its body are ignored.
1225    ///
1226    /// # Complexity
1227    ///
1228    /// This routine is guaranteed to have worst case linear time complexity
1229    /// with respect to both the set of bytes and the haystack. That is, this
1230    /// runs in `O(byteset.len() + haystack.len())` time.
1231    ///
1232    /// This routine is also guaranteed to have worst case constant space
1233    /// complexity.
1234    ///
1235    /// # Examples
1236    /// ```
1237    /// use janetrs::JanetString;
1238    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1239    ///
1240    /// assert_eq!(
1241    ///     JanetString::new("foo bar baz,\t").rfind_not_byteset(b",\t"),
1242    ///     Some(10)
1243    /// );
1244    /// assert_eq!(
1245    ///     JanetString::new("foo baz bar").rfind_not_byteset(b"rabz "),
1246    ///     Some(2)
1247    /// );
1248    /// assert_eq!(
1249    ///     None,
1250    ///     JanetString::new("foo baz bar").rfind_not_byteset(b"barfoz ")
1251    /// );
1252    /// ```
1253    #[inline]
1254    pub fn rfind_not_byteset(&self, byteset: impl AsRef<[u8]>) -> Option<usize> {
1255        self.as_bytes().rfind_not_byteset(byteset)
1256    }
1257
1258    /// Creates an iterator of the non-overlapping occurrences of the given
1259    /// `needle`. The iterator yields byte offset positions indicating the start
1260    /// of each match.
1261    ///
1262    /// # Complexity
1263    ///
1264    /// This routine is guaranteed to have worst case linear time complexity
1265    /// with respect to both the needle and the haystack. That is, this runs
1266    /// in `O(needle.len() + haystack.len())` time.
1267    ///
1268    /// This routine is also guaranteed to have worst case constant space
1269    /// complexity.
1270    ///
1271    /// # Examples
1272    ///
1273    /// Basic usage:
1274    ///
1275    /// ```
1276    /// use janetrs::JanetString;
1277    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1278    ///
1279    /// let s = JanetString::new("foo bar foo foo quux foo");
1280    /// let matches: Vec<usize> = s.find_iter("foo").collect();
1281    /// assert_eq!(matches, vec![0, 8, 12, 21]);
1282    /// ```
1283    ///
1284    /// An empty string matches at every position, including the position
1285    /// immediately following the last byte:
1286    ///
1287    /// ```
1288    /// use janetrs::JanetString;
1289    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1290    ///
1291    /// let matches: Vec<usize> = JanetString::new("foo").find_iter("").collect();
1292    /// assert_eq!(matches, vec![0, 1, 2, 3]);
1293    ///
1294    /// let matches: Vec<usize> = JanetString::new("").find_iter("").collect();
1295    /// assert_eq!(matches, vec![0]);
1296    /// ```
1297    #[inline]
1298    pub fn find_iter<'a, 'b, B>(&'a self, needle: &'b B) -> Find<'a, 'b>
1299    where
1300        B: ?Sized + AsRef<[u8]>,
1301    {
1302        self.as_bytes().find_iter(needle)
1303    }
1304
1305    /// Creates an iterator of the non-overlapping occurrences of the given
1306    /// `needle` in reverse. The iterator yields byte offset positions indicating
1307    /// the start of each match.
1308    ///
1309    /// # Complexity
1310    ///
1311    /// This routine is guaranteed to have worst case linear time complexity
1312    /// with respect to both the needle and the haystack. That is, this runs
1313    /// in `O(needle.len() + haystack.len())` time.
1314    ///
1315    /// This routine is also guaranteed to have worst case constant space
1316    /// complexity.
1317    ///
1318    /// # Examples
1319    ///
1320    /// Basic usage:
1321    ///
1322    /// ```
1323    /// use janetrs::JanetString;
1324    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1325    ///
1326    /// let s = JanetString::new("foo bar foo foo quux foo");
1327    /// let matches: Vec<usize> = s.rfind_iter("foo").collect();
1328    /// assert_eq!(matches, vec![21, 12, 8, 0]);
1329    /// ```
1330    ///
1331    /// An empty string matches at every position, including the position
1332    /// immediately following the last byte:
1333    ///
1334    /// ```
1335    /// use janetrs::JanetString;
1336    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1337    ///
1338    /// let matches: Vec<usize> = JanetString::new("foo").rfind_iter("").collect();
1339    /// assert_eq!(matches, vec![3, 2, 1, 0]);
1340    ///
1341    /// let matches: Vec<usize> = JanetString::new("").rfind_iter("").collect();
1342    /// assert_eq!(matches, vec![0]);
1343    /// ```
1344    #[inline]
1345    pub fn rfind_iter<'a, 'b, B>(&'a self, needle: &'b B) -> FindReverse<'a, 'b>
1346    where
1347        B: ?Sized + AsRef<[u8]>,
1348    {
1349        self.as_bytes().rfind_iter(needle)
1350    }
1351
1352    /// Creates an iterator over the bytes of the [`JanetString`].
1353    ///
1354    /// # Examples
1355    /// ```
1356    /// use janetrs::JanetString;
1357    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1358    ///
1359    /// let s = JanetString::new("Hello");
1360    ///
1361    /// assert_eq!(s.bytes().collect::<Vec<u8>>(), b"Hello");
1362    /// ```
1363    #[inline]
1364    pub fn bytes(&self) -> Bytes {
1365        self.as_bytes().bytes()
1366    }
1367
1368    /// Creates an iterator over the Unicode scalar values in this string. If invalid
1369    /// UTF-8 is encountered, then the Unicode replacement codepoint is yielded instead.
1370    ///
1371    /// # Examples
1372    /// ```
1373    /// use janetrs::JanetString;
1374    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1375    ///
1376    /// let s = JanetString::new(b"\xE2\x98\x83\xFF\xF0\x9D\x9E\x83\xE2\x98\x61");
1377    ///
1378    /// let chars: Vec<char> = s.chars().collect();
1379    /// assert_eq!(vec!['☃', '\u{FFFD}', '𝞃', '\u{FFFD}', 'a'], chars);
1380    /// ```
1381    #[inline]
1382    pub fn chars(&self) -> Chars {
1383        self.as_bytes().chars()
1384    }
1385
1386    /// Creates an iterator over the Unicode scalar values in this janet string along with
1387    /// their starting and ending byte index positions. If invalid UTF-8 is encountered,
1388    /// then the Unicode replacement codepoint is yielded instead.
1389    ///
1390    /// Note that this is slightly different from the `CharIndices` iterator provided by
1391    /// the standard library. Aside from working on possibly invalid UTF-8, this
1392    /// iterator provides both the corresponding starting and ending byte indices of
1393    /// each codepoint yielded. The ending position is necessary to slice the original
1394    /// string when invalid UTF-8 bytes are converted into a Unicode replacement
1395    /// codepoint, since a single replacement codepoint can substitute anywhere from 1
1396    /// to 3 invalid bytes (inclusive).
1397    ///
1398    /// # Examples
1399    /// ```
1400    /// use janetrs::JanetString;
1401    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1402    ///
1403    /// let s = JanetString::new(b"\xE2\x98\x83\xFF\xF0\x9D\x9E\x83\xE2\x98\x61");
1404    ///
1405    /// let chars: Vec<(usize, usize, char)> = s.char_indices().collect();
1406    /// assert_eq!(chars, vec![
1407    ///     (0, 3, '☃'),
1408    ///     (3, 4, '\u{FFFD}'),
1409    ///     (4, 8, '𝞃'),
1410    ///     (8, 10, '\u{FFFD}'),
1411    ///     (10, 11, 'a'),
1412    /// ]);
1413    /// ```
1414    #[inline]
1415    pub fn char_indices(&self) -> CharIndices {
1416        self.as_bytes().char_indices()
1417    }
1418
1419    /// Creates an iterator over the fields in a string, separated by
1420    /// contiguous whitespace.
1421    ///
1422    /// # Example
1423    ///
1424    /// Basic usage:
1425    ///
1426    /// ```
1427    /// use janetrs::JanetString;
1428    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1429    ///
1430    /// let s = JanetString::new("  foo\tbar\t\u{2003}\nquux   \n");
1431    /// let fields: Vec<&[u8]> = s.fields().collect();
1432    /// assert_eq!(fields, vec![
1433    ///     "foo".as_bytes(),
1434    ///     "bar".as_bytes(),
1435    ///     "quux".as_bytes()
1436    /// ]);
1437    /// ```
1438    ///
1439    /// A string consisting of just whitespace yields no elements:
1440    ///
1441    /// ```
1442    /// use janetrs::JanetString;
1443    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1444    ///
1445    /// assert_eq!(
1446    ///     0,
1447    ///     JanetString::new(&"  \n\t\u{2003}\n  \t").fields().count()
1448    /// );
1449    /// ```
1450    #[cfg(feature = "unicode")]
1451    #[cfg_attr(docsrs, doc(cfg(feature = "unicode")))]
1452    #[inline]
1453    pub fn fields(&self) -> Fields {
1454        self.as_bytes().fields()
1455    }
1456
1457    /// Creates an iterator over the fields in a string, separated by
1458    /// contiguous codepoints satisfying the given predicate.
1459    ///
1460    /// If this string is not valid UTF-8, then the given closure will
1461    /// be called with a Unicode replacement codepoint when invalid UTF-8
1462    /// bytes are seen.
1463    ///
1464    /// # Example
1465    ///
1466    /// Basic usage:
1467    ///
1468    /// ```
1469    /// use janetrs::JanetString;
1470    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1471    ///
1472    /// let s = JanetString::new("123foo999999bar1quux123456");
1473    /// let fields: Vec<&[u8]> = s.fields_with(|c| c.is_numeric()).collect();
1474    /// assert_eq!(fields, vec![
1475    ///     "foo".as_bytes(),
1476    ///     "bar".as_bytes(),
1477    ///     "quux".as_bytes()
1478    /// ]);
1479    /// ```
1480    ///
1481    /// A string consisting of all codepoints satisfying the predicate
1482    /// yields no elements:
1483    ///
1484    /// ```
1485    /// use janetrs::JanetString;
1486    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1487    ///
1488    /// assert_eq!(
1489    ///     0,
1490    ///     JanetString::new("1911354563")
1491    ///         .fields_with(|c| c.is_numeric())
1492    ///         .count()
1493    /// );
1494    /// ```
1495    #[inline]
1496    pub fn fields_with<F>(&self, f: F) -> FieldsWith<F>
1497    where
1498        F: FnMut(char) -> bool,
1499    {
1500        self.as_bytes().fields_with(f)
1501    }
1502
1503    /// Creates an iterator over the grapheme clusters in this string along with
1504    /// their starting and ending byte index positions. If invalid UTF-8 is encountered,
1505    /// then the Unicode replacement codepoint is yielded instead.
1506    ///
1507    /// # Examples
1508    ///
1509    /// This example shows how to get the byte offsets of each individual
1510    /// grapheme cluster:
1511    ///
1512    /// ```
1513    /// use janetrs::JanetString;
1514    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1515    ///
1516    /// let s = JanetString::new("a\u{0300}\u{0316}\u{1F1FA}\u{1F1F8}");
1517    /// let graphemes: Vec<(usize, usize, &str)> = s.grapheme_indices().collect();
1518    /// assert_eq!(vec![(0, 5, "à̖"), (5, 13, "🇺🇸")], graphemes);
1519    /// ```
1520    #[cfg(feature = "unicode")]
1521    #[cfg_attr(docsrs, doc(cfg(feature = "unicode")))]
1522    #[inline]
1523    pub fn grapheme_indices(&self) -> GraphemeIndices {
1524        self.as_bytes().grapheme_indices()
1525    }
1526
1527    /// Creates an iterator over the grapheme clusters in this string.
1528    /// If invalid UTF-8 is encountered, then the Unicode replacement codepoint
1529    /// is yielded instead.
1530    ///
1531    /// # Examples
1532    ///
1533    /// This example shows how multiple codepoints can combine to form a
1534    /// single grapheme cluster:
1535    ///
1536    /// ```
1537    /// use janetrs::JanetString;
1538    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1539    ///
1540    /// let s = JanetString::new("a\u{0300}\u{0316}\u{1F1FA}\u{1F1F8}");
1541    /// let graphemes: Vec<&str> = s.graphemes().collect();
1542    /// assert_eq!(vec!["à̖", "🇺🇸"], graphemes);
1543    /// ```
1544    ///
1545    /// This shows that graphemes can be iterated over in reverse:
1546    ///
1547    /// ```
1548    /// use janetrs::JanetString;
1549    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1550    ///
1551    /// let s = JanetString::new("a\u{0300}\u{0316}\u{1F1FA}\u{1F1F8}");
1552    /// let graphemes: Vec<&str> = s.graphemes().rev().collect();
1553    /// assert_eq!(vec!["🇺🇸", "à̖"], graphemes);
1554    /// ```
1555    #[cfg(feature = "unicode")]
1556    #[cfg_attr(docsrs, doc(cfg(feature = "unicode")))]
1557    #[inline]
1558    pub fn graphemes(&self) -> Graphemes {
1559        self.as_bytes().graphemes()
1560    }
1561
1562    /// Creates an iterator over all lines in a string, without their
1563    /// terminators.
1564    ///
1565    /// For this iterator, the only line terminators recognized are `\r\n` and
1566    /// `\n`.
1567    ///
1568    /// # Examples
1569    ///
1570    /// ```
1571    /// use janetrs::JanetString;
1572    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1573    ///
1574    /// let s = JanetString::new(
1575    ///     &b"\
1576    /// foo
1577    ///
1578    /// bar\r
1579    /// baz
1580    ///
1581    ///
1582    /// quux"[..],
1583    /// );
1584    /// let lines: Vec<&[u8]> = s.lines().collect();
1585    /// assert_eq!(lines, vec![
1586    ///     &b"foo"[..],
1587    ///     &b""[..],
1588    ///     &b"bar"[..],
1589    ///     &b"baz"[..],
1590    ///     &b""[..],
1591    ///     &b""[..],
1592    ///     &b"quux"[..],
1593    /// ]);
1594    /// ```
1595    #[inline]
1596    pub fn lines(&self) -> Lines {
1597        self.as_bytes().lines()
1598    }
1599
1600    /// Creates an iterator over all lines in a string, including their
1601    /// terminators.
1602    ///
1603    /// For this iterator, the only line terminator recognized is `\n`. (Since
1604    /// line terminators are included, this also handles `\r\n` line endings.)
1605    ///
1606    /// Line terminators are only included if they are present in the original
1607    /// string. For example, the last line in a string may not end
1608    /// with a line terminator.
1609    ///
1610    /// Concatenating all elements yielded by this iterator is guaranteed to
1611    /// yield the original string.
1612    ///
1613    /// # Examples
1614    ///
1615    /// ```
1616    /// use janetrs::JanetString;
1617    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1618    ///
1619    /// let s = JanetString::new(
1620    ///     &b"\
1621    /// foo
1622    ///
1623    /// bar\r
1624    /// baz
1625    ///
1626    ///
1627    /// quux"[..],
1628    /// );
1629    /// let lines: Vec<&[u8]> = s.lines_with_terminator().collect();
1630    /// assert_eq!(lines, vec![
1631    ///     &b"foo\n"[..],
1632    ///     &b"\n"[..],
1633    ///     &b"bar\r\n"[..],
1634    ///     &b"baz\n"[..],
1635    ///     &b"\n"[..],
1636    ///     &b"\n"[..],
1637    ///     &b"quux"[..],
1638    /// ]);
1639    /// ```
1640    #[inline]
1641    pub fn lines_with_terminator(&self) -> LinesWithTerminator {
1642        self.as_bytes().lines_with_terminator()
1643    }
1644
1645    /// Creates an iterator over the sentences in this string along with
1646    /// their starting and ending byte index positions.
1647    ///
1648    /// Typically, a sentence will include its trailing punctuation and
1649    /// whitespace. Concatenating all elements yielded by the iterator
1650    /// results in the original string (modulo Unicode replacement codepoint
1651    /// substitutions if invalid UTF-8 is encountered).
1652    ///
1653    /// Since sentences are made up of one or more codepoints, this iterator
1654    /// yields `&str` elements. When invalid UTF-8 is encountered, replacement
1655    /// codepoints are substituted.
1656    ///
1657    /// # Examples
1658    ///
1659    /// Basic usage:
1660    ///
1661    /// ```
1662    /// use janetrs::JanetString;
1663    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1664    ///
1665    /// let s = JanetString::new(&b"I want this. Not that. Right now."[..]);
1666    /// let sentences: Vec<(usize, usize, &str)> = s.sentence_indices().collect();
1667    /// assert_eq!(sentences, vec![
1668    ///     (0, 13, "I want this. "),
1669    ///     (13, 23, "Not that. "),
1670    ///     (23, 33, "Right now."),
1671    /// ]);
1672    /// ```
1673    #[cfg(feature = "unicode")]
1674    #[cfg_attr(docsrs, doc(cfg(feature = "unicode")))]
1675    #[inline]
1676    pub fn sentence_indices(&self) -> SentenceIndices {
1677        self.as_bytes().sentence_indices()
1678    }
1679
1680    /// Creates an iterator over the sentences in this string.
1681    ///
1682    /// Typically, a sentence will include its trailing punctuation and
1683    /// whitespace. Concatenating all elements yielded by the iterator
1684    /// results in the original string (modulo Unicode replacement codepoint
1685    /// substitutions if invalid UTF-8 is encountered).
1686    ///
1687    /// Since sentences are made up of one or more codepoints, this iterator
1688    /// yields `&str` elements. When invalid UTF-8 is encountered, replacement
1689    /// codepoints are substituted.
1690    ///
1691    /// # Examples
1692    ///
1693    /// Basic usage:
1694    ///
1695    /// ```
1696    /// use janetrs::JanetString;
1697    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1698    ///
1699    /// let s = JanetString::new(&b"I want this. Not that. Right now."[..]);
1700    /// let sentences: Vec<&str> = s.sentences().collect();
1701    /// assert_eq!(
1702    ///     sentences,
1703    ///     vec!["I want this. ", "Not that. ", "Right now.",]
1704    /// );
1705    /// ```
1706    #[cfg(feature = "unicode")]
1707    #[cfg_attr(docsrs, doc(cfg(feature = "unicode")))]
1708    #[inline]
1709    pub fn sentences(&self) -> Sentences {
1710        self.as_bytes().sentences()
1711    }
1712
1713    /// Creates an iterator over substrings of this string, separated
1714    /// by the given string. Each element yielded is guaranteed not to
1715    /// include the splitter substring.
1716    ///
1717    /// The splitter may be any type that can be cheaply converted into a
1718    /// `&[u8]`. This includes, but is not limited to, `&str` and `&[u8]`.
1719    ///
1720    /// # Examples
1721    ///
1722    /// Basic usage:
1723    ///
1724    /// ```
1725    /// use janetrs::JanetString;
1726    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1727    ///
1728    /// let s = JanetString::from("Mary had a little lamb");
1729    /// let x: Vec<&[u8]> = s.split(" ").collect();
1730    /// assert_eq!(x, vec![
1731    ///     &b"Mary"[..],
1732    ///     &b"had"[..],
1733    ///     &b"a"[..],
1734    ///     &b"little"[..],
1735    ///     &b"lamb"[..],
1736    /// ]);
1737    ///
1738    /// let s = JanetString::from("");
1739    /// let x: Vec<&[u8]> = s.split("X").collect();
1740    /// assert_eq!(x, vec![&b""[..]]);
1741    ///
1742    /// let s = JanetString::from("lionXXtigerXleopard");
1743    /// let x: Vec<&[u8]> = s.split("X").collect();
1744    /// assert_eq!(x, vec![
1745    ///     &b"lion"[..],
1746    ///     &b""[..],
1747    ///     &b"tiger"[..],
1748    ///     &b"leopard"[..]
1749    /// ]);
1750    ///
1751    /// let s = JanetString::from("lion::tiger::leopard");
1752    /// let x: Vec<&[u8]> = s.split("::").collect();
1753    /// assert_eq!(x, vec![&b"lion"[..], &b"tiger"[..], &b"leopard"[..]]);
1754    /// ```
1755    ///
1756    /// If a string contains multiple contiguous separators, you will end up
1757    /// with empty strings yielded by the iterator:
1758    ///
1759    /// ```
1760    /// use janetrs::JanetString;
1761    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1762    ///
1763    /// let s = JanetString::from("||||a||b|c");
1764    /// let x: Vec<&[u8]> = s.split("|").collect();
1765    /// assert_eq!(x, vec![
1766    ///     &b""[..],
1767    ///     &b""[..],
1768    ///     &b""[..],
1769    ///     &b""[..],
1770    ///     &b"a"[..],
1771    ///     &b""[..],
1772    ///     &b"b"[..],
1773    ///     &b"c"[..],
1774    /// ]);
1775    ///
1776    /// let s = JanetString::from("(///)");
1777    /// let x: Vec<&[u8]> = s.split("/").collect();
1778    /// assert_eq!(x, vec![&b"("[..], &b""[..], &b""[..], &b")"[..]]);
1779    /// ```
1780    ///
1781    /// Separators at the start or end of a string are neighbored by empty
1782    /// strings.
1783    ///
1784    /// ```
1785    /// use janetrs::JanetString;
1786    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1787    ///
1788    /// let s = JanetString::from("010");
1789    /// let x: Vec<&[u8]> = s.split("0").collect();
1790    /// assert_eq!(x, vec![&b""[..], &b"1"[..], &b""[..]]);
1791    /// ```
1792    ///
1793    /// When the empty string is used as a separator, it splits every **byte**
1794    /// in the string, along with the beginning and end of the string.
1795    ///
1796    /// ```
1797    /// use janetrs::JanetString;
1798    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1799    ///
1800    /// let s = JanetString::from("rust");
1801    /// let x: Vec<&[u8]> = s.split("").collect();
1802    /// assert_eq!(x, vec![
1803    ///     &b""[..],
1804    ///     &b"r"[..],
1805    ///     &b"u"[..],
1806    ///     &b"s"[..],
1807    ///     &b"t"[..],
1808    ///     &b""[..]
1809    /// ]);
1810    ///
1811    /// // Splitting by an empty string is not UTF-8 aware. Elements yielded
1812    /// // may not be valid UTF-8!
1813    /// let s = JanetString::from("☃");
1814    /// let x: Vec<&[u8]> = s.split("").collect();
1815    /// assert_eq!(x, vec![
1816    ///     &b""[..],
1817    ///     &b"\xE2"[..],
1818    ///     &b"\x98"[..],
1819    ///     &b"\x83"[..],
1820    ///     &b""[..]
1821    /// ]);
1822    /// ```
1823    ///
1824    /// Contiguous separators, especially whitespace, can lead to possibly
1825    /// surprising behavior. For example, this code is correct:
1826    ///
1827    /// ```
1828    /// use janetrs::JanetString;
1829    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1830    ///
1831    /// let s = JanetString::from("    a  b c");
1832    /// let x: Vec<&[u8]> = s.split(" ").collect();
1833    /// assert_eq!(x, vec![
1834    ///     &b""[..],
1835    ///     &b""[..],
1836    ///     &b""[..],
1837    ///     &b""[..],
1838    ///     &b"a"[..],
1839    ///     &b""[..],
1840    ///     &b"b"[..],
1841    ///     &b"c"[..]
1842    /// ]);
1843    /// ```
1844    ///
1845    /// It does *not* give you `["a", "b", "c"]`. For that behavior, use
1846    /// [`fields`](#method.fields) instead.
1847    #[inline]
1848    pub fn split<'a, 'b, S>(&'a self, splitter: &'b S) -> Split<'a, 'b>
1849    where
1850        S: ?Sized + AsRef<[u8]>,
1851    {
1852        self.as_bytes().split_str(splitter)
1853    }
1854
1855    /// Creates an iterator over substrings of this string, separated
1856    /// by the given string. Each element yielded is guaranteed not to
1857    /// include the splitter substring.
1858    ///
1859    /// The splitter may be any type that can be cheaply converted into a
1860    /// `&[u8]`. This includes, but is not limited to, `&str` and `&[u8]`.
1861    ///
1862    /// # Examples
1863    ///
1864    /// Basic usage:
1865    ///
1866    /// ```
1867    /// use janetrs::JanetString;
1868    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1869    ///
1870    /// let s = JanetString::from("Mary had a little lamb");
1871    /// let x: Vec<&[u8]> = s.rsplit(" ").collect();
1872    /// assert_eq!(x, vec![
1873    ///     &b"lamb"[..],
1874    ///     &b"little"[..],
1875    ///     &b"a"[..],
1876    ///     &b"had"[..],
1877    ///     &b"Mary"[..],
1878    /// ]);
1879    ///
1880    /// let s = JanetString::from("");
1881    /// let x: Vec<&[u8]> = s.rsplit("X").collect();
1882    /// assert_eq!(x, vec![&b""[..]]);
1883    ///
1884    /// let s = JanetString::from("lionXXtigerXleopard");
1885    /// let x: Vec<&[u8]> = s.rsplit("X").collect();
1886    /// assert_eq!(x, vec![
1887    ///     &b"leopard"[..],
1888    ///     &b"tiger"[..],
1889    ///     &b""[..],
1890    ///     &b"lion"[..],
1891    /// ]);
1892    /// let s = JanetString::from("lion::tiger::leopard");
1893    /// let x: Vec<&[u8]> = s.rsplit("::").collect();
1894    /// assert_eq!(x, vec![&b"leopard"[..], &b"tiger"[..], &b"lion"[..]]);
1895    /// ```
1896    ///
1897    /// If a string contains multiple contiguous separators, you will end up
1898    /// with empty strings yielded by the iterator:
1899    ///
1900    /// ```
1901    /// use janetrs::JanetString;
1902    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1903    ///
1904    /// let s = JanetString::from("||||a||b|c");
1905    /// let x: Vec<&[u8]> = s.rsplit("|").collect();
1906    /// assert_eq!(x, vec![
1907    ///     &b"c"[..],
1908    ///     &b"b"[..],
1909    ///     &b""[..],
1910    ///     &b"a"[..],
1911    ///     &b""[..],
1912    ///     &b""[..],
1913    ///     &b""[..],
1914    ///     &b""[..],
1915    /// ]);
1916    ///
1917    /// let s = JanetString::from("(///)");
1918    /// let x: Vec<&[u8]> = s.rsplit("/").collect();
1919    /// assert_eq!(x, vec![&b")"[..], &b""[..], &b""[..], &b"("[..]]);
1920    /// ```
1921    ///
1922    /// Separators at the start or end of a string are neighbored by empty
1923    /// strings.
1924    ///
1925    /// ```
1926    /// use janetrs::JanetString;
1927    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1928    ///
1929    /// let s = JanetString::from("010");
1930    /// let x: Vec<&[u8]> = s.rsplit("0").collect();
1931    /// assert_eq!(x, vec![&b""[..], &b"1"[..], &b""[..]]);
1932    /// ```
1933    ///
1934    /// When the empty string is used as a separator, it splits every **byte**
1935    /// in the string, along with the beginning and end of the string.
1936    ///
1937    /// ```
1938    /// use janetrs::JanetString;
1939    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1940    ///
1941    /// let s = JanetString::from("rust");
1942    /// let x: Vec<&[u8]> = s.rsplit("").collect();
1943    /// assert_eq!(x, vec![
1944    ///     &b""[..],
1945    ///     &b"t"[..],
1946    ///     &b"s"[..],
1947    ///     &b"u"[..],
1948    ///     &b"r"[..],
1949    ///     &b""[..]
1950    /// ]);
1951    ///
1952    /// // Splitting by an empty string is not UTF-8 aware. Elements yielded
1953    /// // may not be valid UTF-8!
1954    /// let s = JanetString::from("☃");
1955    /// let x: Vec<&[u8]> = s.rsplit("").collect();
1956    /// assert_eq!(x, vec![
1957    ///     &b""[..],
1958    ///     &b"\x83"[..],
1959    ///     &b"\x98"[..],
1960    ///     &b"\xE2"[..],
1961    ///     &b""[..]
1962    /// ]);
1963    /// ```
1964    ///
1965    /// Contiguous separators, especially whitespace, can lead to possibly
1966    /// surprising behavior. For example, this code is correct:
1967    ///
1968    /// ```
1969    /// use janetrs::JanetString;
1970    /// # let _client = janetrs::client::JanetClient::init().unwrap();
1971    ///
1972    /// let s = JanetString::from("    a  b c");
1973    /// let x: Vec<&[u8]> = s.rsplit(" ").collect();
1974    /// assert_eq!(x, vec![
1975    ///     &b"c"[..],
1976    ///     &b"b"[..],
1977    ///     &b""[..],
1978    ///     &b"a"[..],
1979    ///     &b""[..],
1980    ///     &b""[..],
1981    ///     &b""[..],
1982    ///     &b""[..],
1983    /// ]);
1984    /// ```
1985    ///
1986    /// It does *not* give you `["a", "b", "c"]`.
1987    #[inline]
1988    pub fn rsplit<'a, 'b, S>(&'a self, splitter: &'b S) -> SplitReverse<'a, 'b>
1989    where
1990        S: ?Sized + AsRef<[u8]>,
1991    {
1992        self.as_bytes().rsplit_str(splitter)
1993    }
1994
1995    /// Creates an iterator of at most `limit` substrings of this string,
1996    /// separated by the given string. If `limit` substrings are yielded,
1997    /// then the last substring will contain the remainder of this string.
1998    ///
1999    /// The needle may be any type that can be cheaply converted into a
2000    /// `&[u8]`. This includes, but is not limited to, `&str` and `&[u8]`.
2001    ///
2002    /// # Examples
2003    ///
2004    /// Basic usage:
2005    ///
2006    /// ```
2007    /// use janetrs::JanetString;
2008    /// # let _client = janetrs::client::JanetClient::init().unwrap();
2009    ///
2010    /// let s = JanetString::from("Mary had a little lamb");
2011    /// let x: Vec<_> = s.splitn(3, " ").collect();
2012    /// assert_eq!(x, vec![&b"Mary"[..], &b"had"[..], &b"a little lamb"[..]]);
2013    ///
2014    /// let s = JanetString::from("");
2015    /// let x: Vec<_> = s.splitn(3, "X").collect();
2016    /// assert_eq!(x, vec![b""]);
2017    ///
2018    /// let s = JanetString::from("lionXXtigerXleopard");
2019    /// let x: Vec<_> = s.splitn(3, "X").collect();
2020    /// assert_eq!(x, vec![&b"lion"[..], &b""[..], &b"tigerXleopard"[..]]);
2021    ///
2022    /// let s = JanetString::from("lion::tiger::leopard");
2023    /// let x: Vec<_> = s.splitn(2, "::").collect();
2024    /// assert_eq!(x, vec![&b"lion"[..], &b"tiger::leopard"[..]]);
2025    ///
2026    /// let s = JanetString::from("abcXdef");
2027    /// let x: Vec<_> = s.splitn(1, "X").collect();
2028    /// assert_eq!(x, vec![&b"abcXdef"[..]]);
2029    ///
2030    /// let s = JanetString::from("abcdef");
2031    /// let x: Vec<_> = s.splitn(2, "X").collect();
2032    /// assert_eq!(x, vec![&b"abcdef"[..]]);
2033    ///
2034    /// let s = JanetString::from("abcXdef");
2035    /// let x: Vec<_> = s.splitn(0, "X").collect();
2036    /// assert!(x.is_empty());
2037    /// ```
2038    #[inline]
2039    pub fn splitn<'a, 'b, S>(&'a self, limit: usize, splitter: &'b S) -> SplitN<'a, 'b>
2040    where
2041        S: ?Sized + AsRef<[u8]>,
2042    {
2043        self.as_bytes().splitn_str(limit, splitter)
2044    }
2045
2046    /// Creates an iterator of at most `limit` substrings of this string,
2047    /// separated by the given string. If `limit` substrings are yielded,
2048    /// then the last substring will contain the remainder of this string.
2049    ///
2050    /// The needle may be any type that can be cheaply converted into a
2051    /// `&[u8]`. This includes, but is not limited to, `&str` and `&[u8]`.
2052    ///
2053    /// # Examples
2054    ///
2055    /// Basic usage:
2056    ///
2057    /// ```
2058    /// use janetrs::JanetString;
2059    /// # let _client = janetrs::client::JanetClient::init().unwrap();
2060    ///
2061    /// let s = JanetString::from("Mary had a little lamb");
2062    /// let x: Vec<_> = s.rsplitn(3, " ").collect();
2063    /// assert_eq!(x, vec![&b"lamb"[..], &b"little"[..], &b"Mary had a"[..]]);
2064    ///
2065    /// let s = JanetString::from("");
2066    /// let x: Vec<_> = s.rsplitn(3, "X").collect();
2067    /// assert_eq!(x, vec![b""]);
2068    ///
2069    /// let s = JanetString::from("lionXXtigerXleopard");
2070    /// let x: Vec<_> = s.rsplitn(3, "X").collect();
2071    /// assert_eq!(x, vec![&b"leopard"[..], &b"tiger"[..], &b"lionX"[..]]);
2072    ///
2073    /// let s = JanetString::from("lion::tiger::leopard");
2074    /// let x: Vec<_> = s.rsplitn(2, "::").collect();
2075    /// assert_eq!(x, vec![&b"leopard"[..], &b"lion::tiger"[..]]);
2076    ///
2077    /// let s = JanetString::from("abcXdef");
2078    /// let x: Vec<_> = s.rsplitn(1, "X").collect();
2079    /// assert_eq!(x, vec![&b"abcXdef"[..]]);
2080    ///
2081    /// let s = JanetString::from("abcdef");
2082    /// let x: Vec<_> = s.rsplitn(2, "X").collect();
2083    /// assert_eq!(x, vec![&b"abcdef"[..]]);
2084    ///
2085    /// let s = JanetString::from("abcXdef");
2086    /// let x: Vec<_> = s.rsplitn(0, "X").collect();
2087    /// assert!(x.is_empty());
2088    /// ```
2089    #[inline]
2090    pub fn rsplitn<'a, 'b, S>(&'a self, limit: usize, splitter: &'b S) -> SplitNReverse<'a, 'b>
2091    where
2092        S: ?Sized + AsRef<[u8]>,
2093    {
2094        self.as_bytes().rsplitn_str(limit, splitter)
2095    }
2096
2097    /// Creates an iterator over chunks of valid UTF-8.
2098    ///
2099    /// The iterator returned yields chunks of valid UTF-8 separated by invalid
2100    /// UTF-8 bytes, if they exist. Invalid UTF-8 bytes are always 1-3 bytes,
2101    /// which are determined via the "substitution of maximal subparts"
2102    /// strategy described in the docs for the
2103    /// [`to_str_lossy`] method.
2104    ///
2105    /// # Examples
2106    ///
2107    /// ```
2108    /// use janetrs::JanetString;
2109    /// # let _client = janetrs::client::JanetClient::init().unwrap();
2110    ///
2111    /// let s = JanetString::new(&b"foo\xFD\xFEbar\xFF"[..]);
2112    ///
2113    /// let (mut valid_chunks, mut invalid_chunks) = (vec![], vec![]);
2114    /// for chunk in s.utf8_chunks() {
2115    ///     if !chunk.valid().is_empty() {
2116    ///         valid_chunks.push(chunk.valid());
2117    ///     }
2118    ///     if !chunk.invalid().is_empty() {
2119    ///         invalid_chunks.push(chunk.invalid());
2120    ///     }
2121    /// }
2122    ///
2123    /// assert_eq!(valid_chunks, vec!["foo", "bar"]);
2124    /// assert_eq!(invalid_chunks, vec![b"\xFD", b"\xFE", b"\xFF"]);
2125    /// ```
2126    ///
2127    /// [`to_str_lossy`]: #method.to_str_lossy
2128    #[inline]
2129    pub fn utf8_chunks(&self) -> Utf8Chunks {
2130        ByteSlice::utf8_chunks(self.as_bytes())
2131    }
2132
2133    /// Creates an iterator over the words in this string along with
2134    /// their starting and ending byte index positions.
2135    ///
2136    /// This is similar to [`words_with_break_indices`], except it only returns elements
2137    /// that contain a "word" character. A word character is defined by UTS #18 (Annex
2138    /// C) to be the combination of the `Alphabetic` and `Join_Control` properties,
2139    /// along with the `Decimal_Number`, `Mark` and `Connector_Punctuation` general
2140    /// categories.
2141    ///
2142    /// Since words are made up of one or more codepoints, this iterator
2143    /// yields `&str` elements. When invalid UTF-8 is encountered, replacement
2144    /// codepoints are substituted.
2145    ///
2146    /// # Examples
2147    ///
2148    /// This example shows how to get the byte offsets of each individual
2149    /// word:
2150    ///
2151    /// ```
2152    /// use janetrs::JanetString;
2153    /// # let _client = janetrs::client::JanetClient::init().unwrap();
2154    ///
2155    /// let s = JanetString::new(&b"can't jump 32.3 feet"[..]);
2156    /// let words: Vec<(usize, usize, &str)> = s.word_indices().collect();
2157    /// assert_eq!(words, vec![
2158    ///     (0, 5, "can't"),
2159    ///     (6, 10, "jump"),
2160    ///     (11, 15, "32.3"),
2161    ///     (16, 20, "feet"),
2162    /// ]);
2163    /// ```
2164    ///
2165    /// [`words_with_break_indices`]: #method.words_with_break_indices
2166    #[cfg(feature = "unicode")]
2167    #[cfg_attr(docsrs, doc(cfg(feature = "unicode")))]
2168    #[inline]
2169    pub fn word_indices(&self) -> WordIndices {
2170        self.as_bytes().word_indices()
2171    }
2172
2173    /// Creates an iterator over the words in this string. If invalid
2174    /// UTF-8 is encountered, then the Unicode replacement codepoint is yielded
2175    /// instead.
2176    ///
2177    /// This is similar to [`words_with_breaks`], except it only returns elements that
2178    /// contain a "word" character. A word character is defined by UTS #18 (Annex C)
2179    /// to be the combination of the `Alphabetic` and `Join_Control` properties, along
2180    /// with the `Decimal_Number`, `Mark` and `Connector_Punctuation` general
2181    /// categories.
2182    ///
2183    /// Since words are made up of one or more codepoints, this iterator
2184    /// yields `&str` elements. When invalid UTF-8 is encountered, replacement
2185    /// codepoints are substituted.
2186    ///
2187    /// # Examples
2188    ///
2189    /// Basic usage:
2190    ///
2191    /// ```
2192    /// use janetrs::JanetString;
2193    /// # let _client = janetrs::client::JanetClient::init().unwrap();
2194    ///
2195    /// let s = JanetString::new(&br#"The quick ("brown") fox can't jump 32.3 feet, right?"#[..]);
2196    /// let words: Vec<&str> = s.words().collect();
2197    /// assert_eq!(words, vec![
2198    ///     "The", "quick", "brown", "fox", "can't", "jump", "32.3", "feet", "right",
2199    /// ]);
2200    /// ```
2201    /// [`words_with_breaks`]: #method.words_with_breaks
2202    #[cfg(feature = "unicode")]
2203    #[cfg_attr(docsrs, doc(cfg(feature = "unicode")))]
2204    #[inline]
2205    pub fn words(&self) -> Words {
2206        self.as_bytes().words()
2207    }
2208
2209    /// Creates an iterator over the words and their byte offsets in this
2210    /// string, along with all breaks between the words. Concatenating
2211    /// all elements yielded by the iterator results in the original string
2212    /// (modulo Unicode replacement codepoint substitutions if invalid UTF-8 is
2213    /// encountered).
2214    ///
2215    /// Since words are made up of one or more codepoints, this iterator
2216    /// yields `&str` elements. When invalid UTF-8 is encountered, replacement
2217    /// codepoints are substituted.
2218    ///
2219    /// # Examples
2220    ///
2221    /// This example shows how to get the byte offsets of each individual
2222    /// word:
2223    ///
2224    /// ```
2225    /// use janetrs::JanetString;
2226    /// # let _client = janetrs::client::JanetClient::init().unwrap();
2227    ///
2228    /// let s = JanetString::new(&b"can't jump 32.3 feet"[..]);
2229    /// let words: Vec<(usize, usize, &str)> = s.words_with_break_indices().collect();
2230    /// assert_eq!(words, vec![
2231    ///     (0, 5, "can't"),
2232    ///     (5, 6, " "),
2233    ///     (6, 10, "jump"),
2234    ///     (10, 11, " "),
2235    ///     (11, 15, "32.3"),
2236    ///     (15, 16, " "),
2237    ///     (16, 20, "feet"),
2238    /// ]);
2239    /// ```
2240    #[cfg(feature = "unicode")]
2241    #[cfg_attr(docsrs, doc(cfg(feature = "unicode")))]
2242    #[inline]
2243    pub fn words_with_break_indices(&self) -> WordsWithBreakIndices {
2244        self.as_bytes().words_with_break_indices()
2245    }
2246
2247    /// Creates an iterator over the words in this string, along with
2248    /// all breaks between the words. Concatenating all elements yielded by
2249    /// the iterator results in the original string (modulo Unicode replacement
2250    /// codepoint substitutions if invalid UTF-8 is encountered).
2251    ///
2252    /// Since words are made up of one or more codepoints, this iterator
2253    /// yields `&str` elements. When invalid UTF-8 is encountered, replacement
2254    /// codepoints are substituted.
2255    ///
2256    /// # Examples
2257    ///
2258    /// Basic usage:
2259    ///
2260    /// ```
2261    /// use janetrs::JanetString;
2262    /// # let _client = janetrs::client::JanetClient::init().unwrap();
2263    ///
2264    /// let s = JanetString::new(&br#"The quick ("brown") fox can't jump 32.3 feet, right?"#[..]);
2265    /// let words: Vec<&str> = s.words_with_breaks().collect();
2266    /// assert_eq!(words, vec![
2267    ///     "The", " ", "quick", " ", "(", "\"", "brown", "\"", ")", " ", "fox", " ", "can't", " ",
2268    ///     "jump", " ", "32.3", " ", "feet", ",", " ", "right", "?",
2269    /// ]);
2270    /// ```
2271    #[cfg(feature = "unicode")]
2272    #[cfg_attr(docsrs, doc(cfg(feature = "unicode")))]
2273    #[inline]
2274    pub fn words_with_breaks(&self) -> WordsWithBreaks {
2275        self.as_bytes().words_with_breaks()
2276    }
2277
2278    /// Return a raw pointer to the string raw structure.
2279    ///
2280    /// The caller must ensure that the buffer outlives the pointer this function returns,
2281    /// or else it will end up pointing to garbage.
2282    #[inline]
2283    pub const fn as_raw(&self) -> *const u8 {
2284        self.raw
2285    }
2286
2287    /// Converts a string to a raw pointer.
2288    ///
2289    /// The caller must ensure that the buffer outlives the pointer this function returns,
2290    /// or else it will end up pointing to garbage.
2291    #[inline]
2292    pub const fn as_ptr(&self) -> *const u8 {
2293        self.raw
2294    }
2295}
2296
2297impl Debug for JanetString<'_> {
2298    #[inline]
2299    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2300        let bstr: &BStr = self.as_bytes().as_ref();
2301
2302        Debug::fmt(bstr, f)
2303    }
2304}
2305
2306impl Display for JanetString<'_> {
2307    #[inline]
2308    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2309        let bstr: &BStr = self.as_bytes().as_ref();
2310
2311        Display::fmt(bstr, f)
2312    }
2313}
2314
2315impl Clone for JanetString<'_> {
2316    #[inline]
2317    fn clone(&self) -> Self {
2318        Self {
2319            raw:     unsafe { evil_janet::janet_string(self.raw, self.len() as i32) },
2320            phantom: PhantomData,
2321        }
2322    }
2323}
2324
2325impl Default for JanetString<'_> {
2326    #[inline]
2327    fn default() -> Self {
2328        Self::from("")
2329    }
2330}
2331
2332impl DeepEq<JanetBuffer<'_>> for JanetString<'_> {
2333    #[inline]
2334    fn deep_eq(&self, other: &JanetBuffer<'_>) -> bool {
2335        other.deep_eq(self)
2336    }
2337}
2338
2339impl From<char> for JanetString<'_> {
2340    #[inline]
2341    fn from(ch: char) -> Self {
2342        let mut buff = [0; 4];
2343        let s = ch.encode_utf8(&mut buff);
2344        Self::new(s)
2345    }
2346}
2347
2348impl From<&char> for JanetString<'_> {
2349    #[inline]
2350    fn from(ch: &char) -> Self {
2351        let mut buff = [0; 4];
2352        let s = ch.encode_utf8(&mut buff);
2353        Self::new(s)
2354    }
2355}
2356
2357impl From<JanetBuffer<'_>> for JanetString<'_> {
2358    #[inline]
2359    fn from(buff: JanetBuffer<'_>) -> Self {
2360        From::<&JanetBuffer<'_>>::from(&buff)
2361    }
2362}
2363
2364impl From<&JanetBuffer<'_>> for JanetString<'_> {
2365    #[inline]
2366    fn from(buff: &JanetBuffer<'_>) -> Self {
2367        let slice = buff.as_bytes();
2368        JanetString::new(slice)
2369    }
2370}
2371
2372impl From<super::JanetSymbol<'_>> for JanetString<'_> {
2373    #[inline]
2374    fn from(sym: super::JanetSymbol<'_>) -> Self {
2375        JanetString::new(sym)
2376    }
2377}
2378
2379impl From<&super::JanetSymbol<'_>> for JanetString<'_> {
2380    #[inline]
2381    fn from(sym: &super::JanetSymbol<'_>) -> Self {
2382        JanetString::new(sym)
2383    }
2384}
2385
2386impl From<super::JanetKeyword<'_>> for JanetString<'_> {
2387    #[inline]
2388    fn from(key: super::JanetKeyword<'_>) -> Self {
2389        JanetString::new(key)
2390    }
2391}
2392
2393impl From<&super::JanetKeyword<'_>> for JanetString<'_> {
2394    #[inline]
2395    fn from(key: &super::JanetKeyword<'_>) -> Self {
2396        JanetString::new(key)
2397    }
2398}
2399
2400impl AsRef<[u8]> for JanetString<'_> {
2401    #[inline]
2402    fn as_ref(&self) -> &[u8] {
2403        self.as_bytes()
2404    }
2405}
2406
2407impl AsRef<BStr> for JanetString<'_> {
2408    #[inline]
2409    fn as_ref(&self) -> &BStr {
2410        self.as_bytes().as_ref()
2411    }
2412}
2413
2414impl FromStr for JanetString<'_> {
2415    type Err = Infallible;
2416
2417    #[inline]
2418    fn from_str(s: &str) -> Result<Self, Self::Err> {
2419        Ok(Self::from(s))
2420    }
2421}
2422
2423impl Index<usize> for JanetString<'_> {
2424    type Output = u8;
2425
2426    /// Get a reference to the byte of the string at the `index`.
2427    ///
2428    /// It is more idiomatic to use [`bytes`] method.
2429    ///
2430    /// # Janet Panics
2431    /// Panics if the index is out of bounds.
2432    ///
2433    /// [`bytes`]: #method.bytes.html
2434    #[inline]
2435    fn index(&self, index: usize) -> &Self::Output {
2436        self.as_bytes().get(index).unwrap_or_else(|| {
2437            crate::jpanic!(
2438                "index out of bounds: the len is {} but the index is {}",
2439                self.len(),
2440                index
2441            )
2442        })
2443    }
2444}
2445
2446impl FromIterator<char> for JanetString<'_> {
2447    #[cfg_attr(feature = "inline-more", inline)]
2448    fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
2449        let iter = iter.into_iter();
2450        let (len, _) = iter.size_hint();
2451
2452        let mut s = Self::builder(len);
2453
2454        for ch in iter {
2455            s = s.put_char(ch);
2456        }
2457
2458        s.finalize()
2459    }
2460}
2461
2462impl<'a> FromIterator<&'a u8> for JanetString<'_> {
2463    #[cfg_attr(feature = "inline-more", inline)]
2464    fn from_iter<T: IntoIterator<Item = &'a u8>>(iter: T) -> Self {
2465        let iter = iter.into_iter();
2466        let (len, _) = iter.size_hint();
2467
2468        let mut new = Self::builder(len);
2469
2470        for &byte in iter {
2471            new = new.put([byte]);
2472        }
2473
2474        new.finalize()
2475    }
2476}
2477
2478impl<'a> FromIterator<&'a char> for JanetString<'_> {
2479    #[cfg_attr(feature = "inline-more", inline)]
2480    fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> Self {
2481        let iter = iter.into_iter();
2482        let (len, _) = iter.size_hint();
2483
2484        let mut new = Self::builder(len);
2485
2486        for &ch in iter {
2487            new = new.put_char(ch);
2488        }
2489
2490        new.finalize()
2491    }
2492}
2493
2494impl<'a> FromIterator<&'a str> for JanetString<'_> {
2495    #[cfg_attr(feature = "inline-more", inline)]
2496    fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
2497        let iter = iter.into_iter();
2498        let (len, _) = iter.size_hint();
2499
2500        let mut new = Self::builder(len);
2501
2502        for s in iter {
2503            new = new.put(s);
2504        }
2505
2506        new.finalize()
2507    }
2508}
2509
2510impl FromIterator<String> for JanetString<'_> {
2511    #[cfg_attr(feature = "inline-more", inline)]
2512    fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
2513        let iter = iter.into_iter();
2514        let (len, _) = iter.size_hint();
2515
2516        let mut new = Self::builder(len);
2517
2518        for s in iter {
2519            new = new.put(&s);
2520        }
2521
2522        new.finalize()
2523    }
2524}
2525
2526#[cfg(all(test, any(feature = "amalgation", feature = "link-system")))]
2527mod tests {
2528    use super::*;
2529    use crate::client::JanetClient;
2530
2531    #[test]
2532    fn creation_new() -> Result<(), crate::client::Error> {
2533        let _client = JanetClient::init()?;
2534
2535        let string = JanetString::new("");
2536        assert!(string.is_empty());
2537
2538        let string = JanetString::new("buffer");
2539        assert_eq!(6, string.len());
2540        Ok(())
2541    }
2542
2543    #[test]
2544    fn creation_builder() -> Result<(), crate::client::Error> {
2545        let _client = JanetClient::init()?;
2546
2547        let string = JanetString::builder(0).finalize();
2548        assert!(string.is_empty());
2549
2550        let string = JanetString::builder(6).put("buffer").finalize();
2551        assert_eq!(6, string.len());
2552
2553        let string = JanetString::builder(8).put("data").put("data").finalize();
2554        assert_eq!(8, string.len());
2555
2556        let string = JanetString::builder(10).finalize();
2557        assert_eq!(10, string.len());
2558        Ok(())
2559    }
2560
2561    #[test]
2562    fn builder_no_panic() -> Result<(), crate::client::Error> {
2563        let _client = JanetClient::init()?;
2564
2565        let string = JanetString::builder(6).put("buffersssss").finalize();
2566
2567        assert_eq!(6, string.len());
2568        assert_eq!(JanetString::new("buffer"), string);
2569
2570        let string = JanetString::builder(6)
2571            .put("buffe")
2572            .put("a")
2573            .put("b")
2574            .finalize();
2575
2576        assert_eq!(6, string.len());
2577        assert_eq!(JanetString::new("buffea"), string);
2578        Ok(())
2579    }
2580
2581    #[test]
2582    fn equal() -> Result<(), crate::client::Error> {
2583        let _client = JanetClient::init()?;
2584
2585        let str1 = JanetString::new("buffer");
2586        let str2 = JanetString::builder(6).put("buffer").finalize();
2587
2588        assert_eq!(str1, str2);
2589        Ok(())
2590    }
2591
2592    #[test]
2593    fn ord() -> Result<(), crate::client::Error> {
2594        let _client = JanetClient::init()?;
2595
2596        let str1 = JanetString::new("buffer");
2597        let str2 = JanetString::new("não");
2598        let str3 = JanetString::new("poket monsters");
2599
2600        assert!(str1 < str2);
2601        assert!(str1 < str3);
2602
2603        assert!(str2 < str3);
2604        assert!(str3 > str2);
2605        Ok(())
2606    }
2607
2608    #[test]
2609    fn index() -> Result<(), crate::client::Error> {
2610        let _client = JanetClient::init()?;
2611
2612        let expected = b"test";
2613        let str1 = JanetString::new("test");
2614
2615        assert_eq!(expected[0], str1[0]);
2616        assert_eq!(expected[1], str1[1]);
2617        assert_eq!(expected[2], str1[2]);
2618        assert_eq!(expected[3], str1[3]);
2619        Ok(())
2620    }
2621
2622    #[test]
2623    fn from_char() -> Result<(), crate::client::Error> {
2624        let _client = JanetClient::init()?;
2625
2626        let expected = JanetString::new("α");
2627        let test = JanetString::from('α');
2628
2629        assert_eq!(test, expected);
2630        Ok(())
2631    }
2632}