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
|
/// A block of text, contiguous in memory
|
||||||
pub struct TextBlock {
|
pub struct TextBlock {
|
||||||
|
@ -7,14 +6,27 @@ pub struct TextBlock {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextBlock {
|
impl TextBlock {
|
||||||
|
/// Create a new empty text block.
|
||||||
pub fn new() -> TextBlock {
|
pub fn new() -> TextBlock {
|
||||||
TextBlock {
|
TextBlock {
|
||||||
data: Vec::<u8>::new()
|
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) {
|
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
|
// Grow data size
|
||||||
self.data.grow(text.len(), 0);
|
self.data.grow(text.len(), 0);
|
||||||
|
@ -22,7 +34,7 @@ impl TextBlock {
|
||||||
// Move old bytes forward
|
// Move old bytes forward
|
||||||
let mut from = self.data.len() - text.len();
|
let mut from = self.data.len() - text.len();
|
||||||
let mut to = self.data.len();
|
let mut to = self.data.len();
|
||||||
while from > ins {
|
while from > pos {
|
||||||
from -= 1;
|
from -= 1;
|
||||||
to -= 1;
|
to -= 1;
|
||||||
|
|
||||||
|
@ -30,12 +42,47 @@ impl TextBlock {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy new bytes in
|
// Copy new bytes in
|
||||||
let mut i = ins;
|
let mut i = pos;
|
||||||
for b in text.bytes() {
|
for b in text.bytes() {
|
||||||
self.data[i] = b;
|
self.data[i] = b;
|
||||||
i += 1
|
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();
|
let mut tb = TextBlock::new();
|
||||||
|
|
||||||
for _ in range(0i, 50) {
|
for _ in range(0i, 1000) {
|
||||||
tb.insert_text("Hello", 0);
|
tb.insert_text("Hello", 0);
|
||||||
tb.insert_text("Goodbye", 0);
|
tb.insert_text("Goodbye", 0);
|
||||||
tb.insert_text(args.arg_file.as_slice(), 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