🏃

Rust/AtCoder cargo compete オリジナル快適設定

2023/05/04に公開

RustでAtCoderに参加するとき、cargo competeを使用している人は多いと思いますが、いくつか面倒だなと思っている点を解決する快適な設定を考えてみたので、共有します。

  • オリジナルテンプレート設定
  • release設定
  • コンテスト生成用スクリプト
  • デバッグ用スクリプト

プロジェクト構成

構成は以下の通りです。
通常はないオリジナルのファイルやディレクトリの内容は以下の通りです。

  • atcoder.sh: コンテスト生成用スクリプト
  • run.sh: デバッグ用スクリプト(自動生成)
  • .vscode/settings.json: Rustのvscode設定ファイル(自動生成)
./
├─compete.toml
├─template-cargo-lock.toml
├─atcoder.sh
├─abc193
│  ├─.vscode
│  │  └─settings.json
│  ├─Cargo.toml
│  ├─Cargo.lock
│  ├─run.sh
│  ├─src      
│  │  └─bin   
│  └─testcases

オリジナルテンプレート設定

テンプレート設定は、compete.toml[template]で設定することができます。

デフォルトは以下の通りです。
自作のライブラリをスニペット設定してもよいですが、以下に貼り付けておくのも有りです!

src = '''
fn main() {
    todo!();
}

テンプレートの一例です。

src = '''
#![allow(non_snake_case)]
#![allow(unused_imports)]
#![allow(unused_macros)]
#![allow(clippy::needless_range_loop)]
#![allow(clippy::comparison_chain)]
#![allow(clippy::nonminimal_bool)]
#![allow(clippy::neg_multiply)]
#![allow(dead_code)]
use itertools::Itertools;
use std::collections::{BTreeMap, BTreeSet, VecDeque};

use proconio::{
    fastout, input,
    marker::{Chars, Usize1},
};

const MOD: usize = 1e9 as usize + 7;
// const MOD: usize = 998244353;
// const MOD: usize = 2147483647;

#[macro_export]
macro_rules! max {
    ($x: expr) => ($x);
    ($x: expr, $( $y: expr ),+) => {
        std::cmp::max($x, max!($( $y ),+))
    }
}
#[macro_export]
macro_rules! min {
    ($x: expr) => ($x);
    ($x: expr, $( $y: expr ),+) => {
        std::cmp::min($x, min!($( $y ),+))
    }
}
#[derive(Default)]
struct Solver {}
impl Solver {
    #[fastout]
    fn solve(&mut self) {
        // let mut stdin = LineSource::new(BufReader::new(io::stdin()));
        // macro_rules! input(($($tt:tt)*) => (proconio::input!(from &mut stdin, $($tt)*)));
        input! {

        }
    }
}

fn main() {
    std::thread::Builder::new()
        .stack_size(128 * 1024 * 1024)
        .spawn(|| Solver::default().solve())
        .unwrap()
        .join()
        .unwrap();
}

release設定

cargo competeはデフォルトで、--releaseが付与されていないので、Rust本来の実行速度で動作しません。
実行速度があまり問題にならないのではれば、不要ですが、cargo compete testでTLEになってしまい、提出したらACした、ということが起こりえます。
そのため、基本的に以下のコマンドの通り、--releaseを付与しておくことをオススメします。
※最初だけコンパイルに時間を要します

cargo compete test a --release
cargo compete submit a --release

いちいち--releaseを付与するのが面倒であれば、Cargo.tomlに以下を追記することで、付与しなくてスクリプトもreleaseと同等のコンパイルをします。
コンテスト中に、この記述をするのはナンセンスなので、次項の通り、コンテスト生成用スクリプトにより自動化します。

[profile.dev]
opt-level = 3

コンテスト生成用スクリプト

通常コンテストのディレクトリを生成する際は以下のコマンドにより行います。

cargo compete new abc193

これを以下に置き換えます。

./atcoder.sh abc193

atcoder.shの中身は以下の通りです。

  1. コンテストのディレクトリを生成して、移動
  2. vscodeの設定ファイル作成(echoの中身を自分が好きなように設定、フォーマッターやリンターが不要な人は削除)
  3. デバッグ用スクリプト(windows用、Macだとパスが違うので編集が必要)
  4. releaseでコンパイルするために、Cargo.tomlに設定を追記
  5. コンテストのディレクトリをvscodeで開く
# make contest directory and files
cargo compete new $1
cd $1

# make settings.json
mkdir .vscode
touch .vscode/settings.json 
echo '{
    "editor.formatOnSave": true,
    "editor.defaultFormatter": "rust-lang.rust-analyzer",
    "rust-analyzer.checkOnSave.command": "clippy",
    "rust-analyzer.checkOnSave.extraArgs": ["--", "-A", "clippy::needless_return"]
}
' >> .vscode/settings.json

# make run.sh
touch run.sh
echo '
p=`pwd`
dir=${p##*/}
p=${p///c/C:}
p=${p//\//\\}
p=${p}\\Cargo.toml
rustup run 1.42.0 cargo run --bin $dir-$1 --manifest-path $p
' >> run.sh

# add opt-level to Cargo.toml
echo '
[profile.dev]
opt-level = 3' >> Cargo.toml

# open vscode
code .

デバッグ用スクリプト

cargo compete testを使用しないで、デバッグする際は以下のコマンドにより行いますが、以下の欠点があります。

  • コマンドが長い
  • Rustのバージョンがデフォルトで1.42.0でない場合、AtCoder指定の1.42.0で実行されない
cargo run --bin abc193-a

これを以下に置き換えます。

./run.sh a

前項のコンテスト生成スクリプトで自動生成されるデバッグ用スクリプトの内容は以下の通りです。

p=`pwd`
dir=${p##*/}
p=${p///c/C:}
p=${p//\//\\}
p=${p}\\Cargo.toml
rustup run 1.42.0 cargo run --bin $dir-$1 --manifest-path $p
GitHubで編集を提案

Discussion