#circular #circular-buffer

char-circle

A circular buffer for strings and traits for in-place string transforms

3 releases

0.1.0 Apr 10, 2019
0.1.0-rc1 Apr 9, 2019

#241 in Parser tooling

MIT license

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

https://docs.rs/char-circle

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");

No runtime deps