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:

  1. Bytes are appended to the internal buffer.
  2. 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 as String::from_utf8_lossy.

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 Fragments, 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 chars.

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.

A line popped from StrQueue using pop_line method.

Queue for a string.

Enums

Content fragment of StrQueue, emitted by Fragments iterator.

Handling of suffix bytes of a partial (incomplete) character.