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}