Crate any_rope

source ·
Expand description

AnyRope is an arbitrary data rope for Rust.

AnyRope’s Rope<M> contains elements M that implement Measurable, a trait that assigns an arbitrary “measure” to each element, through the measure() function. AnyRope can then use these “measures” to retrieve and iterate over elements in any given “measure” from the beginning of the Rope<M>.

Keep in mind that the “measure” does not correspond to the actual size of a type in bits or bytes, but is instead decided by the implementor, and can be whatever value they want.

The library is made up of four main components:

A Basic Example

Let’s say we want create a tagging system that will be applied to text, in which the tags either tell you to print normally, print in red, underline, or skip:

use std::fs::File;
use std::io::{BufReader, BufWriter};
use any_rope::{Rope, Measurable};

// A simple tag structure that our program can understand.
#[derive(Clone, Copy, PartialEq, Eq)]
enum Tag {
    // The `usize` in here represents an amount of characters that won't change
    // the color of the text.

impl Measurable for Tag {
    type Measure = usize;

    fn measure(&self) -> Self::Measure {
        match self {
            // The coloring tags are only meant to color, not to "move forward".
            Tag::InRed | Tag::UnderLine | Tag::Normal => 0,
            // The Skip tag represents an amount of characters in which no
            // tags are applied.
            Tag::Skip(amount) => *amount
use Tag::*;

// An `&str` that will be colored.
let my_str = "This word will be red!";

// Here's what this means:
// - Skip 5 characters;
// - Change the color to red;
// - Start underlining;
// - Skip 4 characters;
// - Change the rendering back to normal.
let my_tagger = Rope::from_slice(&[Skip(5), InRed, UnderLine, Skip(4), Normal]);
// Do note that Tag::Skip only represents characters because we are also iterating
// over a `Chars` iterator, and have chosen to do so.

let mut tags_iter = my_tagger.iter().peekable();
for (cur_index, ch) in my_str.chars().enumerate() {
    // The while let loop here is a useful way to activate all tags within the same
    // character. Note the sequence of [.., InRed, UnderLine, ..], both of which have
    // a measure of 0. This means that both would be triggered before moving on to the next
    // character.
    while let Some((index, tag)) = tags_iter.peek() {
        // The returned index is always the measure where an element began. In this
        // case, `tags_iter.peek()` would return `Some((0, Skip(5)))`, and then
        // `Some((5, InRed))`.
        if *index == cur_index {
        } else {

    print!("{}", ch);

An example can be found in the examples directory, detailing a “search and replace” functionality for Rope<M>.

Low-level APIs

AnyRope also provides access to some of its low-level APIs, enabling client code to efficiently work with a Rope<M>’s data and implement new functionality. The most important of those API’s are:

As a reminder, if you notice similarities with the AnyRope crate, it is because this is a heavily modified fork of it.




  • AnyRope’s error type.


  • A trait defining a comparison that must panic if there is ever ambiguity about the ordering in a given struct.
  • A object that has a user defined size, that can be interpreted by a Rope<M>.


Type Aliases

  • AnyRope’s result type.