🔗
Rust でコードを書いているタイミングで URLのパースのエラーを検知する
Rust でコードを書いているタイミングで URLのパースのエラーを検知するマクロ(safe_url!
)を作成してみました. ( https://crates.io/ には公開していないので, コピペしてカスタマイズして使ってください. )
普通の書き方
#[test]
fn test() {
let example_com = url::Url::parse("https//example.com").unwrap();
println!("example_com is {:?}", &example_com);
}
この書き方だと実行時にエラーが発生してしまう. 実行してからすぐに通る処理なら, ミスにすぐ気付けるが, めったに通らない処理だと指定ミスに気づけない.
safe_url!
を使うと
今回作成した 不正なURL (https//example.com
) を指定しているとき
正常なURL (https://example.com
) を指定しているとき
このように実行前にミスを検知できる.
Cargo.toml
[package]
name = "safe-url-macro"
version = "0.1.0"
edition = "2021"
[lib]
proc-macro = true
[dependencies]
url = "2.2.2"
quote = "1.0.18"
syn = "1.0.95"
lib/src
#[proc_macro]
pub fn safe_url(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
match syn::parse::<syn::LitStr>(input) {
Ok(literal) => {
let string_literal_value = literal.value();
match url::Url::parse(&string_literal_value) {
Ok(_safe_url) => quote::quote! {
url::Url::parse(#string_literal_value).unwrap()
}
.into(),
Err(error) => {
let message =
string_literal_value + " is not valid url. (" + &error.to_string() + ")";
quote::quote! {compile_error!(#message)}.into()
}
}
}
Err(_) => quote::quote! {compile_error!("safe_url macro support string literal")}.into(),
}
}
tests/test.rs
#[test]
fn test() {
let example_com = safe_url_macro::safe_url!("https//example.com");
println!("example_com is {:?}", &example_com);
}
URLの指定はテキストエディタによっては表示が変わったりするのでミスには気づきやすいけれど, ミスをするときがあるので, コンパイル時にバリデーションすることは大切.
const EXAMPLE_COM: url::Url = safe_url_macro::safe_url!("https://example.com");
このように const で定数としてかければ更に良かったけど, url::Url::parse
が const fn
ではなかったため できなかった. URL パースの処理を const fn
で自作すればできそう
こういうコンパイル時に色々検査できる機能が増えると良いなぁ
正規表現(Regex)にはこの proc-macro-regex
が使えそう?
Discussion