競技プログラミング用にRustコードを一つの.rsファイルにバンドルするCargoサブコマンドです。
更新情報はCHANGELOG.mdにあります。 また同一の内容がGitHubのリリースページにあります。
- 複数のクレートのバンドル
- cargo-udepsにより使っているライブラリだけバンドル
- 一部のクレートを除外 (
--exclude-{atcoder, codingame}-crates), - 手続き型マクロの展開 (
bin内のみ) #[macro_export]のスコープを保持#[cfg(..)]の解決- コメントおよびdocコメントの削除 (
--remove) - minify機能 (
--minify) - 生成物をコンパイルが通るかチェック
[package]
name = "library-checker"
version = "0.0.0"
edition = "2018"
[dependencies]
ac-library-rs-parted-modint = { git = "https://github.com/qryxip/ac-library-rs-parted" }
proconio = { version = "0.4.3", features = ["derive"] }
qryxip-competitive-tonelli-shanks = { git = "https://github.com/qryxip/competitive-programming-library" }
# ...use acl_modint::ModInt;
use proconio::{fastout, input};
use tonelli_shanks::ModIntBaseExt as _;
#[fastout]
fn main() {
input! {
yps: [(u32, u32)],
}
for (y, p) in yps {
ModInt::set_modulus(p);
if let Some(x) = ModInt::new(y).sqrt() {
println!("{}", x);
} else {
println!("-1");
}
}
}
mod sub {
// You can also `use` the crate in submodules.
#[allow(unused_imports)]
use proconio::input as _;
}↓
❯ cargo equip \
> --remove docs `# doc commentを除去` \
> --minify libs `# ライブラリをそれぞれ一行にminify` \
> --bin sqrt_mod `# binクレートを指定` | xsel -bSubmit Info #59239 - Library-Checker
- fixedbitset 0.4.0
- lazy_static 1.4.0
- maplit 1.0.2
- memoise 0.3.2
- multimap 0.8.3
- permutohedron 0.2.4
- proconio 0.4.3
- rustc-hash 1.1.0
- smallvec 1.6.1
- strsim 0.10.0
- whiteread 0.5.0
nightlyツールチェインとcargo-udepsもインストールしてください。
❯ rustup update nightly❯ cargo install cargo-udeps❯ cargo install cargo-equip❯ cargo install cargo-equip --git https://github.com/qryxip/cargo-equipバイナリでの提供もしています。
cargo-equipで展開できるライブラリには以下の制約があります。
-
editionは"2018"にする。"2015"はサポートしません。 -
libクレートからは手続き型マクロを利用しない。libクレートからの手続き型マクロの利用は今のところサポートしていません。pub useすることは問題ありません。 -
#[macro_export]しないマクロの中ではcrateではなく$crateを使う。macro_rules!内の$crateは$crate::extern_crate_name_in_main_crateに置き換えられます。macro_rules!内のcrateは置き換えられません。 -
3.以外の場合も可能な限り絶対パスを使わない。
cargo-equipはpathの
crateはcrate::extern_crate_name_in_main_crateに、pub(crate)はpub(in crate::extern_crate_name_in_main_crate)に置き換えます。ただしこの置き換えは必ず上手くいくかどうかがわかりません。 できる限り
crate::よりもself::とsuper::を使ってください。-use crate::foo::Foo; +use super::foo::Foo;
-
可能な限りglob importを使わない。
cargo-equipはextern preludeや
#[macro_use]を再現するためにglob importを挿入します。 glob importを使うとこれと衝突する可能性があります。 -
可能な限りライブラリを小さなクレートに分割する。
cargo-equipは「クレート内のアイテムの依存関係」を調べることはしません。 AtCoder以外に参加する場合は、出力結果を制限内(たいてい64KiB程度)に収めるためにできるだけ小さなクレートに分割してください。
. ├── a │ ├── Cargo.toml │ └── src │ └── lib.rs ├── b │ ├── Cargo.toml │ └── src │ └── lib.rs ⋮
ライブラリが用意できたら、それらをbin/example側のCargo.tomlの[dependencies]に加えてください。
コンテスト毎にツールでパッケージを自動生成しているならそれのテンプレートに加えてください。
rust-lang-ja/ac-library-rsを使いたい場合、qryxip/ac-library-rs-partedを使ってください。 本物のac-library-rsを加工したクレートです。
[dependencies]
ac-library-rs-parted = { git = "https://github.com/qryxip/ac-library-rs-parted" }
ac-library-rs-parted-convolution = { git = "https://github.com/qryxip/ac-library-rs-parted" }
ac-library-rs-parted-dsu = { git = "https://github.com/qryxip/ac-library-rs-parted" }
ac-library-rs-parted-fenwicktree = { git = "https://github.com/qryxip/ac-library-rs-parted" }
ac-library-rs-parted-lazysegtree = { git = "https://github.com/qryxip/ac-library-rs-parted" }
ac-library-rs-parted-math = { git = "https://github.com/qryxip/ac-library-rs-parted" }
ac-library-rs-parted-maxflow = { git = "https://github.com/qryxip/ac-library-rs-parted" }
ac-library-rs-parted-mincostflow = { git = "https://github.com/qryxip/ac-library-rs-parted" }
ac-library-rs-parted-modint = { git = "https://github.com/qryxip/ac-library-rs-parted" }
ac-library-rs-parted-scc = { git = "https://github.com/qryxip/ac-library-rs-parted" }
ac-library-rs-parted-segtree = { git = "https://github.com/qryxip/ac-library-rs-parted" }
ac-library-rs-parted-string = { git = "https://github.com/qryxip/ac-library-rs-parted" }
ac-library-rs-parted-twosat = { git = "https://github.com/qryxip/ac-library-rs-parted" }準備ができたらコードを書いてください。
bin/example側の制約は以下の2つです。
-
手続き型マクロを利用する場合、マクロ名が被らないように
proc-macroクレートを選択する。Rustのモジュールグラフを解析することは困難極まるため、手続き型マクロについてはプレフィックス抜きのマクロ名のみを頼りに展開します。
proc-macroクレートの跡地にはダミーのアイテムを展開するため、通常のプログラミングのように手続き型マクロをuseしても問題はありません。もし
useすることで問題が起きるなら、#[macro_use] extern crate crate_name as _;でインポートすることで、 これはuse crate::crate_name::__macros::*;に置き換えられます。cargo-equipはextern preludeや
#[macro_use]を再現するためにglob importを挿入します。 glob importを使うとこれと衝突する可能性があります。 -
可能な限りglob importを使わない。
ライブラリ同様にglob importを挿入します。
pub use __cargo_equip::prelude::*; // ︙ pub mod __cargo_equip { pub mod crates { // ︙ } // ︙ pub(crate) prelude { pub use crate::__cargo_equip::crates::*; } }
use input::input;
use mic::answer;
use partition_point::RangeBoundsExt as _;
#[answer(join("\n"))]
fn main() -> _ {
input! {
a: [u64],
}
a.into_iter()
.map(|a| (1u64..1_000_000_000).partition_point(|ans| ans.pow(2) < a))
}コードが書けたらcargo equipで展開します。
--bin {binの名前}か--example {exampleの名前}、または--src {binのファイルパス}でbin/exampleを指定してください。
パッケージ内のbin/exampleが一つの場合は省略できます。
ただしdefault-runには未対応です。
❯ cargo equip --bin "$name"cargo-equipはデフォルトで
#[cfg(恒真)](e.g.cfg(feature = "enabled-feature"))のアトリビュートを消去します。#[cfg(恒偽)](e.g.cfg(test),cfg(feature = "disable-feature"))のアトリビュートが付いたアイテムを消去します。
これは次の割り当てで判定されます。
test:falseproc_macro:falsecargo_equip:truefeature:bin/example側から見て有効化されているもののみtrue- それ以外: 不明
#[allow(dead_code)]
pub mod a {
pub struct A;
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}
}↓
#[allow(dead_code)]
pub mod a {
pub struct A;
}cargo-equipはデフォルトでバンドルしたコードを出力する前にtarget directoryを共有した一時パッケージを作り、それの上でcargo checkします。
Checking cargo-equip-check-output-6j2i3j3tgtugeaqm v0.1.0 (/tmp/cargo-equip-check-output-6j2i3j3tgtugeaqm)
Finished dev [unoptimized + debuginfo] target(s) in 0.11scargo-equipは手続き型マクロを展開する機能を持っています。
use memoise::memoise;
use proconio_derive::fastout;
#[fastout]
fn main() {
for i in 0..=10 {
println!("{}", fib(i));
}
}
#[memoise(n <= 10)]
fn fib(n: i64) -> i64 {
if n == 0 || n == 1 {
return n;
}
fib(n - 1) + fib(n - 2)
}proc-macroクレートは1.48.0以上のRustでコンパイルされる必要があります。 現在のツールチェインが1.48.0未満である場合、1.48.0以上のツールチェインを探してそれでコンパイルします。pub use $name::*;でre-exportedされた手続き型マクロも展開することができます。
--remove docsでDoc comment (//! ..,/// ..,/** .. */,#[doc = ".."])を--remove commentsでコメント (// ..,/* .. */)を
除去します。
#[allow(dead_code)]
pub mod a {
//! A.
/// A.
pub struct A; // aaaaa
}↓
#[allow(dead_code)]
pub mod a {
pub struct A;
}--minify libで展開後のライブラリをそれぞれ一行に折り畳みます。
--minify allでコード全体を最小化します。
ただ現段階では実装が適当なのでいくつか余計なスペースが挟まる場合があります。
#[cfg(…)]を解決しません。
出力をRustfmtでフォーマットするのをスキップします。
出力をcargo checkにかけるのをスキップします。
MIT or Apache-2.0のデュアルライセンスです。