aboutsummaryrefslogtreecommitdiffstats
path: root/src/rope.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/rope.rs')
-rw-r--r--src/rope.rs99
1 files changed, 62 insertions, 37 deletions
diff --git a/src/rope.rs b/src/rope.rs
index 4e14d84..ab9a7bc 100644
--- a/src/rope.rs
+++ b/src/rope.rs
@@ -1,8 +1,23 @@
+use std::error::Error;
use std::io::{ErrorKind, Read, Write};
use std::rc::Rc;
const MAX_NODE_SIZE: usize = 1024;
+fn read(r: &mut dyn Read, buf: &mut [u8]) -> Result<usize, std::io::Error> {
+ loop {
+ match r.read(buf) {
+ Ok(n) => return Ok(n),
+ Err(err) => {
+ if err.kind() == ErrorKind::Interrupted {
+ continue;
+ }
+ return Err(err);
+ }
+ }
+ }
+}
+
enum Insert {
Node(Rope),
Split(Rope, Rope),
@@ -10,16 +25,16 @@ enum Insert {
#[derive(Debug, Clone)]
struct Leaf {
- unsafe_buf: Option<Rc<[u8]>>,
+ unsafe_buf: Option<Rc<str>>,
start: u16,
end: u16,
lines: u16,
}
impl Leaf {
- fn bytes(&self) -> &[u8] {
+ fn buf(&self) -> &str {
match &self.unsafe_buf {
- None => &[],
+ None => "",
Some(buf) => &buf[usize::from(self.start)..usize::from(self.end)],
}
}
@@ -44,7 +59,7 @@ pub struct Rope(Node);
impl Rope {
pub fn len(&self) -> usize {
match self {
- Rope(Node::Leaf(l)) => l.bytes().len(),
+ Rope(Node::Leaf(l)) => l.buf().len(),
Rope(Node::Branch(b)) => b.len,
}
}
@@ -67,12 +82,12 @@ impl Rope {
lines: 0,
}));
- fn leaf(buf: &[u8]) -> Rope {
+ fn leaf(buf: &str) -> Rope {
if buf.len() > MAX_NODE_SIZE {
panic!("buffer too long");
}
let mut lines = 0;
- for &b in buf.iter() {
+ for &b in buf.as_bytes().iter() {
if b == b'\n' {
lines += 1;
}
@@ -108,19 +123,20 @@ impl Rope {
fn concat_height(&self, self_height: usize, other: &Rope, other_height: usize) -> Insert {
if let (Rope(Node::Leaf(l)), Rope(Node::Leaf(r))) = (self, other) {
if self.len() + other.len() <= MAX_NODE_SIZE {
- let mut buf = Vec::with_capacity(self.len() + other.len());
- buf.extend_from_slice(l.bytes());
- buf.extend_from_slice(r.bytes());
+ let mut buf = String::with_capacity(self.len() + other.len());
+ buf.push_str(l.buf());
+ buf.push_str(r.buf());
return Insert::Node(Rope::leaf(&buf));
}
if self.len() < MAX_NODE_SIZE / 2 || other.len() < MAX_NODE_SIZE / 2 {
- let mut buf = Vec::with_capacity(self.len() + other.len());
- buf.extend_from_slice(l.bytes());
- buf.extend_from_slice(r.bytes());
- return Insert::Split(
- Rope::leaf(&buf[..buf.len() / 2]),
- Rope::leaf(&buf[buf.len() / 2..]),
- );
+ let mut buf = String::with_capacity(self.len() + other.len());
+ buf.push_str(l.buf());
+ buf.push_str(r.buf());
+ let mut half = buf.len() / 2;
+ while !buf.is_char_boundary(half) {
+ half -= 1;
+ }
+ return Insert::Split(Rope::leaf(&buf[..half]), Rope::leaf(&buf[half..]));
}
return Insert::Split(self.clone(), other.clone());
}
@@ -203,43 +219,52 @@ impl Rope {
}
}
- pub fn read(r: &mut dyn Read) -> Result<Rope, std::io::Error> {
+ pub fn read(r: &mut dyn Read) -> Result<Rope, Box<dyn Error>> {
let mut buf = vec![0; MAX_NODE_SIZE];
let mut rope = Rope::EMPTY;
+ let mut offset = 0;
loop {
- let n = match r.read(&mut buf) {
- Ok(n) => n,
+ let mut n = read(r, &mut buf[offset..])?;
+ n += offset;
+ if n == 0 {
+ break;
+ }
+ let s = match std::str::from_utf8(&buf[..n]) {
+ Ok(s) => s,
Err(err) => {
- if err.kind() == ErrorKind::Interrupted {
- continue;
+ let v = err.valid_up_to();
+ if v == 0 {
+ return Err(Box::new(err));
}
- return Err(err);
+ rope = rope.concat(&Rope::leaf(
+ std::str::from_utf8(&buf[..v]).expect("buf should be valid up to v"),
+ ));
+ offset = n - v;
+ for i in 0..offset {
+ buf[i] = buf[v + i];
+ }
+ continue;
}
};
- if n == 0 {
- break;
- }
- rope = rope.concat(&Rope::leaf(&buf[..n]));
+ rope = rope.concat(&Rope::leaf(s));
+ offset = 0;
}
Ok(rope)
}
- pub fn new(buf: &[u8]) -> Rope {
+ pub fn new(buf: &str) -> Rope {
if buf.is_empty() {
return Rope::EMPTY;
}
if buf.len() <= MAX_NODE_SIZE {
return Rope::leaf(buf);
}
- let mut buf = buf;
- Rope::read(&mut buf).expect("reading from a slice should never fail")
+ Rope::read(&mut buf.as_bytes()).expect("reading from a slice should never fail")
}
fn is_char_boundary(&self, i: usize) -> bool {
match self {
- Rope(Node::Leaf(l)) => {
- return i < l.bytes().len() && l.bytes()[i] & 0xc0 != 0x80;
- }
+ Rope(Node::Leaf(l)) => l.buf().is_char_boundary(i),
Rope(Node::Branch(b)) => {
let mut i = i;
for c in b.children.iter() {
@@ -248,7 +273,7 @@ impl Rope {
}
i -= c.len();
}
- false
+ i == 0
}
}
}
@@ -275,7 +300,7 @@ impl Rope {
match self {
Rope(Node::Leaf(l)) => {
let mut count = 0;
- for (i, &c) in l.bytes().iter().enumerate() {
+ for (i, &c) in l.buf().as_bytes().iter().enumerate() {
if c != b'\n' {
continue;
}
@@ -317,7 +342,7 @@ impl Rope {
pub fn print(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
match self {
Rope(Node::Leaf(l)) => {
- w.write_all(l.bytes())?;
+ w.write_all(l.buf().as_bytes())?;
Ok(())
}
Rope(Node::Branch(b)) => {
@@ -349,7 +374,7 @@ impl Rope {
match self {
Rope(Node::Leaf(l)) => {
let mut lines = 0;
- for &b in l.bytes()[start..end].iter() {
+ for &b in l.buf()[start..end].as_bytes().iter() {
if b == b'\n' {
lines += 1;
}
@@ -388,7 +413,7 @@ impl Rope {
panic!("Index {} out of range 0..{}", i, self.len());
}
match self {
- Rope(Node::Leaf(l)) => l.bytes()[i],
+ Rope(Node::Leaf(l)) => l.buf().as_bytes()[i],
Rope(Node::Branch(b)) => {
let mut i = i;
for c in b.children.iter() {