Revision control

Copy as Markdown

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Compile-time URL validation macro for application-services.
//!
//! Provides a [`url!`] proc macro that validates a string literal as a
//! parseable URL at compile time. Invalid input produces a compile
//! error pointing at the offending literal; valid input expands to a
//! runtime `url::Url::parse` call that is guaranteed to succeed.
//!
//! ## Consumer requirements
//!
//! The expanded code references `::url::Url::parse`, so the calling
//! crate must declare `url` as a dependency.
//!
//! ## Limitations
//!
//! `url::Url::parse` is not `const fn`, so the macro cannot be used
//! directly in `static`/`const` initializers. Wrap with
//! `once_cell::Lazy` or `std::sync::LazyLock` for static contexts.
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, LitStr};
/// Validates a URL string literal at compile time.
///
/// On success, expands to a `url::Url::parse(...)` call that cannot
/// fail at runtime. On failure, the macro emits a compile error
/// carrying `url::ParseError`'s message, anchored at the offending
/// literal.
///
/// # Examples
///
/// ```ignore
/// use url_macro::url;
/// use url::Url;
///
/// let endpoint: Url = url!("https://ads.mozilla.org/v1/");
/// // url!("not a url"); // -> compile error: relative URL without a base
/// ```
#[proc_macro]
pub fn url(input: TokenStream) -> TokenStream {
let lit = parse_macro_input!(input as LitStr);
let value = lit.value();
if let Err(err) = ::url::Url::parse(&value) {
return syn::Error::new(lit.span(), err.to_string())
.to_compile_error()
.into();
}
quote! {
::url::Url::parse(#lit).expect("URL validated at compile time")
}
.into()
}