Emacsバッファ内のRustコードを手軽に実行する

More than 1 year has passed since last update.

シュッと実行するという記事を読んで、掲題のようなことをやりたかったことを思い出し、cargo-scriptのインストールを試してみたところ、手元のWindows環境だとgccがないために失敗してしまったので、代替物を作ってみた、という話。

まあ、これだけであればgccをインストールすれば良いだけなのですが、自分の要件的にはcargo-scriptほど本格的なものは必要なく、逆により手軽な記述ができた方が嬉しかった、というのも作った理由(後付け)の一つ。

作成物はevalrs。コード行数的には100行くらいの短いもの。

以降は使い方などの簡単な説明。

インストール

コマンドのインストールはcargoを使えばOK:

$ cargo install evalrs

使い方

コマンドとしては標準入力から受け取ったRustコードを評価・実装するだけの単機能なもの:

$ echo 'println!("Hello World!")' | evalrs
   Compiling evalrs_temp v0.0.0 (file:///tmp/evalrs_temp.zseDeaC77GHQ)
    Finished debug [unoptimized + debuginfo] target(s) in 0.22 secs
     Running `target\debug\evalrs_temp.exe`
Hello World!

extern crate ${CRATE}がコード中に含まれる場合には${CRATE}の最新バージョン("*")を使用して実行される:

$ echo 'extern crate num_cpus; println!("{} logical CPUs", num_cpus::get())' | evalrs
    Updating registry `https://github.com/rust-lang/crates.io-index`
 Downloading num_cpus v1.2.0
 Downloading libc v0.2.18
   Compiling libc v0.2.18
   Compiling num_cpus v1.2.0
   Compiling evalrs_temp v0.0.0 (file:///tmp/evalrs_temp.4alAAhU4VF8J)
    Finished debug [unoptimized + debuginfo] target(s) in 0.57 secs
     Running `target\debug\evalrs_temp.exe`
4 logical CPUs

一度取得およびビルドされたcrateはstd::env::temp_dir().join("evalrs_cache/")以下に保存され、次回以降はそれが再利用される (正確にはダウンロードのキャッシュはcargoの標準機能に含まれているので、evalrsが行っているのはビルド物のキャッシュのみ):

$ echo 'extern crate num_cpus; println!("{} logical CPUs", num_cpus::get())' | evalrs
    Updating registry `https://github.com/rust-lang/crates.io-index`
   Compiling evalrs_temp v0.0.0 (file:///tmp/evalrs_temp.R9D7QQUinyBM)
    Finished debug [unoptimized + debuginfo] target(s) in 0.23 secs
     Running `target\debug\evalrs_temp.exe`
4 logical CPUs

Emacsから使う

quickrunパッケージを使う場合の方法の紹介。
まず上のリンク先のドキュメントに従って、Emacsにインストールしておく。

その後、(例えば)以下の設定を.emacsファイルに追加しevalrsコマンドがquickrun経由で実行可能なようにする:

.emacs
(quickrun-add-command
 "evalrs"
 '((:command . "evalrs")
   (:exec . ("cat %s | %c %a")))
 :default "evalrs")

; ビルド or 実行に時間が掛かる(10秒以上)場合は、以下の行をコメントアウトしてタイムアウト時間を延ばす
; (setq-default quickrun-timeout-seconds 180)

これで準備は整ったので、後は適当なEmacsバッファにRustのコードを入力し、quickrunを叩けばOK:

*rust-eval-buffer*
fn fib (n: usize) -> usize {
    if n < 2 {
        n
    } else {
        fib(n - 1) + fib(n - 2)
    }
}

println!("fib(10) = {}", fib(10));

// 以下を実行:
//     M-x quickrun RET evalrs RET
//
// 出力結果:
//   Compiling evalrs_temp v0.0.0 (file:///tmp/evalrs_temp.PCwV9N95yi5o)
//    Finished debug [unoptimized + debuginfo] target(s) in 0.26 secs
//     Running `target\debug\evalrs_temp.exe`
// fib(10) = 55

現状はかなり限られた機能しかないですが、とりあえずこれでEmacs上から手軽にcrateや関数の挙動が試せるようになったので、結構満足しています。

追記: 2016-12-07

quickrunの実行を以下のようにキーボードショートカットに登録したら、だいぶ利便性が上がりました。
(ついでにrustfmtも合わせて適用)

(global-set-key
 (kbd "C-c C-c C-q")
 '(lambda ()
    (interactive)
    (rust-format-buffer)
    (quickrun :source
              '((:command . "evalrs")
                (:exec . ("cat %s | %c %a"))))))