大まかな外枠の表示ができたので編集用データの構造体を作っていきたいとおもいます。
エディター向けの構造体を調べたところ、Gap BufferやRope、Peace Table等があるようです。1 2 3 4
ただしこれらは行単位でデータを持つ前提のようなのでバイナリのような一塊のデータを扱う上で便利なのかどうかわかりませんでした。
後でデータ構造は変更するかもしれませんが、Vecでも良さそうなのですが、とりあえずVecDequeを使っていこうとおもいます。
BinDataという構造体を定義して編集用バッファとしたいとおもいます。
// 編集用構造体
struct BinData {
buf: VecDeque<u8>,
}
impl BinData {
pub(crate) fn new() -> Self {
BinData { buf: VecDeque::new() }
}
pub(crate) fn push_back(&mut self, new_buf: Vec<u8>) {
let mut new_data: VecDeque<u8> = VecDeque::from(new_buf);
self.buf.make_contiguous();
self.buf.append(&mut new_data);
}
pub(crate) fn insert(&mut self, index: usize, value: u8) {
self.buf.make_contiguous();
self.buf.insert(index, value);
}
pub(crate) fn update(&mut self, index: usize, value: u8) {
self.buf.make_contiguous();
if let Some(elem) = self.buf.get_mut(index) {
*elem = value;
}
}
pub(crate) fn buf(&self) -> &[u8] {
let (res, _) = self.buf.as_slices();
res
}
}
impl From<Vec<u8>> for BinData {
fn from(buf: Vec<u8>) -> Self {
BinData { buf: VecDeque::from(buf) }
}
}
impl Default for BinData {
fn default() -> Self {
Self::new()
}
}
バイナリエディタは普段使いしている訳ではないのでどのような機能の需要があるのかわからないのですが、データを読み込んで必要な箇所だけ書き換えるというのが経験上多いです。
そのため、当面は上記のメソッドだけで十分かな、とおもいます。
データの読み込みはVecから渡される想定で下記のような形でデータ読み込みを想定します。
// 仮データ
let mut bin_data = BinData::new();
bin_data.push_back(vec![
0x01, 0x02, 0x03, 0x00, 0x63, 0x71, 0x00, 0x61, 0x62, 0x0f, 0x01, 0x02, 0x03, 0x00, 0x63,
0x71, 0x0f, 0x61, 0x62, 0x63, 0x01, 0xff, 0x03, 0x00, 0x63, 0x71, 0x0f, 0x61, 0x62, 0x63,
]);
トレイト
BinDataの定義の中でimpl From<Vec<u8>> for BinData {
の文があります。
これはFromトレイトをBinDataに実装する、という文です。
トレイトとは、様々な型でも使えそうなメソッドや関数等の機能が集まったものです。5
例えば、u8やi16で足し算や引き算、Vecや配列にイテレータ処理をする操作は共通の機能として個々にまとめることができます。
このまとめたものがトレイトになります。例えばイテレータの機能をまとめたものはIteratorトレイトです。
トレイトを利用することで処理を個別に実装する手間が省けたり共通化できます。
プログラミングに於ける一種のインターフェイスやポリモーフィズム、ダックタイピング的なものと理解できるかもしれません。
- Windows 用テキストエディタ viviさんの技術文書が詳しい。その1、その2 ↩︎
- 同じくvivi作者の方ですね。その3 ↩︎
- Ropeについてはこちらが参考になります。その1、その2 ↩︎
- PeaceTableについてはこちらが参考になります。その1 ↩︎
- メソッド定義等なく識別子として機能するマーカートレイトというものもあります。 ↩︎
TOC
- 準備
- ターミナル入出力を試す
- ターミナル系crateを利用する
- 編集データと表示処理
- 画面制御
- その他
GitHubにコードをアップロードしています。
コードのコメントに書かれているfirst_stepなどをcargoコマンドに渡すと実行できます。
# Example
$ cargo run --examples first_step