Crate str_queue[−][src]
Expand description
A queue for a string.
Summary
StrQueue
is a queue for UTF-8 sequences.
Strings can be pushed into StrQueue
, characters can be popped from the
queue, and the queue can be printed or converted into a string.
Details
Non-contiguous
StrQueue
does not guarantee that the content is stored on a contiguous
memory region. As of writing this document, StrQueue
internally uses a
ring buffer.
Push
StrQueue
accepts not only strings to be pushed, but also arbitrary bytes.
When bytes (including valid UTF-8 strings) are pushed, the things below
(theoretically) happen in order:
- Bytes are appended to the internal buffer.
- Internal buffers are validated.
- If the buffer has incomplete bytes at the end of the buffer,
they are preserved (at least the until the next bytes are added).
- “Incomplete bytes” here is byte sequence which can be valid UTF-8 sequence if appropriate bytes are appended.
- Other ill-formed bytes than that are replaced with
U+FFFD REPLACEMENT CHARACTER
using the same rule asString::from_utf8_lossy
.
- If the buffer has incomplete bytes at the end of the buffer,
they are preserved (at least the until the next bytes are added).
Pop
Pop operations are basically performed to characters, rather than raw bytes.
For example, StrQueue::pop_char
pops the first character, not the first byte.
This principle helps the queue to keep the internal bytes valid as UTF-8 string.
Conversion
When converting a queue into a string, caller can choose how to handle the
possible trailing incomplete bytes.
PartialHandling::Ignore
lets methods ignore such incomplete bytes (if
exist), and PartialHandling::Emit
lets methods emit them as a U+FFFD REPLACEMENT CHARACTER
.
Range
This crate provides adaptors for subrange access: BytesRange
and
CharsRange
. Subrange adaptor types plays a similar role as &str
for
String
: they are views to the subrange of the underlying StrQueue
.
BytesRange
can point to arbitrary subrange.
CharsRange
can only point to a subrange that are valid UTF-8 string and
the last possibly incomplete character (i.e. the same condition as
StrQueue
.
Usage
Creation
Default queue created by StrQueue::new
is empty.
use str_queue::{PartialHandling, StrQueue}; let queue = StrQueue::new(); assert!(queue.display(PartialHandling::Emit).to_string().is_empty());
A queue can be created with initial contents by StrQueue::from
.
use str_queue::{PartialHandling, StrQueue}; let queue = StrQueue::from("hello"); assert_eq!(queue.display(PartialHandling::Emit).to_string(), "hello");
use str_queue::{PartialHandling, StrQueue}; let queue = StrQueue::from(b"he\xf0llo\xce"); assert_eq!(queue.display(PartialHandling::Emit).to_string(), "he\u{FFFD}llo\u{FFFD}");
Push
Bytes and string can be pushed.
use str_queue::{PartialHandling, StrQueue}; let mut queue = StrQueue::new(); queue.push_str("hello"); assert_eq!(queue.display(PartialHandling::Emit).to_string(), "hello"); queue.push_bytes(b" world"); assert_eq!(queue.display(PartialHandling::Emit).to_string(), "hello world");
Pop
The first characters can be popped using StrQueue::pop_char
.
use str_queue::StrQueue; let mut queue = StrQueue::from(b"ab\xf0"); assert_eq!(queue.pop_char(), Some('a')); assert_eq!(queue.pop_char(), Some('b')); // Incomplete bytes are simply ignored as they are not a character. assert_eq!(queue.pop_char(), None);
The first line can be popped using StrQueue::pop_line
.
use str_queue::StrQueue; // Note that the last "world\r" is not considered as a complete line // since the line can be finally "world\r" or "world\r\n". let mut queue = StrQueue::from("Hello\nworld\r\nGoodbye\rworld\r"); // The popped line can be dropped. queue.pop_line(); // The popped line can be accessed. assert_eq!(queue.pop_line().map(|v| v.to_string()).as_deref(), Some("world\r\n")); assert_eq!(queue.pop_line().map(|v| v.to_string()).as_deref(), Some("Goodbye\r")); assert_eq!(queue.pop_line().map(|v| v.to_string()).as_deref(), None); assert_eq!(queue.chars_range(..), "world\r");
Ranges
Bytes ranges can be created by StrQueue::bytes_range
method.
use str_queue::StrQueue; let queue = StrQueue::from("alpha\u{03B1}beta\u{03B2}"); let bytes = queue.bytes_range(6..12); assert_eq!(bytes, b"\xb1beta\xce"[..]);
Chars ranges can be created by StrQueue::chars_range
method.
CharsRange
implements Display
and
ToString
traits, since the it is guaranteed
to have a valid string as a prefix (with possibly incomplete character as
a suffix).
use str_queue::StrQueue; let queue = StrQueue::from("alpha\u{03B1}beta\u{03B2}"); let range = queue.chars_range(7..); assert_eq!(range, "beta\u{03B2}"); assert_eq!(range.to_string(), "beta\u{03B2}");
Subranges can be created from ranges.
use str_queue::StrQueue; let queue = StrQueue::from("Hello world"); let bytes = queue.bytes_range(6..); assert_eq!(bytes, b"world"[..]); let subrange = bytes.range(1..4); assert_eq!(subrange, b"orl"[..]);
use str_queue::StrQueue; let queue = StrQueue::from("Hello world"); let range = queue.chars_range(6..); assert_eq!(range, "world"); let subrange = range.range(1..4); assert_eq!(subrange, "orl");
Conversion
Note that StrQueue
does not guarantee the content is stored on a
contiguous memory region.
So, you cannot get the content string as a single &str
without paying
additional cost.
Display
StrQueue::display
returns a helper struct which implements
core::fmt::Display
. It can be written to a formatter or converted to
a string using .to_string()
.
To create String
, use .to_string()
.
use str_queue::{PartialHandling, StrQueue}; let queue = StrQueue::from("hello"); let s: String = queue.display(PartialHandling::Emit).to_string(); assert_eq!(s, "hello");
To write the string into a writer, use the return value directly.
use core::fmt::Write as _; use str_queue::{PartialHandling, StrQueue}; let queue = StrQueue::from("hello"); // `String` implements `core::fmt::Write`, and can be used for `write!()`. let mut buf = String::new(); write!(buf, "{}", queue.display(PartialHandling::Emit)); assert_eq!(buf, "hello");
Fragments
StrQueue::fragments
returns an iterator of Fragment
s, which can hold
a substring slices and a characters.
use str_queue::{Fragment, PartialHandling, StrQueue}; // Note that `\xce` can appear as a first byte of valid UTF-8 sequence. let queue = StrQueue::from(b"hello \xce"); let mut buf = String::new(); for frag in queue.fragments(PartialHandling::Emit) { match frag { Fragment::Str(s) => buf.push_str(s), Fragment::Char(c) => buf.push(c), Fragment::Incomplete => buf.push_str("<<incomplete>>"), } } assert_eq!(buf, "hello <<incomplete>>");
Characters
StrQueue::chars
and StrQueue::into_chars
return an iterator of char
s.
StrQueue::chars
does not consume the queue.
use str_queue::{PartialHandling, StrQueue}; let queue = StrQueue::from("hello"); let mut chars = queue.chars(PartialHandling::Emit); assert_eq!(chars.next(), Some('h')); assert_eq!(chars.next(), Some('e')); assert_eq!(chars.next(), Some('l')); assert_eq!(chars.next(), Some('l')); assert_eq!(chars.next(), Some('o')); assert_eq!(chars.next(), None); // `StrQueue::chars()` does not consume the queue, so it can be used here. assert_eq!( queue.chars(PartialHandling::Emit).collect::<String>(), "hello" );
StrQueue::into_chars
consumes the queue.
use str_queue::{PartialHandling, StrQueue}; let queue = StrQueue::from("hello"); let mut chars = queue.into_chars(PartialHandling::Emit); assert_eq!(chars.next(), Some('h')); assert_eq!(chars.next(), Some('e')); assert_eq!(chars.next(), Some('l')); assert_eq!(chars.next(), Some('l')); assert_eq!(chars.next(), Some('o')); assert_eq!(chars.next(), None); // `queue` is no longer available, as it is consumeb dy `queue.into_chars()`.
Structs
Subrange of a StrQueue
.
Iterator of characters in a StrQueue
.
Subrange of a StrQueue
.
A line popped from CharsRange
using pop_line
method.
Helper struct for printing StrQueue
.
Iterator of content fragments of StrQueue
, created by StrQueue::fragments
.
Iterator of characters in a StrQueue
.
A fragment popped from StrQueue
using pop_fragment
method.
Queue for a string.
Enums
Handling of suffix bytes of a partial (incomplete) character.