競技プログラミング用にRustコードを一つの.rs
ファイルにバンドルするCargoサブコマンドです。
Point Add Range Sum - Library-Cheker
lib
側
toml
[package.metadata.cargo-equip-lib.mod-dependencies]
"algebraic" = []
"fenwick" = ["algebraic"]
"input" = []
"output" = []
bin
側
toml
[dependencies]
__lib = { package = "lib", path = "/path/to/lib" }
```rust
use ::__lib::{fenwick::AdditiveFenwickTree, input, output};
use std::io::Write as _;
fn main() { input! { n: usize, q: usize, r#as: [i64; n], }
let mut fenwick = AdditiveFenwickTree::new(n);
for (i, a) in r#as.into_iter().enumerate() {
fenwick.plus(i, &a);
}
output::buf_print(|out| {
macro_rules! println(($($tt:tt)*) => (writeln!(out, $($tt)*).unwrap()));
for _ in 0..q {
input!(kind: u32);
match kind {
0 => {
input!(p: usize, x: i64);
fenwick.plus(p, &x);
}
1 => {
input!(l: usize, r: usize);
println!("{}", fenwick.query(l..r));
}
_ => unreachable!(),
}
}
});
} ```
↓
console
$ cargo equip --oneline mods --rustfmt --check -o ./bundled.rs
Bundling code
Checking cargo-equip-check-output-b6yi355fkyhc37tj v0.1.0 (/tmp/cargo-equip-check-output-b6yi355fkyhc37tj)
Finished dev [unoptimized + debuginfo] target(s) in 0.18s
https://judge.yosupo.jp/submission/21202
console
$ cargo install cargo-equip
master
console
$ cargo install --git https://github.com/qryxip/cargo-equip
バイナリでの提供もしています。
cargo-equip
で展開できるライブラリには以下5つの制限があります。
mod $name;
)は深さ1までmod $name { .. }
)mod
以外のpub
なアイテムが置かれていない (置いてもいいですが使わないでください)#[macro_export] macro_rules! name { .. }
はmod name
の中に置かれている (それ以外の場所に置いていいですがその場合#[macro_use]
で使ってください)#[macro_export]
には組み込み以外のアトリビュート(e.g. #[rustfmt::skip]
)を使用しない (原理的に展開すると壊れる)1.と2.はそのうち対応しようと思います。
このように薄く広く作ってください。
src
├── a.rs
├── b.rs
├── c.rs
└── lib.rs
rust
// src/lib.rs
pub mod a;
pub mod b;
pub mod c;
この制限に合うようなライブラリを書いたら、そのCargo.toml
のpackage.metadata
にモジュールの依存関係を手で書いてください。
直接use
したモジュールと、その連結成分だけを展開します。
欠けている場合はwarningと共にすべてのモジュールを展開します。
toml
[package.metadata.cargo-equip-lib.mod-dependencies]
"a" = []
"b" = ["a"]
"c" = ["a"]
そしてbin
側の準備として、バンドルしたいライブラリをdependencies
に加えてください。
コンテスト毎にツールでパッケージを自動生成しているならそれのテンプレートに加えてください。
ただしこの際、ライブラリは誤って直接使わないようにリネームしておくことを強く推奨します。
直接使った場合cargo-equip
はそれについて何も操作しません。
toml
[dependencies]
__my_lib = { package = "my_lib", path = "/path/to/my_lib" }
準備ができたらこのようにattribute付きでライブラリをuse
します。
```rust
use ::_mylib::{b::B, c::C};
// or // //#[cfgattr(cargoequip, cargoequip::equip)] //use ::{ // _mylib1::{b::B, c::C}, // _my_lib2::{d::D, e::E}, //}; ```
use
のパスにはleading colon (::
)を付けてください。
```
use ::_mylib::{b::B, c::C}; ^^ ```
パスの1つ目のsegmentから展開するべきライブラリを決定します。 leading colonを必須としているのはこのためです。
```
use ::_mylib::{b::B, c::C}; ^^^^^^^^ ```
先述したライブラリの制約より、パスの第二セグメントはモジュールとみなします。
これらのモジュールと、先程書いたmod-dependencies
で繋がっているモジュールが展開されます。
```
use ::_mylib::{b::B, c::C}; ^ ^ ```
第三セグメント以降はuse self::$name::{..}
と展開されます。
```
use ::_mylib::{b::B, c::C}; ^ ^ ```
コードが書けたらcargo equip
で展開します。
--bin {binの名前}
か--src {binのファイルパス}
でbin
を指定してください。
パッケージ内のbin
が一つの場合は省略できます。
ただしdefault-run
には未対応です。
console
$ cargo equip --bin "$name"
コードはこのように展開されます。
``rust
//! # Bundled libraries
//!
//! ## [
mylib]({ a link to Crates.io or the repository })
//!
//! ### Modules
//!
//! -
::mylib::a→
$crate::a
//! -
::mylib::b→
$crate::b
//! -
::mylib::c→
$crate::c`
/#[cfg_attr(cargo_equip, cargo_equip::equip)] use ::__my_lib::{b::B, c::C};/
fn main() { todo!(); }
// The following code was expanded by cargo-equip
.
use self::b::B; use self::c::C;
// b
とc
で使われているとmod-dependencies
に記述されているため、展開される
mod a {
// ..
}
mod b { // .. }
mod c { // .. } ```
モジュールの階層が変わらないため、各ファイルの中身を手を加えずにそのまま展開します。 そのため壊れにくくなっているはずです。 多分。
またライブラリ内の#[macro_export]
しているマクロですが、マクロ名と同名のモジュールに入れておくと自然な形で使えると思います。
```rust // input.rs
macrorules! input { ($($tt:tt)*) => { compileerror!("TODO") }; } ```
```rust
use ::_mylib::input; ```
--remove <REMOVE>...
--remove test-items
で#[cfg(test)]
が付いたアイテムを--remove docs
でDoc comment (//! ..
, /// ..
, /** .. */
, #[doc = ".."]
)を--remove comments
でコメント (// ..
, /* .. */
)を除去することができます。
```rust pub mod a { //! A.
/// A.
pub struct A; // aaaaa
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}
} ```
↓
rust
pub mod a {
pub struct A;
}
--oneline <ONELINE>
--oneline mods
で展開後の各モジュールをそれぞれ一行に折り畳みます。
--oneline all
でコード全体を一行に折り畳みます。
トークン列を" "
区切りで出力しているだけなので、minificationではありません。
--rustfmt
出力をRustfmtでフォーマットします。
--check
バンドルしたコードを出力する前にtarget directoryを共有した一時パッケージを作り、それの上でcargo check
します。
console
$ cargo equip --check -o /dev/null
Bundling code
Checking cargo-equip-check-output-r3cw9cy0swqb5yac v0.1.0 (/tmp/cargo-equip-check-output-r3cw9cy0swqb5yac)
Finished dev [unoptimized + debuginfo] target(s) in 0.18s
MIT or Apache-2.0のデュアルライセンスです。