Fleshing out TextBlock's APIs.
This commit is contained in:
parent
05a9016714
commit
b1dd62f8db
|
@ -1,5 +1,4 @@
|
|||
use std::cmp::min;
|
||||
|
||||
use std::mem;
|
||||
|
||||
/// A block of text, contiguous in memory
|
||||
pub struct TextBlock {
|
||||
|
@ -7,14 +6,27 @@ pub struct TextBlock {
|
|||
}
|
||||
|
||||
impl TextBlock {
|
||||
/// Create a new empty text block.
|
||||
pub fn new() -> TextBlock {
|
||||
TextBlock {
|
||||
data: Vec::<u8>::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the length of the text block in bytes.
|
||||
pub fn len(&self) -> uint {
|
||||
self.data.len()
|
||||
}
|
||||
|
||||
/// Insert 'text' at byte position 'pos'.
|
||||
/// NOTE: this makes no attempt to preserve utf8 validity, and may
|
||||
/// insert text in the middle of multi-byte code points.
|
||||
// TODO: Do checks to prevent invalidating utf8 sequences
|
||||
pub fn insert_text(&mut self, text: &str, pos: uint) {
|
||||
let ins = min(pos, self.data.len());
|
||||
// Bounds check
|
||||
if pos > self.data.len() {
|
||||
panic!("TextBlock::insert_text(): attempt to insert text beyond end of text block.");
|
||||
}
|
||||
|
||||
// Grow data size
|
||||
self.data.grow(text.len(), 0);
|
||||
|
@ -22,7 +34,7 @@ impl TextBlock {
|
|||
// Move old bytes forward
|
||||
let mut from = self.data.len() - text.len();
|
||||
let mut to = self.data.len();
|
||||
while from > ins {
|
||||
while from > pos {
|
||||
from -= 1;
|
||||
to -= 1;
|
||||
|
||||
|
@ -30,12 +42,47 @@ impl TextBlock {
|
|||
}
|
||||
|
||||
// Copy new bytes in
|
||||
let mut i = ins;
|
||||
let mut i = pos;
|
||||
for b in text.bytes() {
|
||||
self.data[i] = b;
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove the text between byte positions 'pos_a' and 'pos_b'.
|
||||
/// NOTE: this makes no attempt to preserve utf8 validity, and may
|
||||
/// remove parts of multi-byte code points.
|
||||
// TODO: Do checks to prevent invalidating utf8 sequences
|
||||
pub fn remove_text(&mut self, pos_a: uint, pos_b: uint) {
|
||||
// Bounds checks
|
||||
if pos_a > pos_b {
|
||||
panic!("TextBlock::remove_text(): pos_a must be less than or equal to pos_b.");
|
||||
}
|
||||
if pos_b > self.data.len() {
|
||||
panic!("TextBlock::remove_text(): attempt to remove text beyond the end of text block.");
|
||||
}
|
||||
|
||||
// Move bytes to fill in the gap left by the removed bytes
|
||||
let mut from = pos_b;
|
||||
let mut to = pos_a;
|
||||
while from < self.data.len() {
|
||||
self.data[to] = self.data[from];
|
||||
|
||||
from += 1;
|
||||
to += 1;
|
||||
}
|
||||
|
||||
// Remove data from the end
|
||||
let final_size = self.data.len() + pos_a - pos_b;
|
||||
self.data.truncate(final_size);
|
||||
}
|
||||
|
||||
/// Returns an immutable string slice into the text block's memory
|
||||
pub fn as_str<'a>(&'a self) -> &'a str {
|
||||
unsafe {
|
||||
mem::transmute(self.data.as_slice())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -32,11 +32,14 @@ fn main() {
|
|||
|
||||
let mut tb = TextBlock::new();
|
||||
|
||||
for _ in range(0i, 50) {
|
||||
for _ in range(0i, 1000) {
|
||||
tb.insert_text("Hello", 0);
|
||||
tb.insert_text("Goodbye", 0);
|
||||
tb.insert_text(args.arg_file.as_slice(), 0);
|
||||
if tb.len() > 1024 {
|
||||
tb.remove_text(0, 12 + args.arg_file.len());
|
||||
}
|
||||
}
|
||||
|
||||
println!("{}", std::str::from_utf8(tb.data.as_slice()).unwrap());
|
||||
println!("{}", tb.as_str());
|
||||
}
|
Loading…
Reference in New Issue
Block a user