str_queue/lib.rs
1//! A queue for a string.
2//!
3//! # Summary
4//!
5//! [`StrQueue`] is a queue for UTF-8 sequences.
6//! Strings can be pushed into `StrQueue`, characters can be popped from the
7//! queue, and the queue can be printed or converted into a string.
8//!
9//! # Details
10//!
11//! ## Non-contiguous
12//!
13//! `StrQueue` does not guarantee that the content is stored on a contiguous
14//! memory region. As of writing this document, `StrQueue` internally uses a
15//! ring buffer.
16//!
17//! ## Push
18//!
19//! `StrQueue` accepts not only strings to be pushed, but also arbitrary bytes.
20//! When bytes (including valid UTF-8 strings) are pushed, the things below
21//! (theoretically) happen in order:
22//!
23//! 1. Bytes are appended to the internal buffer.
24//! 2. Internal buffers are validated.
25//! * If the buffer has incomplete bytes at the end of the buffer,
26//! they are preserved (at least the until the next bytes are added).
27//! * "Incomplete bytes" here is byte sequence which can be valid
28//! UTF-8 sequence if appropriate bytes are appended.
29//! * Other ill-formed bytes than that are replaced with
30//! [`U+FFFD REPLACEMENT CHARACTER`][`core::char::REPLACEMENT_CHARACTER`]
31//! using the same rule as
32//! [`String::from_utf8_lossy`][`alloc::string::String::from_utf8_lossy`].
33//!
34//! ## Pop
35//!
36//! Pop operations are basically performed to characters, rather than raw bytes.
37//! For example, [`StrQueue::pop_char`] pops the first character, not the first byte.
38//! This principle helps the queue to keep the internal bytes valid as UTF-8 string.
39//!
40//! ## Conversion
41//!
42//! When converting a queue into a string, caller can choose how to handle the
43//! possible trailing incomplete bytes.
44//! [`PartialHandling::Ignore`] lets methods ignore such incomplete bytes (if
45//! exist), and [`PartialHandling::Emit`] lets methods emit them as a `U+FFFD
46//! REPLACEMENT CHARACTER`.
47//!
48//! ## Range
49//!
50//! This crate provides adaptors for subrange access: [`BytesRange`] and
51//! [`CharsRange`]. Subrange adaptor types plays a similar role as [`&str`] for
52//! [`String`]: they are views to the subrange of the underlying `StrQueue`.
53//!
54//! [`BytesRange`] can point to arbitrary subrange.
55//! [`CharsRange`] can only point to a subrange that are valid UTF-8 string and
56//! the last possibly incomplete character (i.e. the same condition as
57//! [`StrQueue`].
58//!
59//! # Usage
60//!
61//! ## Creation
62//!
63//! Default queue created by [`StrQueue::new`] is empty.
64//!
65//! ```
66//! use str_queue::{PartialHandling, StrQueue};
67//!
68//! let queue = StrQueue::new();
69//! assert!(queue.display(PartialHandling::Emit).to_string().is_empty());
70//! ```
71//!
72//! A queue can be created with initial contents by [`StrQueue::from`].
73//!
74//! ```
75//! use str_queue::{PartialHandling, StrQueue};
76//!
77//! let queue = StrQueue::from("hello");
78//! assert_eq!(queue.display(PartialHandling::Emit).to_string(), "hello");
79//! ```
80//!
81//! ```
82//! use str_queue::{PartialHandling, StrQueue};
83//!
84//! let queue = StrQueue::from(b"he\xf0llo\xce");
85//! assert_eq!(queue.display(PartialHandling::Emit).to_string(), "he\u{FFFD}llo\u{FFFD}");
86//! ```
87//!
88//! ## Push
89//!
90//! Bytes and string can be pushed.
91//!
92//! ```
93//! use str_queue::{PartialHandling, StrQueue};
94//!
95//! let mut queue = StrQueue::new();
96//!
97//! queue.push_str("hello");
98//! assert_eq!(queue.display(PartialHandling::Emit).to_string(), "hello");
99//!
100//! queue.push_bytes(b" world");
101//! assert_eq!(queue.display(PartialHandling::Emit).to_string(), "hello world");
102//! ```
103//!
104//! ## Pop
105//!
106//! The first characters can be popped using [`StrQueue::pop_char`].
107//!
108//! ```
109//! use str_queue::StrQueue;
110//!
111//! let mut queue = StrQueue::from(b"ab\xf0");
112//! assert_eq!(queue.pop_char(), Some('a'));
113//! assert_eq!(queue.pop_char(), Some('b'));
114//! // Incomplete bytes are simply ignored as they are not a character.
115//! assert_eq!(queue.pop_char(), None);
116//! ```
117//!
118//! The first line can be popped using [`StrQueue::pop_line`].
119//!
120//! ```
121//! use str_queue::StrQueue;
122//!
123//! // Note that the last "world\r" is not considered as a complete line
124//! // since the line can be finally "world\r" or "world\r\n".
125//! let mut queue = StrQueue::from("Hello\nworld\r\nGoodbye\rworld\r");
126//!
127//! // The popped line can be dropped.
128//! queue.pop_line();
129//! // The popped line can be accessed.
130//! assert_eq!(queue.pop_line().map(|v| v.to_string()).as_deref(), Some("world\r\n"));
131//! assert_eq!(queue.pop_line().map(|v| v.to_string()).as_deref(), Some("Goodbye\r"));
132//! assert_eq!(queue.pop_line().map(|v| v.to_string()).as_deref(), None);
133//! assert_eq!(queue.chars_range(..), "world\r");
134//! ```
135//!
136//! ## Ranges
137//!
138//! Bytes ranges can be created by [`StrQueue::bytes_range`] method.
139//!
140//! ```
141//! use str_queue::StrQueue;
142//!
143//! let queue = StrQueue::from("alpha\u{03B1}beta\u{03B2}");
144//! let bytes = queue.bytes_range(6..12);
145//! assert_eq!(bytes, b"\xb1beta\xce"[..]);
146//! ```
147//!
148//! Chars ranges can be created by [`StrQueue::chars_range`] method.
149//! `CharsRange` implements [`Display`][`core::fmt::Display`] and
150//! [`ToString`][`alloc::string::ToString`] traits, since the it is guaranteed
151//! to have a valid string as a prefix (with possibly incomplete character as
152//! a suffix).
153//!
154//! ```
155//! use str_queue::StrQueue;
156//!
157//! let queue = StrQueue::from("alpha\u{03B1}beta\u{03B2}");
158//! let range = queue.chars_range(7..);
159//! assert_eq!(range, "beta\u{03B2}");
160//! assert_eq!(range.to_string(), "beta\u{03B2}");
161//! ```
162//!
163//! Subranges can be created from ranges.
164//!
165//! ```
166//! use str_queue::StrQueue;
167//!
168//! let queue = StrQueue::from("Hello world");
169//! let bytes = queue.bytes_range(6..);
170//! assert_eq!(bytes, b"world"[..]);
171//!
172//! let subrange = bytes.range(1..4);
173//! assert_eq!(subrange, b"orl"[..]);
174//! ```
175//!
176//! ```
177//! use str_queue::StrQueue;
178//!
179//! let queue = StrQueue::from("Hello world");
180//! let range = queue.chars_range(6..);
181//! assert_eq!(range, "world");
182//!
183//! let subrange = range.range(1..4);
184//! assert_eq!(subrange, "orl");
185//! ```
186//!
187//! ## Conversion
188//!
189//! Note that `StrQueue` does not guarantee the content is stored on a
190//! contiguous memory region.
191//! So, you cannot get the content string as a single `&str` without paying
192//! additional cost.
193//!
194//! ### Display
195//!
196//! [`StrQueue::display`] returns a helper struct which implements
197//! [`core::fmt::Display`]. It can be written to a formatter or converted to
198//! a string using `.to_string()`.
199//!
200//! To create [`String`][`alloc::string::String`], use `.to_string()`.
201//!
202//! ```
203//! use str_queue::{PartialHandling, StrQueue};
204//!
205//! let queue = StrQueue::from("hello");
206//!
207//! let s: String = queue.display(PartialHandling::Emit).to_string();
208//! assert_eq!(s, "hello");
209//! ```
210//!
211//! To write the string into a writer, use the return value directly.
212//!
213//! ```
214//! use core::fmt::Write as _;
215//! use str_queue::{PartialHandling, StrQueue};
216//!
217//! let queue = StrQueue::from("hello");
218//! // `String` implements `core::fmt::Write`, and can be used for `write!()`.
219//! let mut buf = String::new();
220//!
221//! write!(buf, "{}", queue.display(PartialHandling::Emit));
222//! assert_eq!(buf, "hello");
223//! ```
224//!
225//! ### Fragments
226//!
227//! [`StrQueue::fragments`] returns an iterator of [`Fragment`]s, which can hold
228//! a substring slices and a characters.
229//!
230//! ```
231//! use str_queue::{Fragment, PartialHandling, StrQueue};
232//!
233//! // Note that `\xce` can appear as a first byte of valid UTF-8 sequence.
234//! let queue = StrQueue::from(b"hello \xce");
235//!
236//! let mut buf = String::new();
237//! for frag in queue.fragments(PartialHandling::Emit) {
238//! match frag {
239//! Fragment::Str(s) => buf.push_str(s),
240//! Fragment::Char(c) => buf.push(c),
241//! Fragment::Incomplete => buf.push_str("<<incomplete>>"),
242//! }
243//! }
244//! assert_eq!(buf, "hello <<incomplete>>");
245//! ```
246//!
247//! ### Characters
248//!
249//! [`StrQueue::chars`] and [`StrQueue::into_chars`] return an iterator of [`char`]s.
250//!
251//! `StrQueue::chars` does not consume the queue.
252//!
253//! ```
254//! use str_queue::{PartialHandling, StrQueue};
255//!
256//! let queue = StrQueue::from("hello");
257//! let mut chars = queue.chars(PartialHandling::Emit);
258//! assert_eq!(chars.next(), Some('h'));
259//! assert_eq!(chars.next(), Some('e'));
260//! assert_eq!(chars.next(), Some('l'));
261//! assert_eq!(chars.next(), Some('l'));
262//! assert_eq!(chars.next(), Some('o'));
263//! assert_eq!(chars.next(), None);
264//! // `StrQueue::chars()` does not consume the queue, so it can be used here.
265//! assert_eq!(
266//! queue.chars(PartialHandling::Emit).collect::<String>(),
267//! "hello"
268//! );
269//! ```
270//!
271//! `StrQueue::into_chars` consumes the queue.
272//!
273//! ```
274//! use str_queue::{PartialHandling, StrQueue};
275//!
276//! let queue = StrQueue::from("hello");
277//! let mut chars = queue.into_chars(PartialHandling::Emit);
278//! assert_eq!(chars.next(), Some('h'));
279//! assert_eq!(chars.next(), Some('e'));
280//! assert_eq!(chars.next(), Some('l'));
281//! assert_eq!(chars.next(), Some('l'));
282//! assert_eq!(chars.next(), Some('o'));
283//! assert_eq!(chars.next(), None);
284//! // `queue` is no longer available, as it is consumeb dy `queue.into_chars()`.
285//! ```
286#![cfg_attr(not(feature = "std"), no_std)]
287#![forbid(unsafe_code)]
288#![warn(rust_2018_idioms)]
289// `clippy::missing_docs_in_private_items` implies `missing_docs`.
290#![warn(clippy::missing_docs_in_private_items)]
291#![warn(clippy::unwrap_used)]
292
293extern crate alloc;
294
295mod iter;
296mod range;
297mod utf8;
298
299use core::cmp::Ordering;
300use core::fmt;
301use core::hash;
302use core::mem;
303use core::num::NonZeroUsize;
304use core::ops::{Bound, RangeBounds};
305use core::str;
306
307use alloc::collections::VecDeque;
308
309pub use crate::iter::{Chars, Fragment, Fragments, IntoChars};
310pub use crate::range::{BytesRange, CharsRange, CharsRangePoppedLine};
311use crate::utf8::REPLACEMENT_CHAR_STR;
312
313/// Queue for a string.
314///
315/// This queue can contain incomplete UTF-8 byte sequences at the tail.
316/// However, if it became sure that the sequence is invalid as UTF-8 sequence,
317/// the invalid bytes would be replaced by U+FFFD REPLACEMENT CHARACTER.
318#[derive(Default, Debug, Clone)]
319pub struct StrQueue {
320 /// Inner deque.
321 inner: VecDeque<u8>,
322 /// Length of the trailing bytes that are possibly invalid UTF-8 sequence.
323 ///
324 /// This must always be less than 4.
325 len_incomplete: u8,
326}
327
328/// `StrQueue` creation.
329impl StrQueue {
330 /// Creates an empty `StrQueue`.
331 ///
332 /// # Examples
333 ///
334 /// ```
335 /// use str_queue::StrQueue;
336 ///
337 /// let deque = StrQueue::new();
338 /// ```
339 #[inline]
340 #[must_use]
341 pub fn new() -> Self {
342 Self::default()
343 }
344
345 /// Creates an empty `StrQueue` with at least the given capacity.
346 ///
347 /// # Examples
348 ///
349 /// ```
350 /// use str_queue::StrQueue;
351 ///
352 /// let deque = StrQueue::with_capacity(42);
353 ///
354 /// assert!(deque.capacity() >= 42);
355 /// ```
356 #[inline]
357 #[must_use]
358 pub fn with_capacity(capacity: usize) -> Self {
359 Self {
360 inner: VecDeque::with_capacity(capacity),
361 len_incomplete: 0,
362 }
363 }
364}
365
366/// Capacity.
367impl StrQueue {
368 /// Returns the number of bytes the `StrQueue` can hold without reallocating.
369 ///
370 /// # Examples
371 ///
372 /// ```
373 /// use str_queue::StrQueue;
374 ///
375 /// let deque = StrQueue::with_capacity(42);
376 ///
377 /// assert!(deque.capacity() >= 42);
378 /// ```
379 #[inline]
380 #[must_use]
381 pub fn capacity(&self) -> usize {
382 self.inner.capacity()
383 }
384
385 /// Reserves capacity for at least `additional` more bytes.
386 #[inline]
387 pub fn reserve(&mut self, additional: usize) {
388 self.inner.reserve(additional);
389 }
390
391 /// Reserves capacity for exact `additional` more bytes.
392 #[inline]
393 pub fn reserve_exact(&mut self, additional: usize) {
394 self.inner.reserve_exact(additional);
395 }
396
397 /// Shrinks the capacity of the `StrQueue` as much as possible.
398 #[inline]
399 pub fn shrink_to_fit(&mut self) {
400 self.inner.shrink_to_fit();
401 }
402}
403
404/// Subrange access.
405impl StrQueue {
406 /// Returns the subrange accessor for the queue.
407 #[inline]
408 #[must_use]
409 pub fn bytes_range<R>(&self, range: R) -> BytesRange<'_>
410 where
411 R: RangeBounds<usize>,
412 {
413 BytesRange::new(self, range)
414 }
415
416 /// Returns the subrange accessor for the queue.
417 ///
418 /// The returned range can contain an incomplete character at the end.
419 /// If you want to exclude a possible trailing incomplete character in the range,
420 /// use [`CharsRange::to_complete`] or [`CharsRange::trim_last_incomplete_char`].
421 ///
422 /// # Panics
423 ///
424 /// Panics if the start bound of the range does not lie on UTF-8 sequence boundary.
425 #[inline]
426 #[must_use]
427 pub fn chars_range<R>(&self, range: R) -> CharsRange<'_>
428 where
429 R: RangeBounds<usize>,
430 {
431 CharsRange::new(self, range)
432 }
433}
434
435/// Content length and existence.
436impl StrQueue {
437 /// Returns the string length in bytes, including incomplete bytes.
438 ///
439 /// # Examples
440 ///
441 /// ```
442 /// use str_queue::StrQueue;
443 ///
444 /// let queue = StrQueue::from(b"hello\xce");
445 /// assert_eq!(queue.len(), 6);
446 /// ```
447 #[inline]
448 #[must_use]
449 pub fn len(&self) -> usize {
450 self.inner.len()
451 }
452
453 /// Returns true if the queue is completely empty (i.e. has no bytes).
454 ///
455 /// # Examples
456 ///
457 /// ```
458 /// use str_queue::StrQueue;
459 ///
460 /// let mut queue = StrQueue::new();
461 /// assert!(queue.is_empty());
462 ///
463 /// queue.push_str("hello");
464 /// assert!(!queue.is_empty());
465 /// ```
466 #[inline]
467 #[must_use]
468 pub fn is_empty(&self) -> bool {
469 self.inner.is_empty()
470 }
471
472 /// Returns the string length in bytes, excluding incomplete bytes.
473 ///
474 /// # Examples
475 ///
476 /// ```
477 /// use str_queue::StrQueue;
478 ///
479 /// let queue = StrQueue::from(b"hello\xce");
480 /// assert_eq!(queue.len_complete(), 5);
481 /// ```
482 #[inline]
483 #[must_use]
484 pub fn len_complete(&self) -> usize {
485 self.inner.len() - self.len_incomplete()
486 }
487
488 /// Returns the length of incomplete bytes.
489 ///
490 /// # Examples
491 ///
492 /// ```
493 /// use str_queue::StrQueue;
494 ///
495 /// let queue = StrQueue::from(b"hello\xce");
496 /// assert_eq!(queue.len_incomplete(), 1);
497 /// ```
498 #[inline]
499 #[must_use]
500 pub fn len_incomplete(&self) -> usize {
501 usize::from(self.len_incomplete)
502 }
503
504 /// Returns true if the `StrQueue` contains no complete string.
505 ///
506 /// This returns the same value as `self.first().is_none()`.
507 ///
508 /// # Examples
509 ///
510 /// ```
511 /// use str_queue::StrQueue;
512 ///
513 /// let mut queue = StrQueue::new();
514 /// assert!(queue.is_empty_complete());
515 ///
516 /// queue.push_bytes(b"\xce");
517 /// assert!(queue.is_empty_complete());
518 /// assert_eq!(queue.first_char(), None);
519 ///
520 /// queue.push_bytes(b"\xb1");
521 /// assert!(!queue.is_empty_complete());
522 /// assert_eq!(queue.first_char(), Some('\u{03B1}'));
523 /// ```
524 #[inline]
525 #[must_use]
526 pub fn is_empty_complete(&self) -> bool {
527 self.inner.len() == self.len_incomplete as usize
528 }
529
530 /// Returns true if the content is a complete string, i.e. has no trailing
531 /// incomplete character.
532 ///
533 /// # Examples
534 ///
535 /// ```
536 /// use str_queue::StrQueue;
537 ///
538 /// let mut queue = StrQueue::from(b"abc\xce");
539 /// assert!(!queue.is_complete());
540 /// queue.push_bytes(b"\xb1");
541 /// // Now the string is "abc\u{03B1}".
542 /// assert!(queue.is_complete());
543 /// ```
544 pub fn is_complete(&self) -> bool {
545 self.len_incomplete == 0
546 }
547}
548
549/// Buffer and content manipulation.
550impl StrQueue {
551 /// Clears the `StrQueue`, removing all bytes.
552 ///
553 /// # Examples
554 ///
555 /// ```
556 /// use str_queue::{PartialHandling, StrQueue};
557 ///
558 /// let mut queue = StrQueue::from(b"Hello \xce");
559 /// assert!(!queue.is_empty());
560 ///
561 /// queue.clear();
562 /// assert!(queue.is_empty());
563 /// ```
564 #[inline]
565 pub fn clear(&mut self) {
566 self.inner.clear();
567 }
568
569 /// Trims the last incomplete character, and returns the length of the trimmed bytes.
570 ///
571 /// If the string is complete (i.e. no incomplete character follows), does
572 /// nothing and returns 0.
573 ///
574 /// If you want to get a modified copy instead of modifying `self` itself,
575 /// use [`CharsRange::to_complete`].
576 ///
577 /// # Examples
578 ///
579 /// ```
580 /// use str_queue::{PartialHandling, StrQueue};
581 ///
582 /// let mut queue = StrQueue::from(b"Hello \xce");
583 /// assert_eq!(
584 /// queue.display(PartialHandling::Emit).to_string(),
585 /// "Hello \u{FFFD}"
586 /// );
587 ///
588 /// queue.trim_last_incomplete_char();
589 /// assert_eq!(queue.display(PartialHandling::Emit).to_string(), "Hello ");
590 /// ```
591 pub fn trim_last_incomplete_char(&mut self) -> usize {
592 self.inner.truncate(self.len_complete());
593 usize::from(mem::replace(&mut self.len_incomplete, 0))
594 }
595
596 /// Pushes the given string to the queue.
597 ///
598 /// # Examples
599 ///
600 /// ```
601 /// use str_queue::{PartialHandling, StrQueue};
602 ///
603 /// let mut queue = StrQueue::from("hello");
604 /// queue.push_str(" world");
605 ///
606 /// assert_eq!(
607 /// queue.chars(PartialHandling::Emit).collect::<String>(),
608 /// "hello world"
609 /// );
610 /// ```
611 pub fn push_str(&mut self, s: &str) {
612 if self.len_incomplete != 0 {
613 self.inner.truncate(self.len_complete());
614 self.inner.extend(REPLACEMENT_CHAR_STR.as_bytes());
615 self.len_incomplete = 0;
616 }
617 self.inner.extend(s.as_bytes());
618 }
619
620 /// Pushes the given character to the queue.
621 ///
622 /// # Examples
623 ///
624 /// ```
625 /// use str_queue::{PartialHandling, StrQueue};
626 ///
627 /// let mut queue = StrQueue::from("hello");
628 /// queue.push_char('!');
629 ///
630 /// assert_eq!(
631 /// queue.chars(PartialHandling::Emit).collect::<String>(),
632 /// "hello!"
633 /// );
634 /// ```
635 pub fn push_char(&mut self, c: char) {
636 let mut buf = [0_u8; 4];
637 self.push_str(c.encode_utf8(&mut buf));
638 }
639
640 /// Pushes the given bytes to the queue.
641 ///
642 /// Invalid UTF-8 sequences not at the last would be replaced with
643 /// `U+FFFD REPLACEMENT CHARACTER`.
644 /// The last incomplete sequences would be kept, since it might become valid
645 /// when more bytes are appended later.
646 ///
647 /// # Examples
648 ///
649 /// ```
650 /// use str_queue::{PartialHandling, StrQueue};
651 ///
652 /// let mut queue = StrQueue::from(b"alpha \xce");
653 /// assert_eq!(
654 /// queue.chars(PartialHandling::Emit).collect::<String>(),
655 /// "alpha \u{FFFD}"
656 /// );
657 ///
658 /// queue.push_bytes(b"\xb1");
659 /// assert_eq!(
660 /// queue.chars(PartialHandling::Emit).collect::<String>(),
661 /// "alpha \u{03B1}"
662 /// );
663 /// ```
664 pub fn push_bytes(&mut self, mut bytes: &[u8]) {
665 // Process incomplete bytes.
666 loop {
667 let (rest, has_progress) = self.process_incomplete_bytes(bytes);
668 if !has_progress {
669 break;
670 }
671 bytes = rest;
672 }
673 if self.len_incomplete != 0 {
674 assert!(
675 bytes.is_empty(),
676 "[consistency] it is not expected to give up processing \
677 incomplete bytes before consuming all the inputs"
678 );
679 return;
680 }
681
682 while !bytes.is_empty() {
683 let e = match str::from_utf8(bytes) {
684 Ok(s) => {
685 self.inner.extend(s.as_bytes());
686 return;
687 }
688 Err(e) => e,
689 };
690 let valid_up_to = e.valid_up_to();
691 if let Some(error_len) = e.error_len() {
692 // Replace invalid bytes with U+FFFD, and resume.
693 self.inner.extend(&bytes[..valid_up_to]);
694 self.inner.extend(REPLACEMENT_CHAR_STR.as_bytes());
695 bytes = &bytes[(valid_up_to + error_len)..];
696 continue;
697 } else {
698 self.inner.extend(bytes);
699 self.len_incomplete = (bytes.len() - valid_up_to) as u8;
700 return;
701 }
702 }
703 }
704
705 /// Processes incomplete bytes and returns a pair of the rest input and the progress.
706 ///
707 /// If there are progress, `(_, true)` is returned.
708 /// If no progress can be made, `(_, false)` is returned.
709 fn process_incomplete_bytes<'a>(&mut self, bytes: &'a [u8]) -> (&'a [u8], bool) {
710 let len_incomplete = usize::from(self.len_incomplete);
711 if len_incomplete == 0 {
712 // Nothing to process.
713 return (bytes, false);
714 }
715
716 // Load already-known incomplete bytes.
717 let mut buf = [0_u8; 4];
718 self.inner
719 .range(self.len_complete()..)
720 .zip(&mut buf[..])
721 .for_each(|(src, dest)| *dest = *src);
722 let len_expected = usize::from(utf8::expected_char_len(buf[0]));
723
724 let len_from_input = len_expected.saturating_sub(len_incomplete);
725 let e = if len_from_input != 0 {
726 // Get more bytes.
727 buf[len_incomplete..len_expected].copy_from_slice(&bytes[..len_from_input]);
728 // Check if the bytes became valid UTF-8 sequence.
729 match str::from_utf8(&buf[..len_expected]) {
730 Ok(_) => {
731 self.inner.extend(&buf[len_incomplete..len_expected]);
732 self.len_incomplete = 0;
733 return (&bytes[len_from_input..], true);
734 }
735 Err(e) => e,
736 }
737 } else {
738 // Incomplete bytes might have some valid UTF-8 sequence.
739 // Check if such prefix exists.
740 match str::from_utf8(&buf[..len_expected]) {
741 Ok(_) => {
742 self.len_incomplete = (len_incomplete - len_expected) as u8;
743 return (bytes, true);
744 }
745 Err(e) => e,
746 }
747 };
748
749 // Cannot get valid UTF-8 sequence.
750 // Remove leading bytes from incomplete bytes.
751 assert_eq!(
752 e.valid_up_to(),
753 0,
754 "[consistency] the buffer must have no valid leading characters here"
755 );
756 let error_len = match e.error_len() {
757 Some(e) => e,
758 None => {
759 // Not enough input.
760 assert_eq!(
761 len_from_input,
762 bytes.len(),
763 "[consistency] if more inputs are available, bytes must be \
764 able to be completed or discarded"
765 );
766 return (&bytes[len_from_input..], len_from_input != 0);
767 }
768 };
769 self.inner.truncate(self.len_complete());
770 self.inner.extend(REPLACEMENT_CHAR_STR.as_bytes());
771 self.inner.extend(&buf[error_len..len_expected]);
772 self.len_incomplete = (len_expected - error_len) as u8;
773
774 (&bytes[len_from_input..], true)
775 }
776
777 /// Pops the first character in the buffer and returns it.
778 ///
779 /// Trailing incomplete character is ignored.
780 ///
781 /// # Examples
782 ///
783 /// ```
784 /// use str_queue::StrQueue;
785 ///
786 /// let mut queue = StrQueue::from("hello");
787 ///
788 /// assert_eq!(queue.pop_char(), Some('h'));
789 /// assert_eq!(queue.pop_char(), Some('e'));
790 /// assert_eq!(queue.pop_char(), Some('l'));
791 /// assert_eq!(queue.pop_char(), Some('l'));
792 /// assert_eq!(queue.pop_char(), Some('o'));
793 /// assert_eq!(queue.pop_char(), None);
794 /// assert!(queue.is_empty());
795 /// ```
796 ///
797 /// ```
798 /// use str_queue::StrQueue;
799 ///
800 /// let mut queue = StrQueue::from(b"a\xf0");
801 ///
802 /// assert_eq!(queue.pop_char(), Some('a'));
803 /// assert_eq!(queue.pop_char(), None);
804 /// assert!(!queue.is_empty());
805 /// ```
806 pub fn pop_char(&mut self) -> Option<char> {
807 let (c, len) = self.first_char_and_len()?;
808 self.inner.drain(..usize::from(len));
809
810 Some(c)
811 }
812
813 /// Pops the first character from the queue and returns it.
814 ///
815 /// The trailing incomplete character is replaced with `U+FFFD REPLACEMENT
816 /// CHARACTER`, if available.
817 ///
818 /// # Examples
819 ///
820 /// ```
821 /// use str_queue::StrQueue;
822 ///
823 /// let queue = StrQueue::from(b"abc\xce");
824 /// let mut range = queue.chars_range(..);
825 ///
826 /// assert_eq!(range.pop_char_replaced(), Some('a'));
827 /// assert_eq!(range.pop_char_replaced(), Some('b'));
828 /// assert_eq!(range.pop_char_replaced(), Some('c'));
829 /// assert_eq!(range.pop_char_replaced(), Some('\u{FFFD}'));
830 /// assert_eq!(range.pop_char_replaced(), None);
831 /// ```
832 pub fn pop_char_replaced(&mut self) -> Option<char> {
833 self.pop_char().or_else(|| {
834 if self.is_empty() {
835 return None;
836 }
837 self.inner.clear();
838 Some('\u{FFFD}')
839 })
840 }
841
842 /// Pops the first line in the queue and returns it.
843 ///
844 /// Incomplete lines are ignored.
845 ///
846 /// Note that it is unspecified whether the line will be removed from the queue,
847 /// if the `PoppedLine` value is not dropped while the borrow it holds expires
848 /// (e.g. due to [`core::mem::forget`]).
849 ///
850 /// # Examples
851 ///
852 /// ```
853 /// use str_queue::StrQueue;
854 ///
855 /// // Note that the last "world\r" is not considered as a complete line
856 /// // since the line can be finally "world\r" or "world\r\n".
857 /// let mut queue = StrQueue::from("Hello\nworld\r\nGoodbye\rworld\r");
858 ///
859 /// assert_eq!(queue.pop_line().map(|v| v.to_string()).as_deref(), Some("Hello\n"));
860 /// assert_eq!(queue.pop_line().map(|v| v.to_string()).as_deref(), Some("world\r\n"));
861 /// assert_eq!(queue.pop_line().map(|v| v.to_string()).as_deref(), Some("Goodbye\r"));
862 /// assert_eq!(queue.pop_line().map(|v| v.to_string()).as_deref(), None);
863 /// assert_eq!(queue.chars_range(..), "world\r");
864 /// ```
865 #[inline]
866 pub fn pop_line(&mut self) -> Option<PoppedLine<'_>> {
867 let line_len = self.first_line()?.len();
868 let line_len = NonZeroUsize::new(line_len)
869 .expect("[validity] a complete line must not be empty since it has a line break");
870 Some(PoppedLine {
871 queue: self,
872 line_len,
873 })
874 }
875
876 /// Pops the first [`Fragment`] from the queue and return it.
877 ///
878 /// In other words, takes as much content as possible from the queue.
879 ///
880 /// # Examples
881 ///
882 /// ```
883 /// use str_queue::StrQueue;
884 ///
885 /// let mut queue = StrQueue::from(b"Hello \xce");
886 /// let mut buf = String::new();
887 ///
888 /// while let Some(frag) = queue.pop_fragment() {
889 /// buf.push_str(&frag.to_string());
890 /// }
891 ///
892 /// assert_eq!(buf, "Hello \u{FFFD}");
893 /// assert!(queue.is_empty());
894 /// ```
895 pub fn pop_fragment(&mut self) -> Option<PoppedFragment<'_>> {
896 if self.inner.is_empty() {
897 return None;
898 }
899
900 let (former, latter) = self.inner.as_slices();
901 if !former.is_empty() {
902 let last_len = utf8::last_char_len_in_last_4bytes(former)
903 .expect("[validity] the queue content must start with valid UTF-8 string");
904 if last_len.is_complete() {
905 return Some(PoppedFragment {
906 queue: self,
907 after_state: StateAfterPoppingFragment::Char { latter_consumed: 0 },
908 });
909 }
910 if usize::from(last_len.available) != former.len() {
911 // Non-empty complete string prefix exists.
912 return Some(PoppedFragment {
913 queue: self,
914 after_state: StateAfterPoppingFragment::Former {
915 rest: last_len.available,
916 },
917 });
918 }
919
920 let len_missing = last_len.len_missing();
921 if last_len.len_missing() <= latter.len() {
922 return Some(PoppedFragment {
923 queue: self,
924 after_state: StateAfterPoppingFragment::Char {
925 latter_consumed: len_missing as u8,
926 },
927 });
928 }
929
930 return Some(PoppedFragment {
931 queue: self,
932 after_state: StateAfterPoppingFragment::AllConsumed,
933 });
934 }
935
936 let last_len = utf8::last_char_len_in_last_4bytes(latter)
937 .expect("[validity] the queue content must start with valid UTF-8 string");
938 if last_len.is_complete() {
939 return Some(PoppedFragment {
940 queue: self,
941 after_state: StateAfterPoppingFragment::Latter { rest: 0 },
942 });
943 }
944 Some(PoppedFragment {
945 queue: self,
946 after_state: StateAfterPoppingFragment::AllConsumed,
947 })
948 }
949}
950
951/// Content access.
952impl StrQueue {
953 /// Returns the first character in the buffer and its length in bytes.
954 #[must_use]
955 fn first_char_and_len(&self) -> Option<(char, u8)> {
956 let bytes = self.inner.iter().take(4).copied();
957 utf8::take_char(bytes)
958 }
959
960 /// Returns the first character in the buffer.
961 ///
962 /// # Examples
963 ///
964 /// ```
965 /// use str_queue::StrQueue;
966 ///
967 /// let queue = StrQueue::from("hello");
968 ///
969 /// assert_eq!(queue.first_char(), Some('h'));
970 /// ```
971 #[inline]
972 #[must_use]
973 pub fn first_char(&self) -> Option<char> {
974 self.first_char_and_len().map(|(c, _len)| c)
975 }
976
977 /// Returns the first complete line in the buffer.
978 ///
979 /// # Examples
980 ///
981 /// ```
982 /// use str_queue::StrQueue;
983 ///
984 /// let mut queue = StrQueue::from("hello");
985 /// // No complete line.
986 /// assert_eq!(queue.first_line(), None);
987 ///
988 /// queue.push_bytes(b"\r");
989 /// // Still no complete line: "hello\r" is considered incomplete since
990 /// // it cannot be decided whether the line is "hello\r" or "hello\r\n".
991 /// assert_eq!(queue.first_line(), None);
992 ///
993 /// queue.push_bytes(b"\n");
994 /// assert_eq!(
995 /// queue.first_line().map(|line| line.to_string()).as_deref(),
996 /// Some("hello\r\n")
997 /// );
998 /// ```
999 #[inline]
1000 #[must_use]
1001 pub fn first_line(&self) -> Option<CharsRange<'_>> {
1002 self.chars_range(..).first_line()
1003 }
1004}
1005
1006/// Iterators.
1007impl StrQueue {
1008 /// Turns the queue into an iterator of the characters.
1009 ///
1010 /// # Examples
1011 ///
1012 /// ```
1013 /// use str_queue::{PartialHandling, StrQueue};
1014 ///
1015 /// let queue = StrQueue::from("alpha \u{03B1} beta \u{03B2}");
1016 ///
1017 /// assert_eq!(
1018 /// queue.into_chars(PartialHandling::Emit).collect::<String>(),
1019 /// "alpha \u{03B1} beta \u{03B2}"
1020 /// );
1021 /// ```
1022 ///
1023 /// Trailing possibly invalid bytes (i.e. incomplete characters) can be
1024 /// replaced with `U+FFFD REPLACEMENT CHARACTER`, or be simply ignored.
1025 ///
1026 /// ```
1027 /// use str_queue::{PartialHandling, StrQueue};
1028 ///
1029 /// let mut queue = StrQueue::from(b"alpha->\xce");
1030 ///
1031 /// // The trailing incomplete character is ignored.
1032 /// assert_eq!(
1033 /// queue.clone().into_chars(PartialHandling::Ignore).collect::<String>(),
1034 /// "alpha->"
1035 /// );
1036 /// // The trailing incomplete character is replaced with U+FFFD.
1037 /// assert_eq!(
1038 /// queue.into_chars(PartialHandling::Emit).collect::<String>(),
1039 /// "alpha->\u{FFFD}"
1040 /// );
1041 /// ```
1042 #[inline]
1043 #[must_use]
1044 pub fn into_chars(self, partial_handling: PartialHandling) -> IntoChars {
1045 IntoChars::new(self, partial_handling)
1046 }
1047
1048 /// Turns the queue into an iterator of the characters.
1049 ///
1050 /// # Examples
1051 ///
1052 /// ```
1053 /// use str_queue::{PartialHandling, StrQueue};
1054 ///
1055 /// let queue = StrQueue::from("alpha \u{03B1} beta \u{03B2}");
1056 ///
1057 /// assert_eq!(
1058 /// queue.chars(PartialHandling::Emit).collect::<String>(),
1059 /// "alpha \u{03B1} beta \u{03B2}"
1060 /// );
1061 /// ```
1062 ///
1063 /// Trailing possibly invalid bytes (i.e. incomplete characters) can be
1064 /// replaced with `U+FFFD REPLACEMENT CHARACTER`, or be simply ignored.
1065 ///
1066 /// ```
1067 /// use str_queue::{PartialHandling, StrQueue};
1068 ///
1069 /// let mut queue = StrQueue::from(b"alpha->\xce");
1070 /// // The trailing incomplete character is ignored.
1071 /// assert_eq!(
1072 /// queue.chars(PartialHandling::Ignore).collect::<String>(),
1073 /// "alpha->"
1074 /// );
1075 /// // The trailing incomplete character is replaced with U+FFFD.
1076 /// assert_eq!(
1077 /// queue.chars(PartialHandling::Emit).collect::<String>(),
1078 /// "alpha->\u{FFFD}"
1079 /// );
1080 ///
1081 /// queue.push_bytes(b"\xb1");
1082 /// assert_eq!(
1083 /// queue.chars(PartialHandling::Emit).collect::<String>(),
1084 /// "alpha->\u{03B1}"
1085 /// );
1086 /// ```
1087 #[inline]
1088 #[must_use]
1089 pub fn chars(&self, partial_handling: PartialHandling) -> Chars<'_> {
1090 Chars::new(self, .., partial_handling)
1091 }
1092
1093 /// Returns the chars iterator for the range.
1094 ///
1095 /// # Panics
1096 ///
1097 /// Panics if the start index of the range does not lie on UTF-8 sequence boundary.
1098 ///
1099 /// # Examples
1100 ///
1101 /// ```
1102 /// use str_queue::{Fragment, PartialHandling, StrQueue};
1103 ///
1104 /// let queue = StrQueue::from("alpha\u{03B1}");
1105 ///
1106 /// assert_eq!(
1107 /// queue.range_chars(3..6, PartialHandling::Emit).collect::<String>(),
1108 /// "ha\u{FFFD}"
1109 /// );
1110 /// assert_eq!(
1111 /// queue.range_chars(3..6, PartialHandling::Ignore).collect::<String>(),
1112 /// "ha"
1113 /// );
1114 /// ```
1115 #[must_use]
1116 pub fn range_chars<R>(&self, range: R, partial_handling: PartialHandling) -> Chars<'_>
1117 where
1118 R: RangeBounds<usize>,
1119 {
1120 Chars::new(self, range, partial_handling)
1121 }
1122
1123 /// Returns an iterator of content fragments.
1124 ///
1125 /// # Examples
1126 ///
1127 /// The code below are redundant since they are intended to show how to use [`Fragment`].
1128 /// To simply create a string from the queue, use [`StrQueue::display`] method.
1129 ///
1130 /// ```
1131 /// use str_queue::{Fragment, PartialHandling, StrQueue};
1132 ///
1133 /// // Note that `\xce` can appear as a first byte of valid UTF-8 sequence.
1134 /// let queue = StrQueue::from(b"hello \xce");
1135 ///
1136 /// let mut buf = String::new();
1137 /// for frag in queue.fragments(PartialHandling::Emit) {
1138 /// match frag {
1139 /// Fragment::Str(s) => buf.push_str(s),
1140 /// Fragment::Char(c) => buf.push(c),
1141 /// Fragment::Incomplete => buf.push_str("<<incomplete>>"),
1142 /// }
1143 /// }
1144 /// assert_eq!(buf, "hello <<incomplete>>");
1145 /// ```
1146 ///
1147 /// When `PartialHandling::Ignore` is passed, `Fragment::Incomplete` won't
1148 /// be emitted even if the queue contains trailing incomplete character.
1149 ///
1150 /// ```
1151 /// use str_queue::{Fragment, PartialHandling, StrQueue};
1152 ///
1153 /// // Note that `\xce` can appear as a first byte of valid UTF-8 sequence.
1154 /// let queue = StrQueue::from(b"hello \xce");
1155 ///
1156 /// let mut buf = String::new();
1157 /// for frag in queue.fragments(PartialHandling::Ignore) {
1158 /// match frag {
1159 /// Fragment::Str(s) => buf.push_str(s),
1160 /// Fragment::Char(c) => buf.push(c),
1161 /// Fragment::Incomplete => unreachable!("`PartialHandling::Ignore` is specified"),
1162 /// }
1163 /// }
1164 /// assert_eq!(buf, "hello ");
1165 /// ```
1166 ///
1167 /// Note that `StrQueue` will immediately replace non-incomplete invalid
1168 /// bytes (such as `\xff` and `\xce\xff`).
1169 /// Such already-replaced bytes will be printed as `U+FFFD` even if
1170 /// `PartialHandling::Ignore` is specified.
1171 ///
1172 /// ```
1173 /// use str_queue::{Fragment, PartialHandling, StrQueue};
1174 ///
1175 /// // Note that valid UTF-8 sequences can start with `\xf0`, but
1176 /// // never start with `\xf0\xf0`.
1177 /// // So, the first `\xf0` is immediately replaced with U+FFFD, and the
1178 /// // second `\xf0` is considered as a prefix of an incomplete character.
1179 /// let queue = StrQueue::from(b"hello \xf0\xf0");
1180 ///
1181 /// let mut buf = String::new();
1182 /// for frag in queue.fragments(PartialHandling::Emit) {
1183 /// match frag {
1184 /// Fragment::Str(s) => buf.push_str(s),
1185 /// Fragment::Char(c) => buf.push(c),
1186 /// Fragment::Incomplete => buf.push_str("<<incomplete>>"),
1187 /// }
1188 /// }
1189 /// assert_eq!(buf, "hello \u{FFFD}<<incomplete>>");
1190 /// ```
1191 ///
1192 /// ```
1193 /// use str_queue::{Fragment, PartialHandling, StrQueue};
1194 ///
1195 /// // Note that valid UTF-8 sequences can start with `\xf0`, but
1196 /// // never start with `\xf0\xf0`.
1197 /// // So, the first `\xf0` is immediately replaced with U+FFFD, and the
1198 /// // second `\xf0` is considered as a prefix of an incomplete character.
1199 /// let queue = StrQueue::from(b"hello \xf0\xf0");
1200 ///
1201 /// let mut buf = String::new();
1202 /// for frag in queue.fragments(PartialHandling::Ignore) {
1203 /// match frag {
1204 /// Fragment::Str(s) => buf.push_str(s),
1205 /// Fragment::Char(c) => buf.push(c),
1206 /// Fragment::Incomplete => unreachable!("`PartialHandling::Ignore` is specified"),
1207 /// }
1208 /// }
1209 /// // Note that the first `\xf0` is replaced with `U+FFFD`.
1210 /// assert_eq!(buf, "hello \u{FFFD}");
1211 /// ```
1212 #[inline]
1213 #[must_use]
1214 pub fn fragments(&self, partial_handling: PartialHandling) -> Fragments<'_> {
1215 self.range_fragments(.., partial_handling)
1216 }
1217
1218 /// Returns the fragments iterator for the range.
1219 ///
1220 /// # Panics
1221 ///
1222 /// Panics if the start index of the range does not lie on UTF-8 sequence boundary.
1223 ///
1224 /// # Examples
1225 ///
1226 /// ```
1227 /// use str_queue::{Fragment, PartialHandling, StrQueue};
1228 ///
1229 /// let queue = StrQueue::from("alpha\u{03B1}");
1230 ///
1231 /// assert_eq!(
1232 /// queue.range_fragments(3..6, PartialHandling::Emit).to_string(),
1233 /// "ha\u{FFFD}"
1234 /// );
1235 /// assert_eq!(
1236 /// queue.range_fragments(3..6, PartialHandling::Ignore).to_string(),
1237 /// "ha"
1238 /// );
1239 /// ```
1240 #[inline]
1241 #[must_use]
1242 pub fn range_fragments<R>(&self, range: R, partial_handling: PartialHandling) -> Fragments<'_>
1243 where
1244 R: RangeBounds<usize>,
1245 {
1246 Fragments::new(self, range, partial_handling)
1247 }
1248
1249 /// Returns an object that implements [`Display`] for printing the content.
1250 ///
1251 /// # Examples
1252 ///
1253 /// ```
1254 /// use str_queue::StrQueue;
1255 /// use str_queue::PartialHandling::{Emit, Ignore};
1256 ///
1257 /// let mut queue = StrQueue::from(b"alpha->\xce");
1258 /// assert_eq!(queue.display(Ignore).to_string(), "alpha->");
1259 /// assert_eq!(queue.display(Emit).to_string(), "alpha->\u{FFFD}");
1260 ///
1261 /// queue.push_bytes(b"\xb1");
1262 /// assert_eq!(queue.display(Ignore).to_string(), "alpha->\u{03B1}");
1263 /// assert_eq!(queue.display(Emit).to_string(), "alpha->\u{03B1}");
1264 /// ```
1265 ///
1266 /// [`Display`]: `fmt::Display`
1267 #[inline]
1268 #[must_use]
1269 pub fn display(&self, partial_handling: PartialHandling) -> Display<'_> {
1270 Display::new(self, partial_handling)
1271 }
1272}
1273
1274impl From<&str> for StrQueue {
1275 #[inline]
1276 fn from(s: &str) -> Self {
1277 let mut this = Self::with_capacity(s.len());
1278 this.push_str(s);
1279 this
1280 }
1281}
1282
1283impl From<&[u8]> for StrQueue {
1284 #[inline]
1285 fn from(s: &[u8]) -> Self {
1286 let mut this = Self::with_capacity(s.len());
1287 this.push_bytes(s);
1288 this
1289 }
1290}
1291
1292impl<const N: usize> From<&[u8; N]> for StrQueue {
1293 #[inline]
1294 fn from(s: &[u8; N]) -> Self {
1295 Self::from(&s[..])
1296 }
1297}
1298
1299impl hash::Hash for StrQueue {
1300 fn hash<H: hash::Hasher>(&self, state: &mut H) {
1301 self.inner.hash(state);
1302 }
1303}
1304
1305/// Handling of suffix bytes of a partial (incomplete) character.
1306#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1307pub enum PartialHandling {
1308 /// Suffix bytes for an incomplete character will be ignored.
1309 Ignore,
1310 /// Suffix bytes for an incomplete character will be visible as
1311 /// `U+FFFD REPLACEMENT CHARACTER`.
1312 Emit,
1313}
1314
1315impl PartialHandling {
1316 /// Returns true if `self` is `Emit`.
1317 #[inline]
1318 #[must_use]
1319 fn is_emit(self) -> bool {
1320 self == Self::Emit
1321 }
1322
1323 /// Returns true if `self` is `Ignore`.
1324 #[inline]
1325 #[must_use]
1326 fn is_ignore(self) -> bool {
1327 self == Self::Ignore
1328 }
1329}
1330
1331/// Helper struct for printing [`StrQueue`].
1332///
1333/// Created by [`StrQueue::display`] method.
1334#[derive(Debug)]
1335pub struct Display<'a> {
1336 /// Queue.
1337 queue: &'a StrQueue,
1338 /// Whether an incomplete character (replaced with U+FFFD) should be emitted.
1339 partial_handling: PartialHandling,
1340}
1341
1342impl<'a> Display<'a> {
1343 /// Creates a new `Display`.
1344 #[inline]
1345 #[must_use]
1346 fn new(queue: &'a StrQueue, partial_handling: PartialHandling) -> Self {
1347 Self {
1348 queue,
1349 partial_handling,
1350 }
1351 }
1352}
1353
1354impl fmt::Display for Display<'_> {
1355 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1356 self.queue
1357 .fragments(self.partial_handling)
1358 .try_for_each(|frag| frag.fmt(f))
1359 }
1360}
1361
1362/// A line popped from [`StrQueue`] using [`pop_line`][`StrQueue::pop_line`] method.
1363///
1364/// Note that it is unspecified whether the line will be removed from the queue,
1365/// if the `PoppedLine` value is not dropped while the borrow it holds expires
1366/// (e.g. due to [`core::mem::forget`]).
1367#[derive(Debug)]
1368pub struct PoppedLine<'a> {
1369 /// Queue.
1370 queue: &'a mut StrQueue,
1371 /// Line length.
1372 ///
1373 /// A complete line cannot be empty since it has a line break.
1374 line_len: NonZeroUsize,
1375}
1376
1377impl<'a> PoppedLine<'a> {
1378 /// Returns the chars range for the line.
1379 #[inline]
1380 #[must_use]
1381 pub fn to_chars_range(&self) -> CharsRange<'_> {
1382 self.queue.chars_range(..self.line_len.get())
1383 }
1384
1385 /// Returns the bytes range for the line.
1386 #[inline]
1387 #[must_use]
1388 pub fn to_bytes_range(&self) -> BytesRange<'_> {
1389 self.queue.bytes_range(..self.line_len.get())
1390 }
1391
1392 /// Returns the length of the line.
1393 #[inline]
1394 #[must_use]
1395 pub fn len(&self) -> usize {
1396 self.line_len.get()
1397 }
1398
1399 /// Returns whether the line is empty, i.e. **always returns false**.
1400 ///
1401 /// A complete line to be removed cannot be empty since it has a line break.
1402 #[inline]
1403 #[must_use]
1404 pub const fn is_empty(&self) -> bool {
1405 false
1406 }
1407}
1408
1409impl fmt::Display for PoppedLine<'_> {
1410 #[inline]
1411 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1412 self.to_chars_range().fmt(f)
1413 }
1414}
1415
1416impl core::ops::Drop for PoppedLine<'_> {
1417 #[inline]
1418 fn drop(&mut self) {
1419 self.queue.inner.drain(..self.line_len.get());
1420 }
1421}
1422
1423impl PartialEq for PoppedLine<'_> {
1424 #[inline]
1425 fn eq(&self, other: &PoppedLine<'_>) -> bool {
1426 self.to_bytes_range().eq(&other.to_bytes_range())
1427 }
1428}
1429
1430impl Eq for PoppedLine<'_> {}
1431
1432impl PartialOrd for PoppedLine<'_> {
1433 #[inline]
1434 fn partial_cmp(&self, rhs: &PoppedLine<'_>) -> Option<Ordering> {
1435 self.to_bytes_range().partial_cmp(&rhs.to_bytes_range())
1436 }
1437}
1438
1439impl Ord for PoppedLine<'_> {
1440 #[inline]
1441 fn cmp(&self, rhs: &PoppedLine<'_>) -> Ordering {
1442 self.to_bytes_range().cmp(&rhs.to_bytes_range())
1443 }
1444}
1445
1446impl PartialEq<str> for PoppedLine<'_> {
1447 #[inline]
1448 fn eq(&self, other: &str) -> bool {
1449 self.to_bytes_range().eq(other.as_bytes())
1450 }
1451}
1452
1453impl PartialOrd<str> for PoppedLine<'_> {
1454 #[inline]
1455 fn partial_cmp(&self, rhs: &str) -> Option<Ordering> {
1456 self.to_bytes_range().partial_cmp(rhs.as_bytes())
1457 }
1458}
1459
1460impl PartialEq<PoppedLine<'_>> for str {
1461 #[inline]
1462 fn eq(&self, other: &PoppedLine<'_>) -> bool {
1463 other.to_bytes_range().eq(self.as_bytes())
1464 }
1465}
1466
1467impl PartialOrd<PoppedLine<'_>> for str {
1468 #[inline]
1469 fn partial_cmp(&self, rhs: &PoppedLine<'_>) -> Option<Ordering> {
1470 rhs.to_bytes_range()
1471 .partial_cmp(self.as_bytes())
1472 .map(Ordering::reverse)
1473 }
1474}
1475
1476impl PartialEq<&str> for PoppedLine<'_> {
1477 #[inline]
1478 fn eq(&self, other: &&str) -> bool {
1479 self.eq(*other)
1480 }
1481}
1482
1483impl PartialOrd<&str> for PoppedLine<'_> {
1484 #[inline]
1485 fn partial_cmp(&self, rhs: &&str) -> Option<Ordering> {
1486 self.partial_cmp(*rhs)
1487 }
1488}
1489
1490impl PartialEq<PoppedLine<'_>> for &str {
1491 #[inline]
1492 fn eq(&self, other: &PoppedLine<'_>) -> bool {
1493 other.eq(*self)
1494 }
1495}
1496
1497impl PartialOrd<PoppedLine<'_>> for &str {
1498 #[inline]
1499 fn partial_cmp(&self, rhs: &PoppedLine<'_>) -> Option<Ordering> {
1500 rhs.partial_cmp(*self).map(Ordering::reverse)
1501 }
1502}
1503
1504/// A state after popping a fragment from a queue.
1505#[derive(Debug, Clone, Copy)]
1506enum StateAfterPoppingFragment {
1507 /// The former buffer is partially consumed.
1508 Former {
1509 /// The unused size in the former buffer at the tail.
1510 ///
1511 /// This must be less than 4 since a complete character is at most
1512 /// 4 bytes in UTF-8.
1513 rest: u8,
1514 },
1515 /// The former is completely consumed and the latter is partially consumed.
1516 Char {
1517 /// The consumed size in the latter buffer at the head.
1518 ///
1519 /// This must be less than 4 since a complete character is at most
1520 /// 4 bytes in UTF-8.
1521 latter_consumed: u8,
1522 },
1523 /// The latter buffer is partially consumed.
1524 Latter {
1525 /// The unused size in the latter buffer at the tail.
1526 ///
1527 /// This must be less than 4 since a complete character is at most
1528 /// 4 bytes in UTF-8.
1529 rest: u8,
1530 },
1531 /// All bytes are consumed.
1532 ///
1533 /// This variant indicates that the buffer is currently not yet empty since
1534 /// the buffer has a trailing incomplete character.
1535 AllConsumed,
1536}
1537
1538/// A fragment popped from [`StrQueue`] using [`pop_fragment`][`StrQueue::pop_fragment`] method.
1539///
1540/// Note that it is unspecified whether the line will be removed from the queue,
1541/// if the `PoppedFragment` value is not dropped while the borrow it holds expires
1542/// (e.g. due to [`core::mem::forget`]).
1543#[derive(Debug)]
1544pub struct PoppedFragment<'a> {
1545 /// Queue.
1546 queue: &'a mut StrQueue,
1547 /// State after popping fragment.
1548 after_state: StateAfterPoppingFragment,
1549}
1550
1551impl<'a> PoppedFragment<'a> {
1552 /// Returns the fragment for the line.
1553 #[inline]
1554 #[must_use]
1555 pub fn to_fragment(&self) -> Fragment<'_> {
1556 use StateAfterPoppingFragment::*;
1557
1558 match self.after_state {
1559 Former { rest } => {
1560 let (former, _) = self.queue.inner.as_slices();
1561 let len = former.len() - usize::from(rest);
1562 let s = str::from_utf8(&former[..len])
1563 .expect("[consistency] the range must be valid UTF-8 string");
1564 Fragment::Str(s)
1565 }
1566 Char { latter_consumed } => {
1567 let (former, latter) = self.queue.inner.as_slices();
1568 let (c, len) = utf8::take_char(
1569 former
1570 .iter()
1571 .chain(&latter[..usize::from(latter_consumed)])
1572 .copied(),
1573 )
1574 .expect(
1575 "[consistency] it should be already validated \
1576 that a complete character is available",
1577 );
1578 debug_assert_eq!(
1579 usize::from(len),
1580 former.len() + usize::from(latter_consumed),
1581 "[consistency] a character lay on the specified area in the buffers"
1582 );
1583 Fragment::Char(c)
1584 }
1585 Latter { rest } => {
1586 let (_, latter) = self.queue.inner.as_slices();
1587 let len = latter.len() - usize::from(rest);
1588 let s = str::from_utf8(&latter[..len])
1589 .expect("[consistency] the range must be valid UTF-8 string");
1590 Fragment::Str(s)
1591 }
1592 AllConsumed => Fragment::Incomplete,
1593 }
1594 }
1595
1596 /// Returns the chars range for the line.
1597 #[inline]
1598 #[must_use]
1599 pub fn to_chars_range(&self) -> CharsRange<'_> {
1600 use StateAfterPoppingFragment::*;
1601
1602 match self.after_state {
1603 Former { rest } => {
1604 let (former, _) = self.queue.inner.as_slices();
1605 let len = former.len() - usize::from(rest);
1606 self.queue.chars_range(..len)
1607 }
1608 Char { latter_consumed } => {
1609 let (former, _) = self.queue.inner.as_slices();
1610 debug_assert!(
1611 former.len() < 4,
1612 "[consistency] the former buffer must not have a complete character"
1613 );
1614 let end = former.len() + usize::from(latter_consumed);
1615 self.queue.chars_range(..end)
1616 }
1617 Latter { rest } => {
1618 let (former, latter) = self.queue.inner.as_slices();
1619 debug_assert!(
1620 former.is_empty(),
1621 "[consistency] the former buffer must have been completely consumed"
1622 );
1623 let len = latter.len() - usize::from(rest);
1624 self.queue.chars_range(..len)
1625 }
1626 AllConsumed => self.queue.chars_range(..),
1627 }
1628 }
1629
1630 /// Returns the bytes range for the line.
1631 #[inline]
1632 #[must_use]
1633 pub fn to_bytes_range(&self) -> BytesRange<'_> {
1634 self.to_chars_range().into()
1635 }
1636
1637 /// Returns the length of the line.
1638 #[inline]
1639 #[must_use]
1640 pub fn len(&self) -> usize {
1641 use StateAfterPoppingFragment::*;
1642
1643 match self.after_state {
1644 Former { rest } => {
1645 let (former, _) = self.queue.inner.as_slices();
1646 former.len() - usize::from(rest)
1647 }
1648 Char { latter_consumed } => {
1649 let (former, _) = self.queue.inner.as_slices();
1650 debug_assert!(
1651 former.len() < 4,
1652 "[consistency] the former buffer must not have a complete character"
1653 );
1654 former.len() + usize::from(latter_consumed)
1655 }
1656 Latter { rest } => {
1657 let (former, latter) = self.queue.inner.as_slices();
1658 debug_assert!(
1659 former.is_empty(),
1660 "[consistency] the former buffer must have been completely consumed"
1661 );
1662 latter.len() - usize::from(rest)
1663 }
1664 AllConsumed => self.queue.len(),
1665 }
1666 }
1667
1668 /// Returns whether the line is empty, i.e. **always returns false**.
1669 ///
1670 /// A complete line to be removed cannot be empty since it has a line break.
1671 #[inline]
1672 #[must_use]
1673 pub const fn is_empty(&self) -> bool {
1674 false
1675 }
1676}
1677
1678impl fmt::Display for PoppedFragment<'_> {
1679 #[inline]
1680 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1681 self.to_fragment().fmt(f)
1682 }
1683}
1684
1685impl core::ops::Drop for PoppedFragment<'_> {
1686 #[inline]
1687 fn drop(&mut self) {
1688 self.queue.inner.drain(..self.len());
1689 }
1690}
1691
1692impl PartialEq for PoppedFragment<'_> {
1693 #[inline]
1694 fn eq(&self, other: &PoppedFragment<'_>) -> bool {
1695 self.to_bytes_range().eq(&other.to_bytes_range())
1696 }
1697}
1698
1699impl Eq for PoppedFragment<'_> {}
1700
1701impl PartialOrd for PoppedFragment<'_> {
1702 #[inline]
1703 fn partial_cmp(&self, rhs: &PoppedFragment<'_>) -> Option<Ordering> {
1704 self.to_bytes_range().partial_cmp(&rhs.to_bytes_range())
1705 }
1706}
1707
1708impl Ord for PoppedFragment<'_> {
1709 #[inline]
1710 fn cmp(&self, rhs: &PoppedFragment<'_>) -> Ordering {
1711 self.to_bytes_range().cmp(&rhs.to_bytes_range())
1712 }
1713}
1714
1715impl PartialEq<str> for PoppedFragment<'_> {
1716 #[inline]
1717 fn eq(&self, other: &str) -> bool {
1718 self.to_bytes_range().eq(other.as_bytes())
1719 }
1720}
1721
1722impl PartialOrd<str> for PoppedFragment<'_> {
1723 #[inline]
1724 fn partial_cmp(&self, rhs: &str) -> Option<Ordering> {
1725 self.to_bytes_range().partial_cmp(rhs.as_bytes())
1726 }
1727}
1728
1729impl PartialEq<PoppedFragment<'_>> for str {
1730 #[inline]
1731 fn eq(&self, other: &PoppedFragment<'_>) -> bool {
1732 other.to_bytes_range().eq(self.as_bytes())
1733 }
1734}
1735
1736impl PartialOrd<PoppedFragment<'_>> for str {
1737 #[inline]
1738 fn partial_cmp(&self, rhs: &PoppedFragment<'_>) -> Option<Ordering> {
1739 rhs.to_bytes_range()
1740 .partial_cmp(self.as_bytes())
1741 .map(Ordering::reverse)
1742 }
1743}
1744
1745impl PartialEq<&str> for PoppedFragment<'_> {
1746 #[inline]
1747 fn eq(&self, other: &&str) -> bool {
1748 self.eq(*other)
1749 }
1750}
1751
1752impl PartialOrd<&str> for PoppedFragment<'_> {
1753 #[inline]
1754 fn partial_cmp(&self, rhs: &&str) -> Option<Ordering> {
1755 self.partial_cmp(*rhs)
1756 }
1757}
1758
1759impl PartialEq<PoppedFragment<'_>> for &str {
1760 #[inline]
1761 fn eq(&self, other: &PoppedFragment<'_>) -> bool {
1762 other.eq(*self)
1763 }
1764}
1765
1766impl PartialOrd<PoppedFragment<'_>> for &str {
1767 #[inline]
1768 fn partial_cmp(&self, rhs: &PoppedFragment<'_>) -> Option<Ordering> {
1769 rhs.partial_cmp(*self).map(Ordering::reverse)
1770 }
1771}
1772
1773/// Workaround to implement `core::ops::Bound::cloned()`.
1774///
1775/// `core::ops::Bound::cloned()` will be stabilized since Rust 1.55.0.
1776/// Once Rust 1.55.0 is released and MSRV of this crate is bumped, this trait
1777/// can be removed safely.
1778///
1779/// See <https://github.com/rust-lang/rust/issues/61356>.
1780trait BoundExt<T> {
1781 /// Maps a `Bound<&T>` to a `Bound<T>` by cloning the contents of the bound.
1782 fn cloned(self) -> Bound<T>;
1783}
1784
1785impl<T: Clone> BoundExt<T> for Bound<&'_ T> {
1786 fn cloned(self) -> Bound<T> {
1787 match self {
1788 Bound::Included(v) => Bound::Included(v.clone()),
1789 Bound::Excluded(v) => Bound::Excluded(v.clone()),
1790 Bound::Unbounded => Bound::Unbounded,
1791 }
1792 }
1793}