pico-args
極めて軽量でシンプルな引数パーサー。最小限の機能と高速な処理が特徴です。
フレームワーク
pico-args
概要
pico-argsは、極めて軽量でシンプルな引数パーサーです。最小限の機能と高速な処理が特徴で、依存関係ゼロで実装されています。シンプルなCLIツールや組み込みシステムでの使用に適しており、軽量性を重視する場合に選択されます。
詳細
pico-argsは、RazrFalconによって開発された最小限のコマンドライン引数パーサーです。「pico」という名前が示すように、極小サイズと高速処理を目指して設計されており、標準ライブラリ以外の依存関係を持ちません。複雑な機能は提供せず、基本的な引数解析のみに焦点を当てることで、軽量性と高いパフォーマンスを実現しています。
主な特徴
- 極軽量: 非常に小さなフットプリントと最小限の依存関係
- 高速処理: オーバーヘッドを最小限に抑えた高速な引数解析
- シンプルAPI: 直感的で理解しやすいAPIデザイン
- ゼロ依存: 標準ライブラリ以外の依存関係なし
- 型安全: Rustの型システムを活用した安全な引数処理
- カスタムパーサー: 独自の値変換関数の実装が可能
- エラーハンドリング: 明確なエラー型による適切なエラー処理
メリット・デメリット
メリット
- 最小限のフットプリント: 非常に軽量でリソース使用量が少ない
- 高速: 引数解析のオーバーヘッドが極めて少ない
- シンプル: 学習コストが低く、すぐに使い始められる
- 依存関係なし: 外部ライブラリに依存しない独立性
- 組み込み向け: リソース制約がある環境に適している
デメリット
- 機能制限: 高度なCLI機能(ヘルプ生成、サブコマンド)は提供されない
- 手動実装: ヘルプメッセージや複雑な構造は手動で実装する必要
- 大規模向けではない: 複雑なCLIアプリケーションには不向き
- エコシステム: 他のCLIライブラリとの統合機能は限定的
主要リンク
書き方の例
use pico_args;
use std::path::PathBuf;
#[derive(Debug)]
struct Config {
// 必須の数値パラメータ
count: u32,
// オプショナルな文字列パラメータ
name: Option<String>,
// デフォルト値を持つパラメータ
timeout: u64,
// 入力ファイルパス
input: PathBuf,
// 出力ファイルパス(オプション)
output: Option<PathBuf>,
// フラグ
verbose: bool,
}
fn main() {
let config = match parse_args() {
Ok(config) => config,
Err(e) => {
eprintln!("引数解析エラー: {}", e);
std::process::exit(1);
}
};
println!("設定: {:#?}", config);
if config.verbose {
println!("詳細モードが有効です");
}
println!("入力ファイル: {:?}", config.input);
if let Some(output) = &config.output {
println!("出力ファイル: {:?}", output);
}
}
fn parse_args() -> Result<Config, pico_args::Error> {
let mut pargs = pico_args::Arguments::from_env();
// ヘルプフラグの確認
if pargs.contains(["-h", "--help"]) {
print_help();
std::process::exit(0);
}
// 各引数の解析
let config = Config {
// 必須パラメータ(カスタムパーサー使用)
count: pargs.value_from_fn("--count", |s| {
s.parse::<u32>().map_err(|_| "数値が必要です")
})?,
// オプショナルパラメータ
name: pargs.opt_value_from_str("--name")?,
// デフォルト値付きパラメータ
timeout: pargs.opt_value_from_str("--timeout")?.unwrap_or(30),
// フラグ(存在するかどうか)
verbose: pargs.contains(["-v", "--verbose"]),
// 必須の位置引数(入力ファイル)
input: pargs.free_from_str()?,
// オプショナルな位置引数(出力ファイル)
output: pargs.opt_free_from_str()?,
};
// 未使用の引数をチェック
let remaining = pargs.finish();
if !remaining.is_empty() {
eprintln!("警告: 未認識の引数: {:?}", remaining);
}
Ok(config)
}
fn print_help() {
const HELP: &str = "\
使用法: myapp [オプション] <入力ファイル> [出力ファイル]
オプション:
--count COUNT 処理回数(必須)
--name NAME 処理名(オプション)
--timeout SECONDS タイムアウト秒数(デフォルト: 30)
-v, --verbose 詳細出力を有効にする
-h, --help このヘルプを表示
引数:
<入力ファイル> 処理する入力ファイル
[出力ファイル] 出力先ファイル(オプション)
例:
myapp --count 10 --verbose input.txt output.txt
myapp --count 5 --name \"テスト\" input.txt
";
print!("{}", HELP);
}
// より高度な使用例:カスタムパーサーと複雑な型
fn advanced_example() -> Result<(), pico_args::Error> {
let mut pargs = pico_args::Arguments::from_env();
// カスタムパーサーでサイズを解析(例: "10MB", "1GB")
let size: u64 = pargs.value_from_fn("--size", |s| {
parse_size(s).ok_or("無効なサイズ形式")
})?;
// 複数の値を取得(カンマ区切り)
let tags: Vec<String> = pargs.opt_value_from_fn("--tags", |s| {
Ok(s.split(',').map(|s| s.trim().to_string()).collect())
})?.unwrap_or_default();
println!("サイズ: {} バイト", size);
println!("タグ: {:?}", tags);
Ok(())
}
fn parse_size(s: &str) -> Option<u64> {
let s = s.to_lowercase();
if let Some(s) = s.strip_suffix("gb") {
s.parse::<u64>().ok().map(|n| n * 1_000_000_000)
} else if let Some(s) = s.strip_suffix("mb") {
s.parse::<u64>().ok().map(|n| n * 1_000_000)
} else if let Some(s) = s.strip_suffix("kb") {
s.parse::<u64>().ok().map(|n| n * 1_000)
} else {
s.parse().ok()
}
}