janetrs/types/
buffer.rs

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