#[derive(Debug, Clone, Copy)]
enum Kind { Ins, Del }
use std::cell::{Ref, RefCell};
use std::fmt::{Debug, Display, Formatter};
use std::ops::{Deref, DerefMut, Range};
use Op::*;
use crate::fast_str_tools::{char_to_byte_idx, count_chars};
use crate::JumpRope;
pub struct JumpRopeBuf(RefCell<(JumpRope, BufferedOp)>);
#[derive(Debug, Clone)]
struct BufferedOp {
kind: Kind,
ins_content: String,
range: Range<usize>,
}
#[derive(Debug, Clone, Copy)]
enum Op<'a> {
Ins(usize, &'a str),
Del(usize, usize), }
impl BufferedOp {
fn new() -> Self {
Self {
kind: Kind::Ins,
ins_content: "".to_string(),
range: Range::default(),
}
}
fn is_empty(&self) -> bool {
self.range.is_empty()
}
fn len(&self) -> usize {
self.range.len()
}
fn clear(&mut self) {
self.ins_content.clear();
self.range = Range::default();
}
fn try_append(&mut self, op: Op) -> Result<(), ()> {
if self.is_empty() {
match op {
Ins(pos, content) => {
self.kind = Kind::Ins;
self.ins_content.push_str(content);
self.range.start = pos;
self.range.end = pos + count_chars(content);
}
Del(start, end) => {
self.kind = Kind::Del;
debug_assert!(self.ins_content.is_empty());
self.range = start..end;
}
}
Ok(())
} else {
match (self.kind, op) {
(Kind::Ins, Op::Ins(pos, content)) if pos == self.range.end => {
self.ins_content.push_str(content);
self.range.end += count_chars(content);
Ok(())
}
(Kind::Ins, Op::Del(start, end)) if end == self.range.end && start >= self.range.start => {
if start == self.range.start {
self.ins_content.clear();
self.range.end = self.range.start;
Ok(())
} else {
let char_offset = start - self.range.start;
let byte_offset = if self.range.len() == self.ins_content.len() {
char_offset
} else {
char_to_byte_idx(self.ins_content.as_str(), char_offset)
};
self.range.end = start;
self.ins_content.truncate(byte_offset);
Ok(())
}
}
(Kind::Del, Op::Del(start, end)) if start <= self.range.start && end >= self.range.start => {
self.range.end += end - self.range.start;
self.range.start = start;
Ok(())
}
(_, _) => Err(()),
}
}
}
}
impl From<JumpRope> for JumpRopeBuf {
fn from(rope: JumpRope) -> Self {
Self::with_rope(rope)
}
}
impl JumpRopeBuf {
pub fn with_rope(rope: JumpRope) -> Self {
Self(RefCell::new((rope, BufferedOp::new())))
}
pub fn new() -> Self {
Self::with_rope(JumpRope::new())
}
pub fn new_from_str(s: &str) -> Self {
Self::with_rope(JumpRope::from(s))
}
fn flush_mut(inner: &mut (JumpRope, BufferedOp)) {
if !inner.1.is_empty() {
match inner.1.kind {
Kind::Ins => {
inner.0.insert(inner.1.range.start, &inner.1.ins_content);
},
Kind::Del => {
inner.0.remove(inner.1.range.clone());
}
}
inner.1.clear();
}
}
fn internal_push_op(&mut self, op: Op) {
let inner = self.0.get_mut();
match inner.1.try_append(op) {
Ok(_) => {}
Err(_) => {
Self::flush_mut(inner);
inner.1.try_append(op).unwrap();
}
}
}
pub fn insert(&mut self, pos: usize, content: &str) {
self.internal_push_op(Op::Ins(pos, content))
}
pub fn remove(&mut self, range: Range<usize>) {
self.internal_push_op(Op::Del(range.start, range.end))
}
pub fn len_chars(&self) -> usize {
let borrow = self.0.borrow();
match borrow.1.kind {
Kind::Ins => borrow.0.len_chars() + borrow.1.range.len(),
Kind::Del => borrow.0.len_chars() - borrow.1.range.len()
}
}
pub fn len_bytes(&self) -> usize {
let mut borrow = self.0.borrow_mut();
match borrow.1.kind {
Kind::Ins => borrow.0.len_bytes() + borrow.1.ins_content.len(),
Kind::Del => {
Self::flush_mut(borrow.deref_mut());
borrow.0.len_bytes()
}
}
}
pub fn is_empty(&self) -> bool {
let borrow = self.0.borrow();
let len_chars = borrow.0.len_chars();
match borrow.1.kind {
Kind::Ins => len_chars == 0 && borrow.1.is_empty(),
Kind::Del => len_chars - borrow.1.len() == 0,
}
}
pub fn into_inner(self) -> JumpRope {
let mut contents = self.0.into_inner();
Self::flush_mut(&mut contents);
contents.0
}
pub fn borrow(&self) -> Ref<'_, JumpRope> {
let mut borrow = self.0.borrow_mut();
Self::flush_mut(borrow.deref_mut());
drop(borrow);
Ref::map(self.0.borrow(), |(rope, _)| rope)
}
fn eq_str(&self, s: &str) -> bool {
self.borrow().deref().eq(s)
}
}
impl AsMut<JumpRope> for JumpRopeBuf {
fn as_mut(&mut self) -> &mut JumpRope {
let inner = self.0.get_mut();
Self::flush_mut(inner);
&mut inner.0
}
}
impl Default for JumpRopeBuf {
fn default() -> Self {
JumpRopeBuf::new()
}
}
impl Debug for JumpRopeBuf {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let inner = self.0.borrow();
f.debug_struct("BufferedRope")
.field("op", &inner.1)
.field("rope", &inner.0)
.finish()
}
}
impl Display for JumpRopeBuf {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
for s in self.borrow().substrings() {
f.write_str(s)?;
}
Ok(())
}
}
impl Clone for JumpRopeBuf {
fn clone(&self) -> Self {
let inner = self.0.borrow();
Self(RefCell::new((inner.0.clone(), inner.1.clone())))
}
}
impl<S: AsRef<str>> From<S> for JumpRopeBuf {
fn from(str: S) -> Self {
JumpRopeBuf::new_from_str(str.as_ref())
}
}
impl<T: AsRef<str>> PartialEq<T> for JumpRopeBuf {
fn eq(&self, other: &T) -> bool {
self.eq_str(other.as_ref())
}
}
impl PartialEq<str> for JumpRopeBuf {
fn eq(&self, other: &str) -> bool {
self.eq_str(other)
}
}
impl PartialEq<String> for &JumpRopeBuf {
fn eq(&self, other: &String) -> bool {
self.eq_str(other.as_str())
}
}
impl PartialEq<JumpRope> for JumpRopeBuf {
fn eq(&self, other: &JumpRope) -> bool {
self.borrow().eq(other)
}
}
impl PartialEq<JumpRopeBuf> for JumpRopeBuf {
fn eq(&self, other: &JumpRopeBuf) -> bool {
std::ptr::eq(self as *const _, other as *const _)
|| self.borrow().eq(other.borrow().deref())
}
}
impl Eq for JumpRopeBuf {}
#[cfg(test)]
mod test {
use crate::JumpRopeBuf;
#[test]
fn is_empty() {
let mut r = JumpRopeBuf::new();
assert!(r.is_empty());
r.insert(0, "hi");
assert!(!r.is_empty());
r.borrow();
r.remove(0..2);
assert!(r.is_empty());
}
#[test]
fn eq_reflexive() {
let r = JumpRopeBuf::new();
assert_eq!(r, r);
}
}