実装の都合で State の enum に対しては現在 Clone が要求されます。現在、標準で提供しているのは BasicStateMachine という構造体です。これは State に Clone を要求しています。実装側を見ていただくとわかるのですが、どうしても clone が必要と思われる箇所が出てくるためです。
/// The basic state machine implementation./// It holds `initial_state`, `current_state`, `transition` function.pubstructBasicStateMachine<State, Input, Transition>where
Transition: Fn(&State, Input) -> State,
State: Clone,
{
/// `initial_state` is literally an initial state of the state machine./// The field isn't updated the whole life of its state machine./// That is, it always returns its initial state of its machine.
initial_state: State,
/// `current_state` is the current state of the state machine./// It transit to the next state via `transition`.
current_state: RefCell<StateWrapper<State>>,
/// `transition` is the definition of state transition./// See an example of [`StateMachine::consume()`], you can grasp how/// to define the transition.
transition: Transition,
_maker: PhantomData<Input>,
}
もし State に Clone を要求するのが、大きなパフォーマンス劣化を招く原因になりうるのだとしたら、この Clone の制約を外せるように実装を調整する必要があるのかなと思っています。が、正直これをどう上手に調整したらよいかの想像がついていません。このあたりのワークアラウンドは結構迷ってます…。
ドキュメントを書くのはかなり骨の折れる作業で、主にサンプルコードの用意の部分で結構手間取りました。ただ、サンプルコードを用意しておくと、cargo test したタイミングで doc test が走り、コメント内のコードのコンパイルが通るかや assertion が通るかを自動でチェックしてくれます。ドキュメントのメンテ漏れに気づけるようになるので、この仕組みは非常に素晴らしいです。ちなみに他の言語での経験だと Python でも同じことができますね。
Tour of Rust [一部邦訳]: これは現時点で最初の一歩におすすめできる資料かなと思います。Go 言語には A Tour of Go という、Go を始める際にうってつけな教材があります。それの Rust 版です。Rust の文法を1ページ1ページ解説しつつ、横で Playground を使ってコードを実際に実行して挙動を確かめるところまでセットでできます。まずこれを軽く通してみて、簡単に文法の概観を掴むとよいのではないかと思います。
Rust by Example: 文法の細かい解説というよりは、サンプルスクリプトを通じて Rust を学んでいける資料に仕上がっています。細かい解説はいいから、とりあえずサクサク写経しつつ概観を掴んで実際にアプリケーションを作って学んでいきたい、という方におすすめできるかなと思います。
Command Line Applications in Rust [未邦訳]: 非常に小さな機能を持つgrepの実装を通じて、Rustの文法機能の実践面での使い方も理解することまでが視野に入ったチュートリアルです。CLIツールの自作はRustで作りたいものがとくにない方にとくにおすすめです。grep以外にも、たとえばlsなどを実装してみてもおもしろいのではないかと思います。
Writing OS in Rust: Rust は OS を作るのに適した言語なのですが、Rust で OS を作るチュートリアルです。一方でただ OS を作るだけではなく、Rust の細かい機能の解説や文法の解説、ワークアラウンドの解説などが記事のなかに散りばめられています。
Rustで始める自作組込みOS入門: Rust でマイコン上で動作する組み込みの OS を作るチュートリアルです。ARMv7-M を題材に、割り込み、プロセスの切り替え、スケジューラまでを実装していきます。組み込みOSの開発に興味がある場合にはよい題材となるはずです。
Let's build a browser engine! [未邦訳]: Rust でブラウザエンジンを実装するチュートリアルです。最終的に HTML と CSS をパースし、その情報から画面に結果を描画するところまで作り上げられます。HTML パーサーなどでハードに代数データとパターンマッチを使うことになるので、その練習にいいかもしれません。
「最近話題の RISC-V などの CPU エミュレータを作ってみたいものの、いきなり作るにはハードルが高い。何か簡単なもので素振りをして CPU の動作の仕組みをまずは知りたい」という方にはかなりオススメできる教材だと思います。私自身、TD4 のエミュレータを実装してみて CPU の動作原理やコンセプトがわかり、その後製作中の RISC-V エミュレータに生きているように思います。
現在どの番地のプログラムを読み出しているかについては、プログラムカウンタ(pc)と呼ばれるフラグによって管理されます。先ほどの fetch-decode-execute サイクルが1サイクル終了するとプログラムカウンタが足され、次のプログラムを読み出し、ということを ROM の配列が終了するまで行うことになります。
まず fetch です。ここでは現状のプログラムカウンタの値を確認し、プログラムカウンタに該当するプログラムを ROM から読み取ります。
(...)
fnfetch(&self) ->u8 {
let pc =self.register.borrow().pc();
ifself.rom.borrow().size() <= pc {
return0;
}
let code =self.rom.borrow().read(pc);
code
}
(...)
(...)
let rom =Rom::new(program);
let register =Register::new();
let port =Port::new(0b0000, 0b0000);
let emulator =CpuEmulator::with(register, port, rom);
match emulator.exec() {
Ok(_) => (),
Err(err) =>panic!("{:?}", err),
}
(...)
この場合ですと、空白で split をかけると、mov, A, 0001 という文字列が取得できます。TD4 の場合、命令がとても単純なので、たとえば mov の後ろには必ず A か B という文字列が来ているはず、といった感じでシンプルに条件分岐をしながらパースしていくと、一通り命令をパースして解釈できるようになります。
(...)
pubfnparse(&mutself) ->Result<Vec<Token>, EmulatorErr> {
letmut result =Vec::new();
loop {
let op =self.source.get(self.pos);
if op.is_none() {
break;
}
let op = op.unwrap();
if op =="mov" {
self.pos +=1;
let lhs =self
.source
.get(self.pos)
.ok_or_else(||EmulatorErr::new("Failed to parse mov left hand side value"))?;
self.pos +=1;
let rhs =self
.source
.get(self.pos)
.ok_or_else(||EmulatorErr::new("Failed to parse mov right hand side value"))?;
let token =if lhs =="B"&& rhs =="A" {
Token::MovBA
} elseif lhs =="A"&& rhs =="B" {
Token::MovAB
} else {
Token::Mov(
Register::from(lhs.to_string()),
self.from_binary_to_decimal(rhs)?,
)
};
result.push(token);
}
(...)
GATs というのは先ほども軽く触れたとおり、関連型に何かしらの型パラメータ(A や T みたいなもの)をもたせることができる機能です。Rust にいわゆる高階カインド型を導入するための機能です。
Rust の場合は、他の言語でもあるような型パラメータ以外にもライフタイム注釈*7をこの位置に入れることができます。つまり、型パラメータの位置に入るのは A というような型情報と、もうひとつは 'a というライフタイム注釈が来ることになります。GATs はこれら2つを関連型で扱えるようにするための機能です。
*7:Rust にはダングリングポインタを防止するための仕組みとしてライフタイムという概念が存在します。このライフタイムというのは、ユーザーがライフタイム注釈を個別に指定してライフタイムを明示的に書くこともできるようになっています。ライフタイム注釈というのは 'a というようにシングルクオートで始まる形で、通常の型情報と同じ位置(<> 内)に入れて書きます。
1ヶ月ほど経ってしまいましたが、Rust の全世界的なカンファレンス RustFest Global を、11/7〜11/8で開催しました。スピーカーとして参加してくださった皆さん、また RustFest Global に遊びに来てくださった皆さん、ありがとうございました。
今日はその RustFest Global に関する話を書きたいと思います。ちなみに多分この記事を Google 翻訳にかけて読まれる海外の方も多いと思うので、先に書きます。英語にするので少しお待ち下さい!
For non Japanese speakers: I'm going to jot down my thoughts regarding RustFest Global. Unfortunately, there is no English version right now. I'm planning to translate this post into English soon. Please gimme a moment!
RustFest Global 2020 is almost over, but make sure you don’t miss the last performance by @linalab && !ME, an exploration about the analogue and manual side of both music and visuals. Tune in on https://t.co/yLfjDUFuNF and celebrate the ending with us! 🥳 pic.twitter.com/e3RBQV1S9G
ツールに関するローカライゼーションなどもあるでしょう。たとえばメッセージングアプリに関して言えば、海外では WhatsApp が大半ですが日本では LINE が大半といった具合にです。日本では使い慣れないツールを使う必要が出てくると、どうしても操作に慣れなくてストレスが…といったこともあるかもしれません。
❯ idrin --help
idrin: not support subcmd --help yet
CallStack (from HasCallStack):
error, called at src/Idringen.hs:28:24 in drngn-0.1.0.3-b556eddc:Idringen