use smallvec::alloc::string::String;
use core::{
iter::FromIterator,
ops::RangeBounds,
};
use alloc::{
sync::Arc,
vec::Vec,
};
use crate::{
crlf,
iter::{
Bytes,
Chars,
Chunks,
Lines,
},
rope_builder::RopeBuilder,
slice::{
end_bound_to_num,
start_bound_to_num,
RopeSlice,
},
str_utils::{
byte_to_char_idx,
byte_to_line_idx,
byte_to_utf16_surrogate_idx,
char_to_byte_idx,
char_to_line_idx,
line_to_byte_idx,
line_to_char_idx,
utf16_code_unit_to_char_idx,
},
tree::{
Count,
Node,
NodeChildren,
TextInfo,
MAX_BYTES,
},
};
#[derive(Clone)]
pub struct Rope {
pub(crate) root: Arc<Node>,
}
impl Rope {
#[inline]
pub fn new() -> Self { Rope { root: Arc::new(Node::new()) } }
#[inline]
#[allow(clippy::should_implement_trait)]
pub fn from_str(text: &str) -> Self { RopeBuilder::new().build_at_once(text) }
#[inline]
pub fn len_bytes(&self) -> usize { self.root.byte_count() }
#[inline]
pub fn len_chars(&self) -> usize { self.root.char_count() }
#[inline]
pub fn len_lines(&self) -> usize { self.root.line_break_count() + 1 }
#[inline]
pub fn len_utf16_cu(&self) -> usize {
let info = self.root.text_info();
(info.chars + info.utf16_surrogates) as usize
}
pub fn capacity(&self) -> usize {
let mut byte_count = 0;
for chunk in self.chunks() {
byte_count += chunk.len().max(MAX_BYTES);
}
byte_count
}
pub fn shrink_to_fit(&mut self) {
let mut node_stack = Vec::new();
let mut builder = RopeBuilder::new();
node_stack.push(self.root.clone());
*self = Rope::new();
loop {
if node_stack.is_empty() {
break;
}
if node_stack.last().unwrap().is_leaf() {
builder.append(node_stack.last().unwrap().leaf_text());
node_stack.pop();
}
else if node_stack.last().unwrap().child_count() == 0 {
node_stack.pop();
}
else {
let (_, next_node) = Arc::make_mut(node_stack.last_mut().unwrap())
.children_mut()
.remove(0);
node_stack.push(next_node);
}
}
*self = builder.finish();
}
#[inline]
pub fn insert(&mut self, char_idx: usize, text: &str) {
assert!(
char_idx <= self.len_chars(),
"Attempt to insert past end of Rope: insertion point {}, Rope length {}",
char_idx,
self.len_chars()
);
if text.len() > MAX_BYTES * 6 {
let text_rope = Rope::from_str(text);
let right = self.split_off(char_idx);
self.append(text_rope);
self.append(right);
}
else {
let mut text = text;
while !text.is_empty() {
let split_idx = crlf::find_good_split(
text.len() - (MAX_BYTES - 4).min(text.len()),
text.as_bytes(),
false,
);
let ins_text = &text[split_idx..];
text = &text[..split_idx];
self.insert_internal(char_idx, ins_text);
}
}
}
#[inline]
pub fn insert_char(&mut self, char_idx: usize, ch: char) {
assert!(
char_idx <= self.len_chars(),
"Attempt to insert past end of Rope: insertion point {}, Rope length {}",
char_idx,
self.len_chars()
);
let mut buf = [0u8; 4];
self.insert_internal(char_idx, ch.encode_utf8(&mut buf));
}
fn insert_internal(&mut self, char_idx: usize, ins_text: &str) {
let mut ins_text = ins_text;
let mut left_seam = false;
let root_info = self.root.text_info();
let (l_info, residual) = Arc::make_mut(&mut self.root).edit_chunk_at_char(
char_idx,
root_info,
|idx, cur_info, leaf_text| {
if idx == 0 && char_idx > 0 && ins_text.as_bytes()[0] == 0x0A {
left_seam = true;
ins_text = &ins_text[1..];
if ins_text.is_empty() {
return (cur_info, None);
}
}
let byte_idx = char_to_byte_idx(leaf_text, idx);
if (leaf_text.len() + ins_text.len()) <= MAX_BYTES {
let new_info = {
let mut info = cur_info + TextInfo::from_str(ins_text);
if byte_idx > 0 {
if leaf_text.as_bytes()[byte_idx - 1] == 0x0D
&& ins_text.as_bytes()[0] == 0x0A
{
info.line_breaks -= 1;
}
if byte_idx < leaf_text.len()
&& leaf_text.as_bytes()[byte_idx - 1] == 0x0D
&& leaf_text.as_bytes()[byte_idx] == 0x0A
{
info.line_breaks += 1;
}
}
if byte_idx < leaf_text.len()
&& *ins_text.as_bytes().last().unwrap() == 0x0D
&& leaf_text.as_bytes()[byte_idx] == 0x0A
{
info.line_breaks -= 1;
}
info
};
leaf_text.insert_str(byte_idx, ins_text);
(new_info, None)
}
else {
let r_text = leaf_text.insert_str_split(byte_idx, ins_text);
let l_text_info = TextInfo::from_str(&leaf_text);
if r_text.len() > 0 {
let r_text_info = TextInfo::from_str(&r_text);
(l_text_info, Some((r_text_info, Arc::new(Node::Leaf(r_text)))))
}
else {
(l_text_info, None)
}
}
},
);
if let Some((r_info, r_node)) = residual {
let mut l_node = Arc::new(Node::new());
core::mem::swap(&mut l_node, &mut self.root);
let mut children = NodeChildren::new();
children.push((l_info, l_node));
children.push((r_info, r_node));
*Arc::make_mut(&mut self.root) = Node::Internal(children);
}
if left_seam {
let root_info = self.root.text_info();
let (l_info, residual) = Arc::make_mut(&mut self.root)
.edit_chunk_at_char(
char_idx - 1,
root_info,
|_, cur_info, leaf_text| {
let byte_idx = leaf_text.len();
if (leaf_text.len() + ins_text.len()) <= MAX_BYTES {
let mut new_info = cur_info;
new_info.bytes += 1;
new_info.chars += 1;
if *leaf_text.as_bytes().last().unwrap() != 0x0D {
new_info.line_breaks += 1;
}
leaf_text.insert_str(byte_idx, "\n");
(new_info, None)
}
else {
let r_text = leaf_text.insert_str_split(byte_idx, "\n");
let l_text_info = TextInfo::from_str(&leaf_text);
if r_text.len() > 0 {
let r_text_info = TextInfo::from_str(&r_text);
(l_text_info, Some((r_text_info, Arc::new(Node::Leaf(r_text)))))
}
else {
(l_text_info, None)
}
}
},
);
if let Some((r_info, r_node)) = residual {
let mut l_node = Arc::new(Node::new());
core::mem::swap(&mut l_node, &mut self.root);
let mut children = NodeChildren::new();
children.push((l_info, l_node));
children.push((r_info, r_node));
*Arc::make_mut(&mut self.root) = Node::Internal(children);
}
}
}
pub fn remove<R>(&mut self, char_range: R)
where R: RangeBounds<usize> {
let start = start_bound_to_num(char_range.start_bound()).unwrap_or(0);
let end = end_bound_to_num(char_range.end_bound())
.unwrap_or_else(|| self.len_chars());
assert!(start <= end);
assert!(
end <= self.len_chars(),
"Attempt to remove past end of Rope: removal end {}, Rope length {}",
end,
self.len_chars()
);
if start == 0 && end == self.len_chars() {
self.root = Arc::new(Node::new());
return;
}
{
let root = Arc::make_mut(&mut self.root);
let root_info = root.text_info();
let (_, crlf_seam, needs_fix) =
root.remove_char_range(start, end, root_info);
if crlf_seam {
let seam_idx = root.char_to_text_info(start).bytes;
root.fix_crlf_seam(seam_idx as Count, false);
}
if needs_fix {
root.fix_after_remove(start);
}
}
self.pull_up_singular_nodes();
}
pub fn split_off(&mut self, char_idx: usize) -> Self {
assert!(
char_idx <= self.len_chars(),
"Attempt to split past end of Rope: split point {}, Rope length {}",
char_idx,
self.len_chars()
);
if char_idx == 0 {
let mut new_rope = Rope::new();
core::mem::swap(self, &mut new_rope);
new_rope
}
else if char_idx == self.len_chars() {
Rope::new()
}
else {
let mut new_rope =
Rope { root: Arc::new(Arc::make_mut(&mut self.root).split(char_idx)) };
Arc::make_mut(&mut self.root).zip_fix_right();
Arc::make_mut(&mut new_rope.root).zip_fix_left();
self.pull_up_singular_nodes();
new_rope.pull_up_singular_nodes();
new_rope
}
}
pub fn append(&mut self, other: Self) {
if self.len_chars() == 0 {
let mut other = other;
core::mem::swap(self, &mut other);
}
else if other.len_chars() > 0 {
let seam_byte_i = if other.char(0) == '\n' {
Some(self.root.text_info().bytes)
}
else {
None
};
let l_depth = self.root.depth();
let r_depth = other.root.depth();
if l_depth > r_depth {
let extra = Arc::make_mut(&mut self.root)
.append_at_depth(other.root, l_depth - r_depth);
if let Some(node) = extra {
let mut children = NodeChildren::new();
children.push((self.root.text_info(), Arc::clone(&self.root)));
children.push((node.text_info(), node));
self.root = Arc::new(Node::Internal(children));
}
}
else {
let mut other = other;
let extra = Arc::make_mut(&mut other.root)
.prepend_at_depth(Arc::clone(&self.root), r_depth - l_depth);
if let Some(node) = extra {
let mut children = NodeChildren::new();
children.push((node.text_info(), node));
children.push((other.root.text_info(), Arc::clone(&other.root)));
other.root = Arc::new(Node::Internal(children));
}
*self = other;
};
if let Some(i) = seam_byte_i {
Arc::make_mut(&mut self.root).fix_crlf_seam(i, true);
}
}
}
#[inline]
pub fn byte_to_char(&self, byte_idx: usize) -> usize {
assert!(
byte_idx <= self.len_bytes(),
"Attempt to index past end of Rope: byte index {}, Rope byte length {}",
byte_idx,
self.len_bytes()
);
let (chunk, b, c, _) = self.chunk_at_byte(byte_idx);
c + byte_to_char_idx(chunk, byte_idx - b)
}
#[inline]
pub fn byte_to_line(&self, byte_idx: usize) -> usize {
assert!(
byte_idx <= self.len_bytes(),
"Attempt to index past end of Rope: byte index {}, Rope byte length {}",
byte_idx,
self.len_bytes()
);
let (chunk, b, _, l) = self.chunk_at_byte(byte_idx);
l + byte_to_line_idx(chunk, byte_idx - b)
}
#[inline]
pub fn char_to_byte(&self, char_idx: usize) -> usize {
assert!(
char_idx <= self.len_chars(),
"Attempt to index past end of Rope: char index {}, Rope char length {}",
char_idx,
self.len_chars()
);
let (chunk, b, c, _) = self.chunk_at_char(char_idx);
b + char_to_byte_idx(chunk, char_idx - c)
}
#[inline]
pub fn char_to_line(&self, char_idx: usize) -> usize {
assert!(
char_idx <= self.len_chars(),
"Attempt to index past end of Rope: char index {}, Rope char length {}",
char_idx,
self.len_chars()
);
let (chunk, _, c, l) = self.chunk_at_char(char_idx);
l + char_to_line_idx(chunk, char_idx - c)
}
#[inline]
pub fn char_to_utf16_cu(&self, char_idx: usize) -> usize {
assert!(
char_idx <= self.len_chars(),
"Attempt to index past end of Rope: char index {}, Rope char length {}",
char_idx,
self.len_chars()
);
let (chunk, chunk_start_info) = self.root.get_chunk_at_char(char_idx);
let chunk_byte_idx =
char_to_byte_idx(chunk, char_idx - chunk_start_info.chars as usize);
let surrogate_count = byte_to_utf16_surrogate_idx(chunk, chunk_byte_idx);
char_idx + chunk_start_info.utf16_surrogates as usize + surrogate_count
}
#[inline]
pub fn utf16_cu_to_char(&self, utf16_cu_idx: usize) -> usize {
assert!(
utf16_cu_idx <= self.len_utf16_cu(),
"Attempt to index past end of Rope: utf16 code unit index {}, Rope \
utf16 code unit length {}",
utf16_cu_idx,
self.len_utf16_cu()
);
let (chunk, chunk_start_info) =
self.root.get_chunk_at_utf16_code_unit(utf16_cu_idx);
let chunk_utf16_cu_idx = utf16_cu_idx
- (chunk_start_info.chars + chunk_start_info.utf16_surrogates) as usize;
let chunk_char_idx = utf16_code_unit_to_char_idx(chunk, chunk_utf16_cu_idx);
chunk_start_info.chars as usize + chunk_char_idx
}
#[inline]
pub fn line_to_byte(&self, line_idx: usize) -> usize {
assert!(
line_idx <= self.len_lines(),
"Attempt to index past end of Rope: line index {}, Rope line length {}",
line_idx,
self.len_lines()
);
if line_idx == self.len_lines() {
self.len_bytes()
}
else {
let (chunk, b, _, l) = self.chunk_at_line_break(line_idx);
b + line_to_byte_idx(chunk, line_idx - l)
}
}
#[inline]
pub fn line_to_char(&self, line_idx: usize) -> usize {
assert!(
line_idx <= self.len_lines(),
"Attempt to index past end of Rope: line index {}, Rope line length {}",
line_idx,
self.len_lines()
);
if line_idx == self.len_lines() {
self.len_chars()
}
else {
let (chunk, _, c, l) = self.chunk_at_line_break(line_idx);
c + line_to_char_idx(chunk, line_idx - l)
}
}
#[inline]
pub fn byte(&self, byte_idx: usize) -> u8 {
assert!(
byte_idx < self.len_bytes(),
"Attempt to index past end of Rope: byte index {}, Rope byte length {}",
byte_idx,
self.len_bytes()
);
let (chunk, chunk_byte_idx, ..) = self.chunk_at_byte(byte_idx);
let chunk_rel_byte_idx = byte_idx - chunk_byte_idx;
chunk.as_bytes()[chunk_rel_byte_idx]
}
#[inline]
pub fn char(&self, char_idx: usize) -> char {
assert!(
char_idx < self.len_chars(),
"Attempt to index past end of Rope: char index {}, Rope char length {}",
char_idx,
self.len_chars()
);
let (chunk, _, chunk_char_idx, _) = self.chunk_at_char(char_idx);
let byte_idx = char_to_byte_idx(chunk, char_idx - chunk_char_idx);
chunk[byte_idx..].chars().next().unwrap()
}
#[inline]
pub fn line(&self, line_idx: usize) -> RopeSlice {
use crate::{
slice::RSEnum,
str_utils::{
count_chars,
count_utf16_surrogates,
},
};
let len_lines = self.len_lines();
assert!(
line_idx < len_lines,
"Attempt to index past end of Rope: line index {}, Rope line length {}",
line_idx,
len_lines
);
let (chunk_1, _, c1, l1) = self.chunk_at_line_break(line_idx);
let (chunk_2, _, c2, l2) = self.chunk_at_line_break(line_idx + 1);
if c1 == c2 {
let text1 = &chunk_1[line_to_byte_idx(chunk_1, line_idx - l1)..];
let text2 = &text1[..line_to_byte_idx(text1, 1)];
RopeSlice(RSEnum::Light {
text: text2,
char_count: count_chars(text2) as Count,
utf16_surrogate_count: count_utf16_surrogates(text2) as Count,
line_break_count: if line_idx == (len_lines - 1) { 0 } else { 1 },
})
}
else {
let start = c1 + line_to_char_idx(chunk_1, line_idx - l1);
let end = c2 + line_to_char_idx(chunk_2, line_idx + 1 - l2);
self.slice(start..end)
}
}
#[inline]
pub fn chunk_at_byte(&self, byte_idx: usize) -> (&str, usize, usize, usize) {
assert!(
byte_idx <= self.len_bytes(),
"Attempt to index past end of Rope: byte index {}, Rope byte length {}",
byte_idx,
self.len_bytes()
);
let (chunk, info) = self.root.get_chunk_at_byte(byte_idx);
(chunk, info.bytes as usize, info.chars as usize, info.line_breaks as usize)
}
#[inline]
pub fn chunk_at_char(&self, char_idx: usize) -> (&str, usize, usize, usize) {
assert!(
char_idx <= self.len_chars(),
"Attempt to index past end of Rope: char index {}, Rope char length {}",
char_idx,
self.len_chars()
);
let (chunk, info) = self.root.get_chunk_at_char(char_idx);
(chunk, info.bytes as usize, info.chars as usize, info.line_breaks as usize)
}
#[inline]
pub fn chunk_at_line_break(
&self,
line_break_idx: usize,
) -> (&str, usize, usize, usize) {
assert!(
line_break_idx <= self.len_lines(),
"Attempt to index past end of Rope: line break index {}, max index {}",
line_break_idx,
self.len_lines()
);
let (chunk, info) = self.root.get_chunk_at_line_break(line_break_idx);
(chunk, info.bytes as usize, info.chars as usize, info.line_breaks as usize)
}
#[inline]
pub fn slice<R>(&self, char_range: R) -> RopeSlice
where R: RangeBounds<usize> {
let start = start_bound_to_num(char_range.start_bound()).unwrap_or(0);
let end = end_bound_to_num(char_range.end_bound())
.unwrap_or_else(|| self.len_chars());
assert!(start <= end);
assert!(
end <= self.len_chars(),
"Attempt to slice past end of Rope: slice end {}, Rope length {}",
end,
self.len_chars()
);
RopeSlice::new_with_range(&self.root, start, end)
}
#[inline]
pub fn bytes(&self) -> Bytes { Bytes::new(&self.root) }
#[inline]
pub fn bytes_at(&self, byte_idx: usize) -> Bytes {
assert!(
byte_idx <= self.len_bytes(),
"Attempt to index past end of Rope: byte index {}, Rope byte length {}",
byte_idx,
self.len_bytes()
);
let info = self.root.text_info();
Bytes::new_with_range_at(
&self.root,
byte_idx,
(0, info.bytes as usize),
(0, info.chars as usize),
(0, info.line_breaks as usize + 1),
)
}
#[inline]
pub fn chars(&self) -> Chars { Chars::new(&self.root) }
#[inline]
pub fn chars_at(&self, char_idx: usize) -> Chars {
assert!(
char_idx <= self.len_chars(),
"Attempt to index past end of Rope: char index {}, Rope char length {}",
char_idx,
self.len_chars()
);
let info = self.root.text_info();
Chars::new_with_range_at(
&self.root,
char_idx,
(0, info.bytes as usize),
(0, info.chars as usize),
(0, info.line_breaks as usize + 1),
)
}
#[inline]
pub fn lines(&self) -> Lines { Lines::new(&self.root) }
#[inline]
pub fn lines_at(&self, line_idx: usize) -> Lines {
assert!(
line_idx <= self.len_lines(),
"Attempt to index past end of Rope: line index {}, Rope line length {}",
line_idx,
self.len_lines()
);
Lines::new_with_range_at(
&self.root,
line_idx,
(0, self.len_bytes()),
(0, self.len_lines()),
)
}
#[inline]
pub fn chunks(&self) -> Chunks { Chunks::new(&self.root) }
#[inline]
pub fn chunks_at_byte(
&self,
byte_idx: usize,
) -> (Chunks, usize, usize, usize) {
assert!(
byte_idx <= self.len_bytes(),
"Attempt to index past end of Rope: byte index {}, Rope byte length {}",
byte_idx,
self.len_bytes()
);
Chunks::new_with_range_at_byte(
&self.root,
byte_idx,
(0, self.len_bytes()),
(0, self.len_chars()),
(0, self.len_lines()),
)
}
#[inline]
pub fn chunks_at_char(
&self,
char_idx: usize,
) -> (Chunks, usize, usize, usize) {
assert!(
char_idx <= self.len_chars(),
"Attempt to index past end of Rope: char index {}, Rope char length {}",
char_idx,
self.len_chars()
);
Chunks::new_with_range_at_char(
&self.root,
char_idx,
(0, self.len_bytes()),
(0, self.len_chars()),
(0, self.len_lines()),
)
}
#[inline]
pub fn chunks_at_line_break(
&self,
line_break_idx: usize,
) -> (Chunks, usize, usize, usize) {
assert!(
line_break_idx <= self.len_lines(),
"Attempt to index past end of Rope: line break index {}, max index {}",
line_break_idx,
self.len_lines()
);
Chunks::new_with_range_at_line_break(
&self.root,
line_break_idx,
(0, self.len_bytes()),
(0, self.len_chars()),
(0, self.len_lines()),
)
}
#[doc(hidden)]
pub fn assert_integrity(&self) { self.root.assert_integrity(); }
#[doc(hidden)]
pub fn assert_invariants(&self) {
self.root.assert_balance();
self.root.assert_node_size(true);
self.assert_crlf_seams();
}
fn assert_crlf_seams(&self) {
if self.chunks().count() > 0 {
let mut itr = self.chunks();
let mut last_chunk = itr.next().unwrap();
for chunk in itr {
if !chunk.is_empty() && !last_chunk.is_empty() {
assert!(crlf::seam_is_break(last_chunk.as_bytes(), chunk.as_bytes()));
last_chunk = chunk;
}
else if last_chunk.is_empty() {
last_chunk = chunk;
}
}
}
}
pub(crate) fn pull_up_singular_nodes(&mut self) {
while (!self.root.is_leaf()) && self.root.child_count() == 1 {
let child = if let Node::Internal(ref children) = *self.root {
Arc::clone(&children.nodes()[0])
}
else {
unreachable!()
};
self.root = child;
}
}
}
impl<'a> From<&'a str> for Rope {
#[inline]
fn from(text: &'a str) -> Self { Rope::from_str(text) }
}
impl<'a> From<alloc::borrow::Cow<'a, str>> for Rope {
#[inline]
fn from(text: alloc::borrow::Cow<'a, str>) -> Self { Rope::from_str(&text) }
}
impl From<String> for Rope {
#[inline]
fn from(text: String) -> Self { Rope::from_str(&text) }
}
impl<'a> From<RopeSlice<'a>> for Rope {
fn from(s: RopeSlice<'a>) -> Self {
use crate::slice::RSEnum;
match s {
RopeSlice(RSEnum::Full { node, start_info, end_info }) => {
let mut rope = Rope { root: Arc::clone(node) };
if end_info.chars < node.text_info().chars {
{
let root = Arc::make_mut(&mut rope.root);
root.split(end_info.chars as usize);
root.zip_fix_right();
}
rope.pull_up_singular_nodes();
}
if start_info.chars > 0 {
{
let root = Arc::make_mut(&mut rope.root);
*root = root.split(start_info.chars as usize);
root.zip_fix_left();
}
rope.pull_up_singular_nodes();
}
rope
}
RopeSlice(RSEnum::Light { text, .. }) => Rope::from_str(text),
}
}
}
impl From<Rope> for String {
#[inline]
fn from(r: Rope) -> Self { String::from(&r) }
}
impl<'a> From<&'a Rope> for String {
#[inline]
fn from(r: &'a Rope) -> Self {
let mut text = String::with_capacity(r.len_bytes());
text.extend(r.chunks());
text
}
}
impl<'a> From<Rope> for alloc::borrow::Cow<'a, str> {
#[inline]
fn from(r: Rope) -> Self { alloc::borrow::Cow::Owned(String::from(r)) }
}
impl<'a> From<&'a Rope> for alloc::borrow::Cow<'a, str> {
#[inline]
fn from(r: &'a Rope) -> Self {
if let Node::Leaf(ref text) = *r.root {
alloc::borrow::Cow::Borrowed(text)
}
else {
alloc::borrow::Cow::Owned(String::from(r))
}
}
}
impl<'a> FromIterator<&'a str> for Rope {
fn from_iter<T>(iter: T) -> Self
where T: IntoIterator<Item = &'a str> {
let mut builder = RopeBuilder::new();
for chunk in iter {
builder.append(chunk);
}
builder.finish()
}
}
impl<'a> FromIterator<alloc::borrow::Cow<'a, str>> for Rope {
fn from_iter<T>(iter: T) -> Self
where T: IntoIterator<Item = alloc::borrow::Cow<'a, str>> {
let mut builder = RopeBuilder::new();
for chunk in iter {
builder.append(&chunk);
}
builder.finish()
}
}
impl FromIterator<String> for Rope {
fn from_iter<T>(iter: T) -> Self
where T: IntoIterator<Item = String> {
let mut builder = RopeBuilder::new();
for chunk in iter {
builder.append(&chunk);
}
builder.finish()
}
}
impl core::fmt::Debug for Rope {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_list().entries(self.chunks()).finish()
}
}
impl core::fmt::Display for Rope {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
for chunk in self.chunks() {
write!(f, "{}", chunk)?
}
Ok(())
}
}
impl core::default::Default for Rope {
#[inline]
fn default() -> Self { Self::new() }
}
impl core::cmp::Eq for Rope {}
impl core::cmp::PartialEq<Rope> for Rope {
#[inline]
fn eq(&self, other: &Rope) -> bool { self.slice(..) == other.slice(..) }
}
impl<'a> core::cmp::PartialEq<&'a str> for Rope {
#[inline]
fn eq(&self, other: &&'a str) -> bool { self.slice(..) == *other }
}
impl<'a> core::cmp::PartialEq<Rope> for &'a str {
#[inline]
fn eq(&self, other: &Rope) -> bool { *self == other.slice(..) }
}
impl core::cmp::PartialEq<str> for Rope {
#[inline]
fn eq(&self, other: &str) -> bool { self.slice(..) == other }
}
impl core::cmp::PartialEq<Rope> for str {
#[inline]
fn eq(&self, other: &Rope) -> bool { self == other.slice(..) }
}
impl<'a> core::cmp::PartialEq<String> for Rope {
#[inline]
fn eq(&self, other: &String) -> bool { self.slice(..) == other.as_str() }
}
impl<'a> core::cmp::PartialEq<Rope> for String {
#[inline]
fn eq(&self, other: &Rope) -> bool { self.as_str() == other.slice(..) }
}
impl<'a> core::cmp::PartialEq<alloc::borrow::Cow<'a, str>> for Rope {
#[inline]
fn eq(&self, other: &alloc::borrow::Cow<'a, str>) -> bool {
self.slice(..) == **other
}
}
impl<'a> core::cmp::PartialEq<Rope> for alloc::borrow::Cow<'a, str> {
#[inline]
fn eq(&self, other: &Rope) -> bool { **self == other.slice(..) }
}
impl core::cmp::Ord for Rope {
#[inline]
fn cmp(&self, other: &Rope) -> core::cmp::Ordering {
self.slice(..).cmp(&other.slice(..))
}
}
impl core::cmp::PartialOrd<Rope> for Rope {
#[inline]
fn partial_cmp(&self, other: &Rope) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::str_utils::byte_to_char_idx;
const TEXT: &str = "Hello there! How're you doing? It's a fine day, isn't \
it? Aren't you glad we're alive? \
こんにちは、みんなさん!";
const TEXT_LINES: &str = "Hello there! How're you doing?\nIt's a fine day, \
isn't it?\nAren't you glad we're \
alive?\nこんにちは、みんなさん!";
const TEXT_EMOJI: &str = "Hello there!🐸 How're you doing?🐸 It's a fine \
day, isn't it?🐸 Aren't you glad we're alive?🐸 \
こんにちは、みんなさん!";
#[test]
fn new_01() {
let r = Rope::new();
assert_eq!(r, "");
r.assert_integrity();
r.assert_invariants();
}
#[test]
fn from_str() {
let r = Rope::from_str(TEXT);
assert_eq!(r, TEXT);
r.assert_integrity();
r.assert_invariants();
}
#[test]
fn len_bytes_01() {
let r = Rope::from_str(TEXT);
assert_eq!(r.len_bytes(), 127);
}
#[test]
fn len_bytes_02() {
let r = Rope::from_str("");
assert_eq!(r.len_bytes(), 0);
}
#[test]
fn len_chars_01() {
let r = Rope::from_str(TEXT);
assert_eq!(r.len_chars(), 103);
}
#[test]
fn len_chars_02() {
let r = Rope::from_str("");
assert_eq!(r.len_chars(), 0);
}
#[test]
fn len_lines_01() {
let r = Rope::from_str(TEXT_LINES);
assert_eq!(r.len_lines(), 4);
}
#[test]
fn len_lines_02() {
let r = Rope::from_str("");
assert_eq!(r.len_lines(), 1);
}
#[test]
fn len_utf16_cu_01() {
let r = Rope::from_str(TEXT);
assert_eq!(r.len_utf16_cu(), 103);
}
#[test]
fn len_utf16_cu_02() {
let r = Rope::from_str(TEXT_EMOJI);
assert_eq!(r.len_utf16_cu(), 111);
}
#[test]
fn len_utf16_cu_03() {
let r = Rope::from_str("");
assert_eq!(r.len_utf16_cu(), 0);
}
#[test]
fn insert_01() {
let mut r = Rope::from_str(TEXT);
r.insert(3, "AA");
assert_eq!(
r,
"HelAAlo there! How're you doing? It's a fine day, isn't it? Aren't \
you glad we're alive? こんにちは、みんなさん!"
);
r.assert_integrity();
r.assert_invariants();
}
#[test]
fn insert_02() {
let mut r = Rope::from_str(TEXT);
r.insert(0, "AA");
assert_eq!(
r,
"AAHello there! How're you doing? It's a fine day, isn't it? Aren't \
you glad we're alive? こんにちは、みんなさん!"
);
r.assert_integrity();
r.assert_invariants();
}
#[test]
fn insert_03() {
let mut r = Rope::from_str(TEXT);
r.insert(103, "AA");
assert_eq!(
r,
"Hello there! How're you doing? It's a fine day, isn't it? Aren't \
you glad we're alive? こんにちは、みんなさん!AA"
);
r.assert_integrity();
r.assert_invariants();
}
#[test]
fn insert_04() {
let mut r = Rope::new();
r.insert(0, "He");
r.insert(2, "l");
r.insert(3, "l");
r.insert(4, "o w");
r.insert(7, "o");
r.insert(8, "rl");
r.insert(10, "d!");
r.insert(3, "zopter");
assert_eq!("Helzopterlo world!", r);
r.assert_integrity();
r.assert_invariants();
}
#[test]
fn insert_05() {
let mut r = Rope::new();
r.insert(0, "こんいちは、みんなさん!");
r.insert(7, "zopter");
assert_eq!("こんいちは、みzopterんなさん!", r);
r.assert_integrity();
r.assert_invariants();
}
#[test]
fn insert_06() {
let mut r = Rope::new();
r.insert(0, "こ");
r.insert(1, "ん");
r.insert(2, "い");
r.insert(3, "ち");
r.insert(4, "は");
r.insert(5, "、");
r.insert(6, "み");
r.insert(7, "ん");
r.insert(8, "な");
r.insert(9, "さ");
r.insert(10, "ん");
r.insert(11, "!");
r.insert(7, "zopter");
assert_eq!("こんいちは、みzopterんなさん!", r);
r.assert_integrity();
r.assert_invariants();
}
#[test]
fn insert_char_01() {
let mut r = Rope::from_str(TEXT);
r.insert_char(3, 'A');
r.insert_char(12, '!');
r.insert_char(12, '!');
assert_eq!(
r,
"HelAlo there!!! How're you doing? It's a fine day, isn't it? Aren't \
you glad we're alive? こんにちは、みんなさん!"
);
r.assert_integrity();
r.assert_invariants();
}
#[test]
fn insert_char_02() {
let mut r = Rope::new();
r.insert_char(0, '!');
r.insert_char(0, 'こ');
r.insert_char(1, 'ん');
r.insert_char(2, 'い');
r.insert_char(3, 'ち');
r.insert_char(4, 'は');
r.insert_char(5, '、');
r.insert_char(6, 'み');
r.insert_char(7, 'ん');
r.insert_char(8, 'な');
r.insert_char(9, 'さ');
r.insert_char(10, 'ん');
assert_eq!("こんいちは、みんなさん!", r);
r.assert_integrity();
r.assert_invariants();
}
#[test]
fn remove_01() {
let mut r = Rope::from_str(TEXT);
r.remove(5..11);
r.remove(24..31);
r.remove(19..25);
r.remove(75..79);
assert_eq!(
r,
"Hello! How're you \
a fine day, isn't it? Aren't you glad \
we're alive? こんにんなさん!"
);
r.assert_integrity();
r.assert_invariants();
}
#[test]
fn remove_02() {
let mut r =
Rope::from_str("\r\n\r\n\r\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n");
r.remove(3..6);
assert_eq!(r, "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n");
r.assert_integrity();
r.assert_invariants();
}
#[test]
fn remove_03() {
let mut r = Rope::from_str(TEXT);
r.remove(45..45);
assert_eq!(r, TEXT);
r.assert_integrity();
r.assert_invariants();
}
#[test]
fn remove_04() {
let mut r = Rope::from_str(TEXT);
r.remove(0..103);
assert_eq!(r, "");
r.assert_integrity();
r.assert_invariants();
}
#[test]
fn remove_05() {
let mut r = Rope::from_str(TEXT);
r.remove(3..100);
assert_eq!(r, "Helさん!");
r.assert_integrity();
r.assert_invariants();
}
#[test]
#[should_panic]
fn remove_06() {
let mut r = Rope::from_str(TEXT);
r.remove(56..55); }
#[test]
#[should_panic]
fn remove_07() {
let mut r = Rope::from_str(TEXT);
r.remove(102..104); }
#[test]
#[should_panic]
fn remove_08() {
let mut r = Rope::from_str(TEXT);
r.remove(103..104); }
#[test]
#[should_panic]
fn remove_09() {
let mut r = Rope::from_str(TEXT);
r.remove(104..104); }
#[test]
#[should_panic]
fn remove_10() {
let mut r = Rope::from_str(TEXT);
r.remove(104..105); }
#[test]
fn split_off_01() {
let mut r = Rope::from_str(TEXT);
let r2 = r.split_off(50);
assert_eq!(r, "Hello there! How're you doing? It's a fine day, ");
assert_eq!(
r2,
"isn't it? Aren't you glad we're alive? こんにちは、みんなさん!"
);
r.assert_integrity();
r2.assert_integrity();
r.assert_invariants();
r2.assert_invariants();
}
#[test]
fn split_off_02() {
let mut r = Rope::from_str(TEXT);
let r2 = r.split_off(1);
assert_eq!(r, "H");
assert_eq!(
r2,
"ello there! How're you doing? It's a fine day, isn't it? Aren't you \
glad we're alive? こんにちは、みんなさん!"
);
r.assert_integrity();
r2.assert_integrity();
r.assert_invariants();
r2.assert_invariants();
}
#[test]
fn split_off_03() {
let mut r = Rope::from_str(TEXT);
let r2 = r.split_off(102);
assert_eq!(
r,
"Hello there! How're you doing? It's a fine day, isn't it? Aren't \
you glad we're alive? こんにちは、みんなさん"
);
assert_eq!(r2, "!");
r.assert_integrity();
r2.assert_integrity();
r.assert_invariants();
r2.assert_invariants();
}
#[test]
fn split_off_04() {
let mut r = Rope::from_str(TEXT);
let r2 = r.split_off(0);
assert_eq!(r, "");
assert_eq!(
r2,
"Hello there! How're you doing? It's a fine day, isn't it? Aren't \
you glad we're alive? こんにちは、みんなさん!"
);
r.assert_integrity();
r2.assert_integrity();
r.assert_invariants();
r2.assert_invariants();
}
#[test]
fn split_off_05() {
let mut r = Rope::from_str(TEXT);
let r2 = r.split_off(103);
assert_eq!(
r,
"Hello there! How're you doing? It's a fine day, isn't it? Aren't \
you glad we're alive? こんにちは、みんなさん!"
);
assert_eq!(r2, "");
r.assert_integrity();
r2.assert_integrity();
r.assert_invariants();
r2.assert_invariants();
}
#[test]
#[should_panic]
fn split_off_06() {
let mut r = Rope::from_str(TEXT);
r.split_off(104); }
#[test]
fn append_01() {
let mut r = Rope::from_str(
"Hello there! How're you doing? It's a fine day, isn't ",
);
let r2 = Rope::from_str(
"it? Aren't you glad we're alive? こんにちは、みんなさん!",
);
r.append(r2);
assert_eq!(r, TEXT);
r.assert_integrity();
r.assert_invariants();
}
#[test]
fn append_02() {
let mut r = Rope::from_str(
"Hello there! How're you doing? It's a fine day, isn't it? Aren't \
you glad we're alive? こんに",
);
let r2 = Rope::from_str("ちは、みんなさん!");
r.append(r2);
assert_eq!(r, TEXT);
r.assert_integrity();
r.assert_invariants();
}
#[test]
fn append_03() {
let mut r = Rope::from_str(
"Hello there! How're you doing? It's a fine day, isn't it? Aren't \
you glad we're alive? こんにちは、みんなさん",
);
let r2 = Rope::from_str("!");
r.append(r2);
assert_eq!(r, TEXT);
r.assert_integrity();
r.assert_invariants();
}
#[test]
fn append_04() {
let mut r = Rope::from_str("H");
let r2 = Rope::from_str(
"ello there! How're you doing? It's a fine day, isn't it? Aren't you \
glad we're alive? こんにちは、みんなさん!",
);
r.append(r2);
assert_eq!(r, TEXT);
r.assert_integrity();
r.assert_invariants();
}
#[test]
fn append_05() {
let mut r = Rope::from_str(TEXT);
let r2 = Rope::from_str("");
r.append(r2);
assert_eq!(r, TEXT);
r.assert_integrity();
r.assert_invariants();
}
#[test]
fn append_06() {
let mut r = Rope::from_str("");
let r2 = Rope::from_str(TEXT);
r.append(r2);
assert_eq!(r, TEXT);
r.assert_integrity();
r.assert_invariants();
}
#[test]
fn append_07() {
let mut r = Rope::from_str("\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r");
let r2 = Rope::from_str("\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r");
r.append(r2);
assert_eq!(r, "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r");
assert_eq!(r.len_lines(), 24);
r.assert_integrity();
r.assert_invariants();
}
#[test]
fn shrink_to_fit_01() {
let mut r = Rope::new();
for _ in 0..10 {
let len = r.len_chars();
r.insert(len / 2, "こ");
r.insert(len / 2, "ん");
r.insert(len / 2, "い");
r.insert(len / 2, "ち");
r.insert(len / 2, "は");
r.insert(len / 2, "、");
r.insert(len / 2, "み");
r.insert(len / 2, "ん");
r.insert(len / 2, "な");
r.insert(len / 2, "さ");
r.insert(len / 2, "ん");
r.insert(len / 2, "!");
r.insert(len / 2, "zopter");
}
let r2 = r.clone();
r.shrink_to_fit();
assert_eq!(r, r2);
r.assert_integrity();
r.assert_invariants();
}
#[test]
fn byte_to_char_01() {
let r = Rope::from_str(TEXT);
assert_eq!(0, r.byte_to_char(0));
assert_eq!(1, r.byte_to_char(1));
assert_eq!(2, r.byte_to_char(2));
assert_eq!(91, r.byte_to_char(91));
assert_eq!(91, r.byte_to_char(92));
assert_eq!(91, r.byte_to_char(93));
assert_eq!(92, r.byte_to_char(94));
assert_eq!(92, r.byte_to_char(95));
assert_eq!(92, r.byte_to_char(96));
assert_eq!(102, r.byte_to_char(124));
assert_eq!(102, r.byte_to_char(125));
assert_eq!(102, r.byte_to_char(126));
assert_eq!(103, r.byte_to_char(127));
}
#[test]
fn byte_to_line_01() {
let r = Rope::from_str(TEXT_LINES);
assert_eq!(0, r.byte_to_line(0));
assert_eq!(0, r.byte_to_line(1));
assert_eq!(0, r.byte_to_line(31));
assert_eq!(1, r.byte_to_line(32));
assert_eq!(1, r.byte_to_line(33));
assert_eq!(1, r.byte_to_line(58));
assert_eq!(2, r.byte_to_line(59));
assert_eq!(2, r.byte_to_line(60));
assert_eq!(2, r.byte_to_line(87));
assert_eq!(3, r.byte_to_line(88));
assert_eq!(3, r.byte_to_line(89));
assert_eq!(3, r.byte_to_line(124));
}
#[test]
fn byte_to_line_02() {
let r = Rope::from_str("");
assert_eq!(0, r.byte_to_line(0));
}
#[test]
fn byte_to_line_03() {
let r = Rope::from_str("Hi there\n");
assert_eq!(0, r.byte_to_line(0));
assert_eq!(0, r.byte_to_line(8));
assert_eq!(1, r.byte_to_line(9));
}
#[test]
#[should_panic]
fn byte_to_line_04() {
let r = Rope::from_str(TEXT_LINES);
r.byte_to_line(125);
}
#[test]
fn char_to_byte_01() {
let r = Rope::from_str(TEXT);
assert_eq!(0, r.char_to_byte(0));
assert_eq!(1, r.char_to_byte(1));
assert_eq!(2, r.char_to_byte(2));
assert_eq!(91, r.char_to_byte(91));
assert_eq!(94, r.char_to_byte(92));
assert_eq!(97, r.char_to_byte(93));
assert_eq!(100, r.char_to_byte(94));
assert_eq!(124, r.char_to_byte(102));
assert_eq!(127, r.char_to_byte(103));
}
#[test]
fn char_to_line_01() {
let r = Rope::from_str(TEXT_LINES);
assert_eq!(0, r.char_to_line(0));
assert_eq!(0, r.char_to_line(1));
assert_eq!(0, r.char_to_line(31));
assert_eq!(1, r.char_to_line(32));
assert_eq!(1, r.char_to_line(33));
assert_eq!(1, r.char_to_line(58));
assert_eq!(2, r.char_to_line(59));
assert_eq!(2, r.char_to_line(60));
assert_eq!(2, r.char_to_line(87));
assert_eq!(3, r.char_to_line(88));
assert_eq!(3, r.char_to_line(89));
assert_eq!(3, r.char_to_line(100));
}
#[test]
fn char_to_line_02() {
let r = Rope::from_str("");
assert_eq!(0, r.char_to_line(0));
}
#[test]
fn char_to_line_03() {
let r = Rope::from_str("Hi there\n");
assert_eq!(0, r.char_to_line(0));
assert_eq!(0, r.char_to_line(8));
assert_eq!(1, r.char_to_line(9));
}
#[test]
#[should_panic]
fn char_to_line_04() {
let r = Rope::from_str(TEXT_LINES);
r.char_to_line(101);
}
#[test]
fn line_to_byte_01() {
let r = Rope::from_str(TEXT_LINES);
assert_eq!(0, r.line_to_byte(0));
assert_eq!(32, r.line_to_byte(1));
assert_eq!(59, r.line_to_byte(2));
assert_eq!(88, r.line_to_byte(3));
assert_eq!(124, r.line_to_byte(4));
}
#[test]
fn line_to_byte_02() {
let r = Rope::from_str("");
assert_eq!(0, r.line_to_byte(0));
assert_eq!(0, r.line_to_byte(1));
}
#[test]
#[should_panic]
fn line_to_byte_03() {
let r = Rope::from_str(TEXT_LINES);
r.line_to_byte(5);
}
#[test]
fn line_to_char_01() {
let r = Rope::from_str(TEXT_LINES);
assert_eq!(0, r.line_to_char(0));
assert_eq!(32, r.line_to_char(1));
assert_eq!(59, r.line_to_char(2));
assert_eq!(88, r.line_to_char(3));
assert_eq!(100, r.line_to_char(4));
}
#[test]
fn line_to_char_02() {
let r = Rope::from_str("");
assert_eq!(0, r.line_to_char(0));
assert_eq!(0, r.line_to_char(1));
}
#[test]
#[should_panic]
fn line_to_char_03() {
let r = Rope::from_str(TEXT_LINES);
r.line_to_char(5);
}
#[test]
fn char_to_utf16_cu_01() {
let r = Rope::from_str("");
assert_eq!(0, r.char_to_utf16_cu(0));
}
#[test]
#[should_panic]
fn char_to_utf16_cu_02() {
let r = Rope::from_str("");
r.char_to_utf16_cu(1);
}
#[test]
fn char_to_utf16_cu_03() {
let r = Rope::from_str(TEXT_EMOJI);
assert_eq!(0, r.char_to_utf16_cu(0));
assert_eq!(12, r.char_to_utf16_cu(12));
assert_eq!(14, r.char_to_utf16_cu(13));
assert_eq!(33, r.char_to_utf16_cu(32));
assert_eq!(35, r.char_to_utf16_cu(33));
assert_eq!(63, r.char_to_utf16_cu(61));
assert_eq!(65, r.char_to_utf16_cu(62));
assert_eq!(95, r.char_to_utf16_cu(92));
assert_eq!(97, r.char_to_utf16_cu(93));
assert_eq!(111, r.char_to_utf16_cu(107));
}
#[test]
#[should_panic]
fn char_to_utf16_cu_04() {
let r = Rope::from_str(TEXT_EMOJI);
r.char_to_utf16_cu(108);
}
#[test]
fn utf16_cu_to_char_01() {
let r = Rope::from_str("");
assert_eq!(0, r.utf16_cu_to_char(0));
}
#[test]
#[should_panic]
fn utf16_cu_to_char_02() {
let r = Rope::from_str("");
r.utf16_cu_to_char(1);
}
#[test]
fn utf16_cu_to_char_03() {
let r = Rope::from_str(TEXT_EMOJI);
assert_eq!(0, r.utf16_cu_to_char(0));
assert_eq!(12, r.utf16_cu_to_char(12));
assert_eq!(12, r.utf16_cu_to_char(13));
assert_eq!(13, r.utf16_cu_to_char(14));
assert_eq!(32, r.utf16_cu_to_char(33));
assert_eq!(32, r.utf16_cu_to_char(34));
assert_eq!(33, r.utf16_cu_to_char(35));
assert_eq!(61, r.utf16_cu_to_char(63));
assert_eq!(61, r.utf16_cu_to_char(64));
assert_eq!(62, r.utf16_cu_to_char(65));
assert_eq!(92, r.utf16_cu_to_char(95));
assert_eq!(92, r.utf16_cu_to_char(96));
assert_eq!(93, r.utf16_cu_to_char(97));
assert_eq!(107, r.utf16_cu_to_char(111));
}
#[test]
#[should_panic]
fn utf16_cu_to_char_04() {
let r = Rope::from_str(TEXT_EMOJI);
r.utf16_cu_to_char(112);
}
#[test]
fn byte_01() {
let r = Rope::from_str(TEXT);
assert_eq!(r.byte(0), b'H');
assert_eq!(r.byte(124), 0xEF);
assert_eq!(r.byte(125), 0xBC);
assert_eq!(r.byte(126), 0x81);
}
#[test]
#[should_panic]
fn byte_02() {
let r = Rope::from_str(TEXT);
r.byte(127);
}
#[test]
#[should_panic]
fn byte_03() {
let r = Rope::from_str("");
r.byte(0);
}
#[test]
fn char_01() {
let r = Rope::from_str(TEXT);
assert_eq!(r.char(0), 'H');
assert_eq!(r.char(10), 'e');
assert_eq!(r.char(18), 'r');
assert_eq!(r.char(102), '!');
}
#[test]
#[should_panic]
fn char_02() {
let r = Rope::from_str(TEXT);
r.char(103);
}
#[test]
#[should_panic]
fn char_03() {
let r = Rope::from_str("");
r.char(0);
}
#[test]
fn line_01() {
let r = Rope::from_str(TEXT_LINES);
let l0 = r.line(0);
assert_eq!(l0, "Hello there! How're you doing?\n");
assert_eq!(l0.len_bytes(), 32);
assert_eq!(l0.len_chars(), 32);
assert_eq!(l0.len_lines(), 2);
let l1 = r.line(1);
assert_eq!(l1, "It's a fine day, isn't it?\n");
assert_eq!(l1.len_bytes(), 27);
assert_eq!(l1.len_chars(), 27);
assert_eq!(l1.len_lines(), 2);
let l2 = r.line(2);
assert_eq!(l2, "Aren't you glad we're alive?\n");
assert_eq!(l2.len_bytes(), 29);
assert_eq!(l2.len_chars(), 29);
assert_eq!(l2.len_lines(), 2);
let l3 = r.line(3);
assert_eq!(l3, "こんにちは、みんなさん!");
assert_eq!(l3.len_bytes(), 36);
assert_eq!(l3.len_chars(), 12);
assert_eq!(l3.len_lines(), 1);
}
#[test]
fn line_02() {
let r = Rope::from_str("Hello there! How're you doing?\n");
assert_eq!(r.line(0), "Hello there! How're you doing?\n");
assert_eq!(r.line(1), "");
}
#[test]
fn line_03() {
let r = Rope::from_str("Hi\nHi\nHi\nHi\nHi\nHi\n");
assert_eq!(r.line(0), "Hi\n");
assert_eq!(r.line(1), "Hi\n");
assert_eq!(r.line(2), "Hi\n");
assert_eq!(r.line(3), "Hi\n");
assert_eq!(r.line(4), "Hi\n");
assert_eq!(r.line(5), "Hi\n");
assert_eq!(r.line(6), "");
}
#[test]
fn line_04() {
let r = Rope::from_str("");
assert_eq!(r.line(0), "");
}
#[test]
#[should_panic]
fn line_05() {
let r = Rope::from_str(TEXT_LINES);
r.line(4);
}
#[test]
fn line_06() {
let r = Rope::from_str("1\n2\n3\n4\n5\n6\n7\n8");
assert_eq!(r.line(0).len_lines(), 2);
assert_eq!(r.line(1).len_lines(), 2);
assert_eq!(r.line(2).len_lines(), 2);
assert_eq!(r.line(3).len_lines(), 2);
assert_eq!(r.line(4).len_lines(), 2);
assert_eq!(r.line(5).len_lines(), 2);
assert_eq!(r.line(6).len_lines(), 2);
assert_eq!(r.line(7).len_lines(), 1);
}
#[test]
fn chunk_at_byte() {
let r = Rope::from_str(TEXT_LINES);
let mut t = TEXT_LINES;
let mut last_chunk = "";
for i in 0..r.len_bytes() {
let (chunk, b, c, l) = r.chunk_at_byte(i);
assert_eq!(c, byte_to_char_idx(TEXT_LINES, b));
assert_eq!(l, byte_to_line_idx(TEXT_LINES, b));
if chunk != last_chunk {
assert_eq!(chunk, &t[..chunk.len()]);
t = &t[chunk.len()..];
last_chunk = chunk;
}
let c1 = {
let i2 = byte_to_char_idx(TEXT_LINES, i);
TEXT_LINES.chars().nth(i2).unwrap()
};
let c2 = {
let i2 = i - b;
let i3 = byte_to_char_idx(chunk, i2);
chunk.chars().nth(i3).unwrap()
};
assert_eq!(c1, c2);
}
assert_eq!(t.len(), 0);
}
#[test]
fn chunk_at_char() {
let r = Rope::from_str(TEXT_LINES);
let mut t = TEXT_LINES;
let mut last_chunk = "";
for i in 0..r.len_chars() {
let (chunk, b, c, l) = r.chunk_at_char(i);
assert_eq!(b, char_to_byte_idx(TEXT_LINES, c));
assert_eq!(l, char_to_line_idx(TEXT_LINES, c));
if chunk != last_chunk {
assert_eq!(chunk, &t[..chunk.len()]);
t = &t[chunk.len()..];
last_chunk = chunk;
}
let c1 = TEXT_LINES.chars().nth(i).unwrap();
let c2 = {
let i2 = i - c;
chunk.chars().nth(i2).unwrap()
};
assert_eq!(c1, c2);
}
assert_eq!(t.len(), 0);
}
#[test]
fn chunk_at_line_break() {
let r = Rope::from_str(TEXT_LINES);
{
let (chunk, b, c, l) = r.chunk_at_line_break(0);
assert_eq!(chunk, &TEXT_LINES[..chunk.len()]);
assert_eq!(b, 0);
assert_eq!(c, 0);
assert_eq!(l, 0);
}
for i in 1..r.len_lines() {
let (chunk, b, c, l) = r.chunk_at_line_break(i);
assert_eq!(chunk, &TEXT_LINES[b..(b + chunk.len())]);
assert_eq!(c, byte_to_char_idx(TEXT_LINES, b));
assert_eq!(l, byte_to_line_idx(TEXT_LINES, b));
assert!(l < i);
assert!(i <= byte_to_line_idx(TEXT_LINES, b + chunk.len()));
}
{
let (chunk, b, c, l) = r.chunk_at_line_break(r.len_lines());
assert_eq!(chunk, &TEXT_LINES[(TEXT_LINES.len() - chunk.len())..]);
assert_eq!(chunk, &TEXT_LINES[b..]);
assert_eq!(c, byte_to_char_idx(TEXT_LINES, b));
assert_eq!(l, byte_to_line_idx(TEXT_LINES, b));
}
}
#[test]
fn slice_01() {
let r = Rope::from_str(TEXT);
let s = r.slice(0..r.len_chars());
assert_eq!(TEXT, s);
}
#[test]
fn slice_02() {
let r = Rope::from_str(TEXT);
let s = r.slice(5..21);
assert_eq!(&TEXT[5..21], s);
}
#[test]
fn slice_03() {
let r = Rope::from_str(TEXT);
let s = r.slice(31..97);
assert_eq!(&TEXT[31..109], s);
}
#[test]
fn slice_04() {
let r = Rope::from_str(TEXT);
let s = r.slice(53..53);
assert_eq!("", s);
}
#[test]
#[should_panic]
fn slice_05() {
let r = Rope::from_str(TEXT);
r.slice(53..52);
}
#[test]
#[should_panic]
fn slice_06() {
let r = Rope::from_str(TEXT);
r.slice(102..104);
}
#[test]
fn eq_rope_01() {
let r = Rope::from_str("");
assert_eq!(r, r);
}
#[test]
fn eq_rope_02() {
let r = Rope::from_str(TEXT);
assert_eq!(r, r);
}
#[test]
fn eq_rope_03() {
let r1 = Rope::from_str(TEXT);
let mut r2 = r1.clone();
r2.remove(26..27);
r2.insert(26, "z");
assert_ne!(r1, r2);
}
#[test]
fn eq_rope_04() {
let r = Rope::from_str("");
assert_eq!(r, "");
assert_eq!("", r);
}
#[test]
fn eq_rope_05() {
let r = Rope::from_str(TEXT);
assert_eq!(r, TEXT);
assert_eq!(TEXT, r);
}
#[test]
fn eq_rope_06() {
let mut r = Rope::from_str(TEXT);
r.remove(26..27);
r.insert(26, "z");
assert_ne!(r, TEXT);
assert_ne!(TEXT, r);
}
#[test]
fn eq_rope_07() {
let r = Rope::from_str(TEXT);
let s: String = TEXT.into();
assert_eq!(r, s);
assert_eq!(s, r);
}
#[test]
fn to_string_01() {
let r = Rope::from_str(TEXT);
let s: String = (&r).into();
assert_eq!(r, s);
}
#[test]
fn to_cow_01() {
use alloc::borrow::Cow;
let r = Rope::from_str(TEXT);
let cow: Cow<str> = (&r).into();
assert_eq!(r, cow);
}
#[test]
fn to_cow_02() {
use alloc::borrow::Cow;
let r = Rope::from_str(TEXT);
let cow: Cow<str> = (r.clone()).into();
assert_eq!(r, cow);
}
#[test]
fn to_cow_03() {
use alloc::borrow::Cow;
let r = Rope::from_str("a");
let cow: Cow<str> = (&r).into();
if let Cow::Owned(_) = cow {
panic!("Small Cow conversions should result in a borrow.");
}
assert_eq!(r, cow);
}
#[test]
fn from_rope_slice_01() {
let r1 = Rope::from_str(TEXT);
let s = r1.slice(..);
let r2: Rope = s.into();
assert_eq!(r1, r2);
assert_eq!(s, r2);
}
#[test]
fn from_rope_slice_02() {
let r1 = Rope::from_str(TEXT);
let s = r1.slice(0..24);
let r2: Rope = s.into();
assert_eq!(s, r2);
}
#[test]
fn from_rope_slice_03() {
let r1 = Rope::from_str(TEXT);
let s = r1.slice(13..89);
let r2: Rope = s.into();
assert_eq!(s, r2);
}
#[test]
fn from_rope_slice_04() {
let r1 = Rope::from_str(TEXT);
let s = r1.slice(13..41);
let r2: Rope = s.into();
assert_eq!(s, r2);
}
#[test]
fn from_iter_01() {
let r1 = Rope::from_str(TEXT);
let r2: Rope = Rope::from_iter(r1.chunks());
assert_eq!(r1, r2);
}
}