str_queue/range/chars.rs
1//! Chars range in a queue.
2
3use core::cmp::Ordering;
4use core::fmt;
5use core::num::NonZeroUsize;
6use core::ops::{Bound, RangeBounds};
7
8use crate::iter::{Chars, Fragment, Fragments};
9use crate::range::BytesRange;
10use crate::utf8::{self, REPLACEMENT_CHAR};
11use crate::StrQueue;
12// `BoundExt` trait is a workaround until Rust 1.55.0.
13// Suppress `unused_imports` for Rust 1.55.0 beta or later, for now.
14#[allow(unused_imports)]
15use crate::BoundExt;
16
17/// An internal error type indicating the character is incomplete.
18#[derive(Debug, Clone, Copy)]
19struct IncompleteCharError;
20
21/// Subrange of a `StrQueue`.
22///
23/// This can be created by [`StrQueue::chars_range`].
24///
25/// The range contains valid UTF-8 sequence with the optional
26/// last incomplete character.
27#[derive(Debug, Clone, Copy, Eq, Hash)]
28pub struct CharsRange<'a> {
29 /// The range.
30 range: BytesRange<'a>,
31}
32
33/// Setup.
34impl<'a> CharsRange<'a> {
35 /// Creates a new `CharsRange` for the queue.
36 ///
37 /// # Panics
38 ///
39 /// Panics if the start bound of the range does not lie on UTF-8 sequence boundary.
40 #[must_use]
41 pub(crate) fn new<R>(queue: &'a StrQueue, range: R) -> Self
42 where
43 R: RangeBounds<usize>,
44 {
45 let (former, latter) = queue.inner.as_slices();
46 #[allow(unstable_name_collisions)] // This is intended. See `crate::BoundExt` trait.
47 Self::from_slices_and_bounds(
48 former,
49 latter,
50 range.start_bound().cloned(),
51 range.end_bound().cloned(),
52 )
53 }
54
55 /// Creates `CharsRange` from slices and range bounds.
56 ///
57 /// # Panics
58 ///
59 /// Panics if the start bound of the range does not lie on UTF-8 sequence boundary.
60 /// Panics if `former` and `latter` overlaps.
61 /// Panics if the given index is out of range.
62 #[must_use]
63 fn from_slices_and_bounds(
64 former: &'a [u8],
65 latter: &'a [u8],
66 start: Bound<usize>,
67 end: Bound<usize>,
68 ) -> Self {
69 let range = BytesRange::from_slices_and_bounds(former, latter, start, end);
70
71 // Check if the first byte of the index is the start byte of a character.
72 if !matches!(start, Bound::Unbounded | Bound::Included(0))
73 && range.first().map(utf8::expected_char_len) == Some(0)
74 {
75 panic!(
76 "[precondition] start bound of the range {:?} \
77 does not lie on UTF-8 sequence boundary",
78 (start, end)
79 );
80 }
81
82 Self { range }
83 }
84}
85
86/// Subrange access.
87impl<'a> CharsRange<'a> {
88 /// Returns the subrange.
89 ///
90 /// The returned range can contain an incomplete character at the end.
91 /// If you want to exclude a possible trailing incomplete character in the range,
92 /// use [`CharsRange::to_complete`] or [`CharsRange::trim_last_incomplete_char`].
93 ///
94 /// # Panics
95 ///
96 /// Panics if the start bound of the range does not lie on UTF-8 sequence boundary.
97 /// Panics if the given index is out of range.
98 ///
99 /// # Examples
100 ///
101 /// ```
102 /// use str_queue::StrQueue;
103 ///
104 /// let queue = StrQueue::from(b"Hello \xce\xb1");
105 /// let range = queue.chars_range(..);
106 /// assert_eq!(range.to_string(), "Hello \u{03B1}");
107 ///
108 /// assert_eq!(range.range(3..7).to_string(), "lo \u{FFFD}");
109 /// ```
110 #[must_use]
111 pub fn range<R>(&self, range: R) -> Self
112 where
113 R: RangeBounds<usize>,
114 {
115 #[allow(unstable_name_collisions)] // This is intended. See `crate::BoundExt` trait.
116 Self::from_slices_and_bounds(
117 self.range.former,
118 self.range.latter,
119 range.start_bound().cloned(),
120 range.end_bound().cloned(),
121 )
122 }
123
124 /// Returns the range without the last incomplete character.
125 ///
126 /// If you want to modify `self` instead of getting a modified copy, use
127 /// [`CharsRange::trim_last_incomplete_char`].
128 ///
129 /// # Examples
130 ///
131 /// ```
132 /// use str_queue::{PartialHandling, StrQueue};
133 ///
134 /// let queue = StrQueue::from(b"Hello \xce");
135 /// let range = queue.chars_range(..);
136 /// assert_eq!(range.to_string(), "Hello \u{FFFD}");
137 /// assert_eq!(range.to_complete().to_string(), "Hello ");
138 /// ```
139 #[inline]
140 #[must_use]
141 pub fn to_complete(mut self) -> Self {
142 self.trim_last_incomplete_char();
143 self
144 }
145
146 /// Returns the range without the last incomplete character and the trimmed length.
147 #[inline]
148 #[must_use]
149 // TODO: Better name?
150 fn to_complete_and_trimmed_len(mut self) -> (Self, usize) {
151 let trimmed = self.trim_last_incomplete_char();
152 (self, trimmed)
153 }
154}
155
156/// Content length and existence.
157impl<'a> CharsRange<'a> {
158 /// Returns the total length.
159 ///
160 /// # Examples
161 ///
162 /// ```
163 /// use str_queue::StrQueue;
164 ///
165 /// let queue = StrQueue::from(b"Hello \xce");
166 /// let range = queue.chars_range(..);
167 /// assert_eq!(range.len(), b"Hello \xce".len());
168 /// ```
169 #[inline]
170 #[must_use]
171 pub fn len(&self) -> usize {
172 self.range.len()
173 }
174
175 /// Returns true if the range is empty.
176 ///
177 /// # Examples
178 ///
179 /// ```
180 /// use str_queue::StrQueue;
181 ///
182 /// let queue = StrQueue::from(b"\xce");
183 /// let range = queue.chars_range(..);
184 /// assert!(!range.is_empty());
185 ///
186 /// assert!(queue.chars_range(0..0).is_empty());
187 /// ```
188 #[inline]
189 #[must_use]
190 pub fn is_empty(&self) -> bool {
191 self.range.is_empty()
192 }
193
194 /// Returns the string length in bytes, excluding incomplete bytes.
195 ///
196 /// # Examples
197 ///
198 /// ```
199 /// use str_queue::StrQueue;
200 ///
201 /// let queue = StrQueue::from(b"hello\xce");
202 /// assert_eq!(queue.chars_range(..).len_complete(), 5);
203 /// ```
204 #[inline]
205 #[must_use]
206 pub fn len_complete(&self) -> usize {
207 self.len() - self.len_incomplete()
208 }
209
210 /// Returns the length of incomplete bytes.
211 ///
212 /// # Examples
213 ///
214 /// ```
215 /// use str_queue::StrQueue;
216 ///
217 /// let queue = StrQueue::from(b"hello\xce");
218 /// assert_eq!(queue.chars_range(..).len_incomplete(), 1);
219 /// ```
220 #[inline]
221 #[must_use]
222 pub fn len_incomplete(&self) -> usize {
223 let former = self.range.former;
224 let latter = self.range.latter;
225 if !latter.is_empty() {
226 if let Some(partial_len) = utf8::last_char_len_in_last_4bytes(latter) {
227 return partial_len.len_incomplete();
228 }
229 }
230
231 // No characters starts from the latter slice.
232 utf8::last_char_len_in_last_4bytes(former)
233 .expect("[validity] the former buffer must be null or start with valid UTF-8 sequence")
234 .len_incomplete()
235 }
236
237 /// Returns true if the chars range contains no complete string.
238 ///
239 /// # Examples
240 ///
241 /// ```
242 /// use str_queue::StrQueue;
243 ///
244 /// let mut queue = StrQueue::new();
245 /// assert!(queue.chars_range(..).is_empty_complete());
246 ///
247 /// queue.push_bytes(b"\xce");
248 /// assert!(queue.chars_range(..).is_empty_complete());
249 ///
250 /// queue.push_bytes(b"\xb1");
251 /// assert!(!queue.chars_range(..).is_empty_complete());
252 /// ```
253 #[inline]
254 #[must_use]
255 pub fn is_empty_complete(&self) -> bool {
256 self.len() == self.len_incomplete()
257 }
258
259 /// Returns true if the chars range is a complete string, i.e. has no
260 /// trailing incomplete character.
261 ///
262 /// # Examples
263 ///
264 /// ```
265 /// use str_queue::StrQueue;
266 ///
267 /// let mut queue = StrQueue::from(b"abc\xce");
268 /// assert!(!queue.chars_range(..).is_complete());
269 /// queue.push_bytes(b"\xb1");
270 /// // Now the string is "abc\u{03B1}".
271 /// assert!(queue.chars_range(..).is_complete());
272 /// ```
273 pub fn is_complete(&self) -> bool {
274 if self.range.latter.is_empty() {
275 // Check only the former.
276 return utf8::last_char_len_in_last_4bytes(self.range.former)
277 .map_or(false, |v| v.is_complete());
278 }
279 if let Some(partial_len) = utf8::last_char_len_in_last_4bytes(self.range.latter) {
280 // Check only the latter.
281 return partial_len.is_complete();
282 }
283
284 // The latter has no beginning of a character.
285 let latter_len = self.range.latter.len();
286 debug_assert!(
287 latter_len < 4,
288 "[consistency] a complete character must start in the last 4 bytes"
289 );
290 debug_assert!(
291 latter_len > 0,
292 "[consistency] must be returned earlily when the latter is empty"
293 );
294 let partial_len = match utf8::last_char_len_in_last_4bytes(self.range.former) {
295 Some(v) => v,
296 None => unreachable!("[consistency] a character start must exist in the last 4 bytes"),
297 };
298 match partial_len.len_missing().cmp(&latter_len) {
299 Ordering::Greater => false,
300 Ordering::Equal => true,
301 Ordering::Less => {
302 unreachable!("[consistency] a character must not be longer than expected")
303 }
304 }
305 }
306}
307
308/// Range and content manipulation.
309impl<'a> CharsRange<'a> {
310 /// Clears the range, removing all elements.
311 ///
312 /// # Examples
313 ///
314 /// ```
315 /// use str_queue::{PartialHandling, StrQueue};
316 ///
317 /// let queue = StrQueue::from(b"Hello \xce");
318 /// let mut range = queue.chars_range(..);
319 /// assert!(!range.is_empty());
320 ///
321 /// range.clear();
322 /// assert!(range.is_empty());
323 /// // Only the range is cleared. The underlying queue does not change.
324 /// assert!(!queue.is_empty());
325 /// ```
326 #[inline]
327 pub fn clear(&mut self) {
328 self.range.clear()
329 }
330
331 /// Trims the last incomplete character, and returns the length of the trimmed bytes.
332 ///
333 /// If the string is complete (i.e. no incomplete character follows), does
334 /// nothing and returns 0.
335 ///
336 /// If you want to get a modified copy instead of modifying `self` itself,
337 /// use [`CharsRange::to_complete`].
338 ///
339 /// # Examples
340 ///
341 /// ```
342 /// use str_queue::{PartialHandling, StrQueue};
343 ///
344 /// let queue = StrQueue::from(b"Hello \xce");
345 /// let mut range = queue.chars_range(..);
346 /// assert_eq!(range.to_string(), "Hello \u{FFFD}");
347 ///
348 /// range.trim_last_incomplete_char();
349 /// assert_eq!(range.to_string(), "Hello ");
350 /// ```
351 pub fn trim_last_incomplete_char(&mut self) -> usize {
352 let former = &mut self.range.former;
353 let latter = &mut self.range.latter;
354
355 if !latter.is_empty() {
356 if let Some(partial_len) = utf8::last_char_len_in_last_4bytes(latter) {
357 let len_incomplete = partial_len.len_incomplete();
358 let valid_up_to = latter.len() - len_incomplete;
359 *latter = &latter[..valid_up_to];
360 return len_incomplete;
361 }
362 }
363
364 // No characters starts from the latter slice.
365 *latter = &latter[..0];
366 // Check for the former slice.
367 let len_incomplete = utf8::last_char_len_in_last_4bytes(former)
368 .expect("[validity] the former buffer must be null or start with valid UTF-8 sequence")
369 .len_incomplete();
370 let valid_up_to = former.len() - len_incomplete;
371 *former = &former[..valid_up_to];
372
373 len_incomplete
374 }
375
376 /// Pops the first character in the range and returns it.
377 ///
378 /// Trailing incomplete character is ignored.
379 ///
380 /// # Examples
381 ///
382 /// ```
383 /// use str_queue::StrQueue;
384 ///
385 /// let queue = StrQueue::from("hello");
386 /// let mut range = queue.chars_range(..);
387 ///
388 /// assert_eq!(range.pop_char(), Some('h'));
389 /// assert_eq!(range.pop_char(), Some('e'));
390 /// assert_eq!(range.pop_char(), Some('l'));
391 /// assert_eq!(range.pop_char(), Some('l'));
392 /// assert_eq!(range.pop_char(), Some('o'));
393 /// assert_eq!(range.pop_char(), None);
394 /// assert!(range.is_empty());
395 /// ```
396 ///
397 /// ```
398 /// use str_queue::StrQueue;
399 ///
400 /// let queue = StrQueue::from(b"a\xf0");
401 /// let mut range = queue.chars_range(..);
402 ///
403 /// assert_eq!(range.pop_char(), Some('a'));
404 /// assert_eq!(range.pop_char(), None);
405 /// assert!(!range.is_empty());
406 /// ```
407 pub fn pop_char(&mut self) -> Option<char> {
408 self.pop_char_raw(false).and_then(Result::ok)
409 }
410
411 /// Pops the first character from the range and returns it.
412 ///
413 /// The trailing incomplete character is replaced with `U+FFFD REPLACEMENT
414 /// CHARACTER`, if available.
415 ///
416 /// # Examples
417 ///
418 /// ```
419 /// use str_queue::StrQueue;
420 ///
421 /// let queue = StrQueue::from(b"abc\xce");
422 /// let mut range = queue.chars_range(..);
423 ///
424 /// assert_eq!(range.pop_char_replaced(), Some('a'));
425 /// assert_eq!(range.pop_char_replaced(), Some('b'));
426 /// assert_eq!(range.pop_char_replaced(), Some('c'));
427 /// assert_eq!(range.pop_char_replaced(), Some('\u{FFFD}'));
428 /// ```
429 pub fn pop_char_replaced(&mut self) -> Option<char> {
430 self.pop_char_raw(true)
431 .map(|res| res.unwrap_or(REPLACEMENT_CHAR))
432 }
433
434 /// Pops the first character from the range and return it.
435 ///
436 /// If the first character is incomplete, `Some(Err(IncompleteCharError))`
437 /// is returned.
438 /// The trailing incomplete character is removed from the range if and only
439 /// if `pop_incomplete` is true.
440 fn pop_char_raw(&mut self, pop_incomplete: bool) -> Option<Result<char, IncompleteCharError>> {
441 if self.range.is_empty() {
442 return None;
443 }
444 match utf8::take_char(self.range.bytes()) {
445 Some((c, len)) => {
446 self.range.trim_start(usize::from(len));
447 Some(Ok(c))
448 }
449 None => {
450 debug_assert!(!self.range.is_empty());
451 // Incomplete character.
452 if pop_incomplete {
453 self.range.clear();
454 }
455 Some(Err(IncompleteCharError))
456 }
457 }
458 }
459
460 /// Pops the first line in the queue and returns it.
461 ///
462 /// Incomplete lines are ignored.
463 ///
464 /// Note that it is unspecified whether the line will be removed from the queue,
465 /// if the `PoppedLine` value is not dropped while the borrow it holds expires
466 /// (e.g. due to [`core::mem::forget`]).
467 ///
468 /// # Examples
469 ///
470 /// ```
471 /// use str_queue::StrQueue;
472 ///
473 /// // Note that the last "world\r" is not considered as a complete line
474 /// // since the line can be finally "world\r" or "world\r\n".
475 /// let queue = StrQueue::from("Hello\nworld\r\nGoodbye\rworld\r");
476 /// let mut range = queue.chars_range(..);
477 ///
478 /// assert_eq!(range.pop_line().map(|v| v.to_string()).as_deref(), Some("Hello\n"));
479 /// assert_eq!(range.pop_line().map(|v| v.to_string()).as_deref(), Some("world\r\n"));
480 /// assert_eq!(range.pop_line().map(|v| v.to_string()).as_deref(), Some("Goodbye\r"));
481 /// assert_eq!(range.pop_line().map(|v| v.to_string()).as_deref(), None);
482 /// assert_eq!(range, "world\r");
483 /// ```
484 #[inline]
485 pub fn pop_line<'r>(&'r mut self) -> Option<CharsRangePoppedLine<'a, 'r>> {
486 let line_len = self.first_line()?.len();
487 let line_len = NonZeroUsize::new(line_len)
488 .expect("[validity] a complete line must not be empty since it has a line break");
489 Some(CharsRangePoppedLine {
490 range: self,
491 line_len,
492 })
493 }
494
495 /// Pops the first [`Fragment`] from the range and return it.
496 ///
497 /// In other words, takes as much content as possible from the range.
498 ///
499 /// # Examples
500 ///
501 /// ```
502 /// use str_queue::StrQueue;
503 ///
504 /// let queue = StrQueue::from(b"Hello \xce");
505 /// let mut buf = String::new();
506 ///
507 /// let mut range = queue.chars_range(..);
508 /// while let Some(frag) = range.pop_fragment() {
509 /// buf.push_str(&frag.to_string());
510 /// }
511 ///
512 /// assert_eq!(buf, "Hello \u{FFFD}");
513 /// assert!(range.is_empty());
514 /// ```
515 pub fn pop_fragment(&mut self) -> Option<Fragment<'a>> {
516 if self.range.is_empty() {
517 return None;
518 }
519
520 {
521 let (former_valid, former_incomplete) =
522 utf8::split_incomplete_suffix(self.range.former);
523 if !former_valid.is_empty() {
524 // The former slice has valid UTF-8 sequence as a prefix.
525 self.range.trim_start(former_valid.len());
526 return Some(Fragment::Str(former_valid));
527 }
528 if former_incomplete.is_some() {
529 // The former slice starts with incomplete character.
530 let frag = self
531 .pop_char_raw(true)
532 .expect("[consistency] the incomplete bytes are not empty")
533 .map_or(Fragment::Incomplete, Fragment::Char);
534 return Some(frag);
535 }
536 }
537
538 let (latter_valid, latter_incomplete) = utf8::split_incomplete_suffix(self.range.latter);
539 if !latter_valid.is_empty() {
540 // The latter slice has valid UTF-8 sequence as a prefix since
541 // the range starts inside the latter slice.
542 self.range.trim_start(latter_valid.len());
543 return Some(Fragment::Str(latter_valid));
544 }
545 assert!(
546 latter_incomplete.is_some(),
547 "[consistency] this cannot be empty since the range is not empty here"
548 );
549 // The latter slice starts with (and ends with) the incomplete character.
550 Some(Fragment::Incomplete)
551 }
552}
553
554/// Content access.
555impl<'a> CharsRange<'a> {
556 /// Returns the first character in the range.
557 ///
558 /// # Examples
559 ///
560 /// ```
561 /// use str_queue::StrQueue;
562 ///
563 /// let queue = StrQueue::from("hello");
564 ///
565 /// assert_eq!(queue.first_char(), Some('h'));
566 /// ```
567 #[inline]
568 #[must_use]
569 pub fn first_char(&self) -> Option<char> {
570 let bytes = self
571 .range
572 .former
573 .iter()
574 .chain(self.range.latter.iter())
575 .take(4)
576 .copied();
577 utf8::take_char(bytes).map(|(c, _len)| c)
578 }
579
580 /// Returns the subrange of the first line, including the line break.
581 ///
582 /// Returns `Some(range)` if the range contains a complete line, which
583 /// won't be changed if more contents are appended.
584 /// Returns `None` if the range contains only an incomplete line,
585 /// which will be changed if more contents are appended.
586 ///
587 /// # Examples
588 ///
589 /// ```
590 /// use str_queue::StrQueue;
591 ///
592 /// let mut queue = StrQueue::from(b"Hello \xce");
593 /// assert_eq!(
594 /// queue.chars_range(..).first_line().map(|r| r.to_string()),
595 /// None
596 /// );
597 ///
598 /// queue.push_bytes(b"\xb1\r");
599 /// // The line is still considered incomplete since the line ending can be `\r\n`.
600 /// assert_eq!(
601 /// queue.chars_range(..).first_line().map(|r| r.to_string()),
602 /// None
603 /// );
604 ///
605 /// queue.push_bytes(b"\nhello");
606 /// assert_eq!(
607 /// queue.chars_range(..).first_line().map(|r| r.to_string()),
608 /// Some("Hello \u{03B1}\r\n".to_owned())
609 /// );
610 /// ```
611 ///
612 /// ```
613 /// use str_queue::{PartialHandling, StrQueue};
614 ///
615 /// let queue = StrQueue::from(b"Hello\n");
616 /// assert_eq!(
617 /// queue.chars_range(..).first_line().map(|r| r.to_string()),
618 /// Some("Hello\n".to_owned())
619 /// );
620 /// ```
621 pub fn first_line(&self) -> Option<CharsRange<'a>> {
622 self.next_line_position().map(|pos| self.range(..pos.get()))
623 }
624
625 /// Returns the position where the next line starts.
626 #[must_use]
627 fn next_line_position(&self) -> Option<NonZeroUsize> {
628 let first_newline = self.range.position2(b'\n', b'\r')?;
629 debug_assert!(
630 first_newline < usize::MAX,
631 "the string length won't be `usize::MAX` \
632 since other objects (including self) may exist on memory"
633 );
634 if self.range.former[first_newline] == b'\n' {
635 return NonZeroUsize::new(first_newline + 1);
636 }
637 assert_eq!(self.range.former[first_newline], b'\r');
638
639 // The string ending with `\r` is considered incomplete line,
640 // since it is unsure which is used as the line ending, `\r` or `\r\n`.
641 let next = self.range.get_byte(first_newline + 1)?;
642 if next == b'\n' {
643 debug_assert!(
644 first_newline + 1 < usize::MAX,
645 "the string length won't be `usize::MAX` \
646 since other objects (including self) may exist on memory"
647 );
648 NonZeroUsize::new(first_newline + 2)
649 } else {
650 NonZeroUsize::new(first_newline + 1)
651 }
652 }
653}
654
655/// Iterators.
656impl<'a> CharsRange<'a> {
657 /// Returns an iterator of `char`s.
658 ///
659 /// Incomplete characters are emitted as `U+FFFD REPLACEMENT CHARACTER`.
660 /// If you want to ignore them, use [`CharsRange::to_complete`] or
661 /// [`CharsRange::trim_last_incomplete_char`] before creating the iterator.
662 ///
663 /// # Examples
664 ///
665 /// ```
666 /// use str_queue::{PartialHandling, StrQueue};
667 ///
668 /// let queue = StrQueue::from(b"alpha->\xce");
669 /// let range = queue.chars_range(..);
670 ///
671 /// // The trailing incomplete character is replaced with U+FFFD.
672 /// assert_eq!(
673 /// range.chars().collect::<String>(),
674 /// "alpha->\u{FFFD}"
675 /// );
676 /// ```
677 #[inline]
678 #[must_use]
679 pub fn chars(&self) -> Chars<'_> {
680 Chars::from_range(*self)
681 }
682
683 /// Returns an iterator of content fragments.
684 ///
685 /// # Examples
686 ///
687 /// The code below are redundant since they are intended to show how to use [`Fragment`].
688 /// To simply create a string from the queue, use [`StrQueue::display`] method.
689 ///
690 /// ```
691 /// use str_queue::{Fragment, StrQueue};
692 ///
693 /// // `\xce\xb1` is `\u{03B1}`.
694 /// let queue = StrQueue::from(b"hello \xce\xb1");
695 /// let range = queue.chars_range(3..7);
696 ///
697 /// let mut buf = String::new();
698 /// for frag in range.fragments() {
699 /// match frag {
700 /// Fragment::Str(s) => buf.push_str(s),
701 /// Fragment::Char(c) => buf.push(c),
702 /// Fragment::Incomplete => buf.push_str("<<incomplete>>"),
703 /// }
704 /// }
705 /// assert_eq!(buf, "lo <<incomplete>>");
706 /// ```
707 #[inline]
708 #[must_use]
709 pub fn fragments(&self) -> Fragments<'_> {
710 Fragments::from_range(*self)
711 }
712}
713
714/// Conversion.
715impl<'a> CharsRange<'a> {
716 /// Returns the bytes range.
717 #[inline]
718 #[must_use]
719 pub fn to_bytes_range(&self) -> BytesRange<'a> {
720 (*self).into()
721 }
722}
723
724/// Comparison.
725impl CharsRange<'_> {
726 /// Compares the two chars ranges.
727 ///
728 /// This comparson is arawe of the existence of the last incomplete
729 /// characters, but does not aware of its value.
730 /// If you care about the value of the incomplete characters, you should use
731 /// bytes comparison.
732 ///
733 /// If the range has the incomplete character, it is treated as a character
734 /// which is smaller than any other characters.
735 /// In other words, the comparison result can be thought as
736 /// `(lhs.complete(), !lhs.is_complete()).cmp(&(rhs.complete(), !rhs.is_complete()))`.
737 ///
738 /// # Examples
739 ///
740 /// ```
741 /// use str_queue::{PartialHandling, StrQueue};
742 /// use core::cmp::Ordering;
743 ///
744 /// let queue_ce = StrQueue::from(b"Hello\xce");
745 /// let range_ce = queue_ce.chars_range(..);
746 /// let queue_f0 = StrQueue::from(b"Hello\xf0");
747 /// let range_f0 = queue_f0.chars_range(..);
748 ///
749 /// // Bytes for incomplete characters are considered the same.
750 /// assert_eq!(range_ce, range_f0);
751 /// assert_eq!(range_ce.cmp(&range_f0), Ordering::Equal);
752 /// // To distinguish incomplete characters, use bytes range.
753 /// assert_ne!(range_ce.to_bytes_range(), range_f0.to_bytes_range());
754 /// assert_eq!(
755 /// range_ce.to_bytes_range().cmp(&range_f0.to_bytes_range()),
756 /// Ordering::Less
757 /// );
758 /// ```
759 ///
760 /// ```
761 /// use str_queue::{PartialHandling, StrQueue};
762 /// use core::cmp::Ordering;
763 ///
764 /// let queue_ce = StrQueue::from(b"Hello\xce");
765 /// let range_ce = queue_ce.chars_range(..);
766 ///
767 /// let queue_none = StrQueue::from(b"Hello");
768 /// let range_none = queue_none.chars_range(..);
769 /// assert_ne!(range_ce, range_none);
770 /// assert_eq!(range_ce.partial_cmp(&range_none), Some(Ordering::Greater));
771 ///
772 /// let queue_00 = StrQueue::from(b"Hello\x00");
773 /// let range_00 = queue_00.chars_range(..);
774 /// assert_ne!(range_ce, range_00);
775 /// // `\xce` is incomplete, so it is considered smaller than `\x00`.
776 /// // Note that `\x00` is a valid ASCII character.
777 /// assert_eq!(range_ce.partial_cmp(&range_00), Some(Ordering::Less));
778 ///
779 /// let queue_ufffd = StrQueue::from("Hello\u{FFFD}");
780 /// let range_ufffd = queue_ufffd.chars_range(..);
781 /// assert_ne!(range_ce, range_ufffd);
782 /// // The incomplete character (which consists of `\xce`) is converted to
783 /// // `\u{FFFD}` when displayed, but it is not considered to be the same
784 /// // as a valid Unicode character `\u{FFFD}`.
785 /// assert_eq!(range_ce.partial_cmp(&range_ufffd), Some(Ordering::Less));
786 /// ```
787 fn cmp_self(&self, rhs: &Self) -> Ordering {
788 let self_has_incomplete = !self.is_complete();
789 let rhs_has_incomplete = !rhs.is_complete();
790 self.to_complete()
791 .range
792 .cmp_self(&rhs.to_complete().range)
793 .then_with(|| self_has_incomplete.cmp(&rhs_has_incomplete))
794 }
795
796 /// Compares the chars range and a string slice.
797 ///
798 /// If the range has the incomplete character, it is treated as a character
799 /// which is smaller than any other characters.
800 /// In other words, the comparison result can be thought as
801 /// `(range.complete(), !range.is_complete()).cmp(&(rhs, false))`.
802 /// The complete part differ from the rhs string slice, that result is
803 /// returned regardless of the incomplete character.
804 ///
805 /// # Examples
806 ///
807 /// ```
808 /// use str_queue::{PartialHandling, StrQueue};
809 /// use core::cmp::Ordering;
810 ///
811 /// let queue_00 = StrQueue::from(b"Hello\x00");
812 /// let range_00 = queue_00.chars_range(..);
813 /// let queue_ce = StrQueue::from(b"Hello\xce");
814 /// let range_ce = queue_ce.chars_range(..);
815 ///
816 /// assert_eq!(range_00, "Hello\u{0}");
817 /// assert_eq!(range_00.partial_cmp("Hello\u{0}"), Some(Ordering::Equal));
818 ///
819 /// assert_eq!(range_ce.partial_cmp("Hello"), Some(Ordering::Greater));
820 /// // `\xce` is incomplete, so it is considered smaller than `\x00`.
821 /// // Note that `\x00` is a valid ASCII character.
822 /// assert_eq!(range_ce.partial_cmp("Hello\u{0}"), Some(Ordering::Less));
823 /// // The incomplete character (which consists of `\xce`) is converted to
824 /// // `\u{FFFD}` when displayed, but it is not considered to be the same
825 /// // as a valid Unicode character `\u{FFFD}`.
826 /// assert_eq!(range_ce.partial_cmp("Hello\u{FFFD}"), Some(Ordering::Less));
827 /// ```
828 fn cmp_str(&self, rhs: &str) -> Ordering {
829 let (complete, trimmed_len) = self.to_complete_and_trimmed_len();
830 let fallback = || {
831 if trimmed_len == 0 {
832 Ordering::Equal
833 } else {
834 Ordering::Greater
835 }
836 };
837
838 let former_len = complete.range.former.len();
839 let rhs = rhs.as_bytes();
840 let rhs_len = rhs.len();
841
842 if former_len > rhs_len {
843 complete.range.former.cmp(rhs).then_with(fallback)
844 } else {
845 complete
846 .range
847 .former
848 .cmp(&rhs[..former_len])
849 .then_with(|| complete.range.latter.cmp(&rhs[former_len..]))
850 .then_with(fallback)
851 }
852 }
853}
854
855impl fmt::Display for CharsRange<'_> {
856 #[inline]
857 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
858 Fragments::from(*self).fmt(f)
859 }
860}
861
862impl<'a> From<CharsRange<'a>> for BytesRange<'a> {
863 #[inline]
864 fn from(v: CharsRange<'a>) -> Self {
865 v.range
866 }
867}
868
869impl PartialEq for CharsRange<'_> {
870 /// Compares the two chars ranges and returns true if they are equal.
871 ///
872 /// This comparson is arawe of the existence of the last incomplete
873 /// characters, but does not aware of its value.
874 /// If you care about the value of the incomplete characters, you should use
875 /// bytes comparison.
876 ///
877 /// # Examples
878 ///
879 /// ```
880 /// use str_queue::{PartialHandling, StrQueue};
881 /// use core::cmp::Ordering;
882 ///
883 /// let queue1 = StrQueue::from(b"Hello\xce");
884 /// let range1 = queue1.chars_range(..);
885 /// let queue2 = StrQueue::from(b"Hello\xf0");
886 /// let range2 = queue2.chars_range(..);
887 ///
888 /// assert_eq!(range1, range2);
889 /// assert_ne!(range1.to_bytes_range(), range2.to_bytes_range());
890 /// ```
891 #[inline]
892 fn eq(&self, other: &Self) -> bool {
893 // Return earlily if lengths are not the same.
894 (self.len() == other.len()) && self.cmp_self(other).is_eq()
895 }
896}
897
898impl PartialOrd for CharsRange<'_> {
899 /// Compares the two chars ranges.
900 ///
901 /// This comparson is arawe of the existence of the last incomplete
902 /// characters, but does not aware of its value.
903 /// If you care about the value of the incomplete characters, you should use
904 /// bytes comparison.
905 ///
906 /// If the range has the incomplete character, it is treated as a character
907 /// which is smaller than any other characters.
908 /// In other words, the comparison result can be thought as
909 /// `(lhs.complete(), !lhs.is_complete()).cmp(&(rhs.complete(), !rhs.is_complete()))`.
910 ///
911 /// # Examples
912 ///
913 /// ```
914 /// use str_queue::{PartialHandling, StrQueue};
915 /// use core::cmp::Ordering;
916 ///
917 /// let queue_ce = StrQueue::from(b"Hello\xce");
918 /// let range_ce = queue_ce.chars_range(..);
919 /// let queue_f0 = StrQueue::from(b"Hello\xf0");
920 /// let range_f0 = queue_f0.chars_range(..);
921 ///
922 /// // Bytes for incomplete characters are considered the same.
923 /// assert_eq!(range_ce, range_f0);
924 /// assert_eq!(range_ce.cmp(&range_f0), Ordering::Equal);
925 /// // To distinguish incomplete characters, use bytes range.
926 /// assert_ne!(range_ce.to_bytes_range(), range_f0.to_bytes_range());
927 /// assert_eq!(
928 /// range_ce.to_bytes_range().cmp(&range_f0.to_bytes_range()),
929 /// Ordering::Less
930 /// );
931 /// ```
932 ///
933 /// ```
934 /// use str_queue::{PartialHandling, StrQueue};
935 /// use core::cmp::Ordering;
936 ///
937 /// let queue_ce = StrQueue::from(b"Hello\xce");
938 /// let range_ce = queue_ce.chars_range(..);
939 ///
940 /// let queue_none = StrQueue::from(b"Hello");
941 /// let range_none = queue_none.chars_range(..);
942 /// assert_ne!(range_ce, range_none);
943 /// assert_eq!(range_ce.partial_cmp(&range_none), Some(Ordering::Greater));
944 ///
945 /// let queue_00 = StrQueue::from(b"Hello\x00");
946 /// let range_00 = queue_00.chars_range(..);
947 /// assert_ne!(range_ce, range_00);
948 /// // `\xce` is incomplete, so it is considered smaller than `\x00`.
949 /// // Note that `\x00` is a valid ASCII character.
950 /// assert_eq!(range_ce.partial_cmp(&range_00), Some(Ordering::Less));
951 ///
952 /// let queue_ufffd = StrQueue::from("Hello\u{FFFD}");
953 /// let range_ufffd = queue_ufffd.chars_range(..);
954 /// assert_ne!(range_ce, range_ufffd);
955 /// // The incomplete character (which consists of `\xce`) is converted to
956 /// // `\u{FFFD}` when displayed, but it is not considered to be the same
957 /// // as a valid Unicode character `\u{FFFD}`.
958 /// assert_eq!(range_ce.partial_cmp(&range_ufffd), Some(Ordering::Less));
959 /// ```
960 fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
961 Some(self.cmp_self(rhs))
962 }
963}
964
965impl Ord for CharsRange<'_> {
966 ///
967 /// This comparson is arawe of the existence of the last incomplete
968 /// characters, but does not aware of its value.
969 /// If you care about the value of the incomplete characters, you should use
970 /// bytes comparison.
971 ///
972 /// If the range has the incomplete character, it is treated as a character
973 /// which is smaller than any other characters.
974 /// In other words, the comparison result can be thought as
975 /// `(lhs.complete(), !lhs.is_complete()).cmp(&(rhs.complete(), !rhs.is_complete()))`.
976 ///
977 /// # Examples
978 ///
979 /// ```
980 /// use str_queue::{PartialHandling, StrQueue};
981 /// use core::cmp::Ordering;
982 ///
983 /// let queue_ce = StrQueue::from(b"Hello\xce");
984 /// let range_ce = queue_ce.chars_range(..);
985 /// let queue_f0 = StrQueue::from(b"Hello\xf0");
986 /// let range_f0 = queue_f0.chars_range(..);
987 ///
988 /// // Bytes for incomplete characters are considered the same.
989 /// assert_eq!(range_ce, range_f0);
990 /// assert_eq!(range_ce.cmp(&range_f0), Ordering::Equal);
991 /// // To distinguish incomplete characters, use bytes range.
992 /// assert_ne!(range_ce.to_bytes_range(), range_f0.to_bytes_range());
993 /// assert_eq!(
994 /// range_ce.to_bytes_range().cmp(&range_f0.to_bytes_range()),
995 /// Ordering::Less
996 /// );
997 /// ```
998 ///
999 /// ```
1000 /// use str_queue::{PartialHandling, StrQueue};
1001 /// use core::cmp::Ordering;
1002 ///
1003 /// let queue_ce = StrQueue::from(b"Hello\xce");
1004 /// let range_ce = queue_ce.chars_range(..);
1005 ///
1006 /// let queue_none = StrQueue::from(b"Hello");
1007 /// let range_none = queue_none.chars_range(..);
1008 /// assert_ne!(range_ce, range_none);
1009 /// assert_eq!(range_ce.partial_cmp(&range_none), Some(Ordering::Greater));
1010 ///
1011 /// let queue_00 = StrQueue::from(b"Hello\x00");
1012 /// let range_00 = queue_00.chars_range(..);
1013 /// assert_ne!(range_ce, range_00);
1014 /// // `\xce` is incomplete, so it is considered smaller than `\x00`.
1015 /// // Note that `\x00` is a valid ASCII character.
1016 /// assert_eq!(range_ce.partial_cmp(&range_00), Some(Ordering::Less));
1017 ///
1018 /// let queue_ufffd = StrQueue::from("Hello\u{FFFD}");
1019 /// let range_ufffd = queue_ufffd.chars_range(..);
1020 /// assert_ne!(range_ce, range_ufffd);
1021 /// // The incomplete character (which consists of `\xce`) is converted to
1022 /// // `\u{FFFD}` when displayed, but it is not considered to be the same
1023 /// // as a valid Unicode character `\u{FFFD}`.
1024 /// assert_eq!(range_ce.partial_cmp(&range_ufffd), Some(Ordering::Less));
1025 /// ```
1026 fn cmp(&self, rhs: &Self) -> Ordering {
1027 self.cmp_self(rhs)
1028 }
1029}
1030
1031impl PartialEq<str> for CharsRange<'_> {
1032 #[inline]
1033 fn eq(&self, other: &str) -> bool {
1034 // Return earlily if lengths are not the same.
1035 (self.len() == other.len()) && self.cmp_str(other).is_eq()
1036 }
1037}
1038
1039impl PartialOrd<str> for CharsRange<'_> {
1040 /// Compares the chars range and a string slice.
1041 ///
1042 /// If the range has the incomplete character, it is treated as a character
1043 /// which is smaller than any other characters.
1044 /// In other words, the comparison result can be thought as
1045 /// `(range.complete(), !range.is_complete()).cmp(&(rhs, false))`.
1046 /// The complete part differ from the rhs string slice, that result is
1047 /// returned regardless of the incomplete character.
1048 ///
1049 /// # Examples
1050 ///
1051 /// ```
1052 /// use str_queue::{PartialHandling, StrQueue};
1053 /// use core::cmp::Ordering;
1054 ///
1055 /// let queue_00 = StrQueue::from(b"Hello\x00");
1056 /// let range_00 = queue_00.chars_range(..);
1057 /// let queue_ce = StrQueue::from(b"Hello\xce");
1058 /// let range_ce = queue_ce.chars_range(..);
1059 ///
1060 /// assert_eq!(range_00, "Hello\u{0}");
1061 /// assert_eq!(range_00.partial_cmp("Hello\u{0}"), Some(Ordering::Equal));
1062 ///
1063 /// assert_eq!(range_ce.partial_cmp("Hello"), Some(Ordering::Greater));
1064 /// // `\xce` is incomplete, so it is considered smaller than `\x00`.
1065 /// // Note that `\x00` is a valid ASCII character.
1066 /// assert_eq!(range_ce.partial_cmp("Hello\u{0}"), Some(Ordering::Less));
1067 /// // The incomplete character (which consists of `\xce`) is converted to
1068 /// // `\u{FFFD}` when displayed, but it is not considered to be the same
1069 /// // as a valid Unicode character `\u{FFFD}`.
1070 /// assert_eq!(range_ce.partial_cmp("Hello\u{FFFD}"), Some(Ordering::Less));
1071 /// ```
1072 #[inline]
1073 fn partial_cmp(&self, rhs: &str) -> Option<Ordering> {
1074 Some(self.cmp_str(rhs))
1075 }
1076}
1077
1078impl PartialEq<CharsRange<'_>> for str {
1079 #[inline]
1080 fn eq(&self, other: &CharsRange<'_>) -> bool {
1081 other.eq(self)
1082 }
1083}
1084
1085impl PartialOrd<CharsRange<'_>> for str {
1086 #[inline]
1087 fn partial_cmp(&self, rhs: &CharsRange<'_>) -> Option<Ordering> {
1088 rhs.partial_cmp(self).map(Ordering::reverse)
1089 }
1090}
1091
1092impl PartialEq<&str> for CharsRange<'_> {
1093 #[inline]
1094 fn eq(&self, other: &&str) -> bool {
1095 self.eq(*other)
1096 }
1097}
1098
1099impl PartialOrd<&str> for CharsRange<'_> {
1100 #[inline]
1101 fn partial_cmp(&self, rhs: &&str) -> Option<Ordering> {
1102 self.partial_cmp(*rhs)
1103 }
1104}
1105
1106impl PartialEq<CharsRange<'_>> for &str {
1107 #[inline]
1108 fn eq(&self, other: &CharsRange<'_>) -> bool {
1109 other.eq(*self)
1110 }
1111}
1112
1113impl PartialOrd<CharsRange<'_>> for &str {
1114 #[inline]
1115 fn partial_cmp(&self, rhs: &CharsRange<'_>) -> Option<Ordering> {
1116 rhs.partial_cmp(*self).map(Ordering::reverse)
1117 }
1118}
1119
1120/// A line popped from [`CharsRange`] using [`pop_line`][`CharsRange::pop_line`] method.
1121///
1122/// Note that this may pop a line from `CharsRange`, but `StrQueue` behind the
1123/// range won't be affected.
1124///
1125/// Also note that it is unspecified whether the line will be removed from the
1126/// queue, if the `CharsRangePoppedLine` value is not dropped while the borrow
1127/// it holds expires (e.g. due to [`core::mem::forget`]).
1128#[derive(Debug)]
1129pub struct CharsRangePoppedLine<'a, 'r> {
1130 /// Range.
1131 range: &'r mut CharsRange<'a>,
1132 /// Line length.
1133 ///
1134 /// A complete line cannot be empty since it has a line break.
1135 line_len: NonZeroUsize,
1136}
1137
1138impl<'a, 'r> CharsRangePoppedLine<'a, 'r> {
1139 /// Returns the chars range for the line.
1140 #[inline]
1141 #[must_use]
1142 pub fn to_chars_range(&self) -> CharsRange<'a> {
1143 self.range.range(..self.line_len.get())
1144 }
1145
1146 /// Returns the bytes range for the line.
1147 #[inline]
1148 #[must_use]
1149 pub fn to_bytes_range(&self) -> BytesRange<'_> {
1150 self.range.to_bytes_range().range(..self.line_len.get())
1151 }
1152
1153 /// Returns the length of the line.
1154 #[inline]
1155 #[must_use]
1156 pub fn len(&self) -> usize {
1157 self.line_len.get()
1158 }
1159
1160 /// Returns whether the line is empty, i.e. **always returns false**.
1161 ///
1162 /// A complete line to be removed cannot be empty since it has a line break.
1163 #[inline]
1164 #[must_use]
1165 pub const fn is_empty(&self) -> bool {
1166 false
1167 }
1168}
1169
1170impl fmt::Display for CharsRangePoppedLine<'_, '_> {
1171 #[inline]
1172 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1173 self.to_chars_range().fmt(f)
1174 }
1175}
1176
1177impl core::ops::Drop for CharsRangePoppedLine<'_, '_> {
1178 #[inline]
1179 fn drop(&mut self) {
1180 *self.range = self.range.range(self.line_len.get()..);
1181 }
1182}
1183
1184impl PartialEq for CharsRangePoppedLine<'_, '_> {
1185 #[inline]
1186 fn eq(&self, other: &CharsRangePoppedLine<'_, '_>) -> bool {
1187 self.to_bytes_range().eq(&other.to_bytes_range())
1188 }
1189}
1190
1191impl Eq for CharsRangePoppedLine<'_, '_> {}
1192
1193impl PartialOrd for CharsRangePoppedLine<'_, '_> {
1194 #[inline]
1195 fn partial_cmp(&self, rhs: &CharsRangePoppedLine<'_, '_>) -> Option<Ordering> {
1196 self.to_bytes_range().partial_cmp(&rhs.to_bytes_range())
1197 }
1198}
1199
1200impl Ord for CharsRangePoppedLine<'_, '_> {
1201 #[inline]
1202 fn cmp(&self, rhs: &CharsRangePoppedLine<'_, '_>) -> Ordering {
1203 self.to_bytes_range().cmp(&rhs.to_bytes_range())
1204 }
1205}
1206
1207impl PartialEq<str> for CharsRangePoppedLine<'_, '_> {
1208 #[inline]
1209 fn eq(&self, other: &str) -> bool {
1210 self.to_bytes_range().eq(other.as_bytes())
1211 }
1212}
1213
1214impl PartialOrd<str> for CharsRangePoppedLine<'_, '_> {
1215 #[inline]
1216 fn partial_cmp(&self, rhs: &str) -> Option<Ordering> {
1217 self.to_bytes_range().partial_cmp(rhs.as_bytes())
1218 }
1219}
1220
1221impl PartialEq<CharsRangePoppedLine<'_, '_>> for str {
1222 #[inline]
1223 fn eq(&self, other: &CharsRangePoppedLine<'_, '_>) -> bool {
1224 other.to_bytes_range().eq(self.as_bytes())
1225 }
1226}
1227
1228impl PartialOrd<CharsRangePoppedLine<'_, '_>> for str {
1229 #[inline]
1230 fn partial_cmp(&self, rhs: &CharsRangePoppedLine<'_, '_>) -> Option<Ordering> {
1231 rhs.to_bytes_range()
1232 .partial_cmp(self.as_bytes())
1233 .map(Ordering::reverse)
1234 }
1235}
1236
1237impl PartialEq<&str> for CharsRangePoppedLine<'_, '_> {
1238 #[inline]
1239 fn eq(&self, other: &&str) -> bool {
1240 self.eq(*other)
1241 }
1242}
1243
1244impl PartialOrd<&str> for CharsRangePoppedLine<'_, '_> {
1245 #[inline]
1246 fn partial_cmp(&self, rhs: &&str) -> Option<Ordering> {
1247 self.partial_cmp(*rhs)
1248 }
1249}
1250
1251impl PartialEq<CharsRangePoppedLine<'_, '_>> for &str {
1252 #[inline]
1253 fn eq(&self, other: &CharsRangePoppedLine<'_, '_>) -> bool {
1254 other.eq(*self)
1255 }
1256}
1257
1258impl PartialOrd<CharsRangePoppedLine<'_, '_>> for &str {
1259 #[inline]
1260 fn partial_cmp(&self, rhs: &CharsRangePoppedLine<'_, '_>) -> Option<Ordering> {
1261 rhs.partial_cmp(*self).map(Ordering::reverse)
1262 }
1263}