3 releases
0.1.0 | Apr 10, 2019 |
---|---|
0.1.0-rc1 | Apr 9, 2019 |
#241 in Parser tooling
46KB
600 lines
Char-circle
A circular buffer for strings and traits for in-place string transforms.
This crate provides two key types: the CharCircle
struct and the StringTransform
trait. The CharCircle
is a circular buffer specialized for UTF-8 strings, and the StringTransform
trait builds upon it to provide a character-oriented API for in-place string transformations. In short, StringTransform
allows you to implement transformations as iterator adaptors, with copy-on-write optimizations in mind.
Documentation
Usage
Char-circle is a pure Rust library. To use it, simply add it to your Cargo.toml
:
[dependencies]
char-circle = "0.1.0"
lib.rs
:
A circular buffer for strings and traits for in-place string transforms.
This crate provides two key types: the CharCircle
struct and the
StringTransform
trait. The CharCircle
is a circular buffer
specialized for UTF-8 strings, and the StringTransform
trait builds upon
it to provide a character-oriented API for in-place string transformations.
In short, StringTransform
allows you to implement transformations as
iterator adaptors, with copy-on-write optimizations in mind.
The CharCircle
uses internal mutability. This enables its contents to be
consumed by an external iterator, Chars
. As a consequence, the
CharCircle
is not Sync
. It is implemented as a RefCell
around the
RawCircle
, which has a nearly identical API, uses external mutability,
is thread-safe, and does not provide a consuming iterator.
The StringTransform
trait is implemented by factories of iterator
adaptors. For simple cases, the SimpleTransform
trait provides an
alternative that is implemented directly by the adaptor.
Example: To Uppercase
Transforms which don't require configuration are most easily implemented
with SimpleTransform
.
Here we implement an uppercase transform:
use char_circle::{SimpleTransform, Chars};
// Step 1: Define the transform as an iterator adaptor.
struct ToUpper<I>(I);
impl<I> Iterator for ToUpper<I> where I: Iterator<Item=char> {
type Item = char;
fn next(&mut self) -> Option<char> {
self.0.next().map(|ch| ch.to_ascii_uppercase())
}
}
// Step 2: Define a constructor for the adaptor with `SimpleTransform`.
impl<'a> SimpleTransform<'a> for ToUpper<Chars<'a>> {
fn transform_chars(chars: Chars<'a>) -> Self {
ToUpper(chars)
}
}
// Step 3: Profit!
let s = "can you hear me in the back?";
let s = ToUpper::transform(s);
assert_eq!(&s, "CAN YOU HEAR ME IN THE BACK?");
Example: Caesar Cipher
Transforms that need to be configured should define a factory which
implements StringTransform
.
Here we implement a Caesar cipher configured with its key:
use char_circle::{StringTransform, Chars};
// Step 1: Define the transform as an iterator adaptor.
struct CaesarCipherIter<I> {
inner: I,
key: i32,
}
impl<I> Iterator for CaesarCipherIter<I> where I: Iterator<Item=char> {
type Item = char;
fn next(&mut self) -> Option<char> {
let plaintext = self.inner.next()?;
let ciphertext = plaintext as i32 + self.key;
let ciphertext = std::char::from_u32(ciphertext as u32).unwrap();
Some(ciphertext)
}
}
// Step 2: Define a factory for the adaptor with `StringTransform`.
struct CaesarCipher(i32);
impl<'a> StringTransform<'a> for CaesarCipher {
type Iter = CaesarCipherIter<Chars<'a>>;
fn transform_chars(&self, chars: Chars<'a>) -> Self::Iter {
CaesarCipherIter { inner: chars, key: self.0 }
}
}
// Step 3: Profit!
let encoder = CaesarCipher(8);
let decoder = CaesarCipher(-8);
let plaintext = "Veni, vidi, vici";
let ciphertext = encoder.transform(plaintext);
assert_eq!(&ciphertext, "^mvq4(~qlq4(~qkq");
let plaintext = decoder.transform(ciphertext);
assert_eq!(&plaintext, "Veni, vidi, vici");