static_iref/
lib.rs

1//! This is a companion crate for [`iref`][iref] providing macros to build
2//! `'static` URI/IRIs and URI/IRI references at compile time.
3//!
4//! [iref]: <https://github.com/timothee-haudebourg/iref>
5//!
6//! ## Basic usage
7//!
8//! Use the `uri!` (resp. `iri!`) macro to build URI (resp. IRI) statically, and
9//! the `uri_ref!` (resp `iri_ref!`) macro to build URI (resp. IRI) references
10//! statically.
11//!
12//! ```rust
13//! use iref::{Iri, IriRef};
14//! use static_iref::{iri, iri_ref};
15//!
16//! const IRI: &'static Iri = iri!("https://www.rust-lang.org/foo/bar#frag");
17//! const IRI_REF: &'static IriRef = iri_ref!("/foo/bar#frag");
18//! ```
19use iref::{IriBuf, IriRefBuf, UriBuf, UriRefBuf};
20use proc_macro::TokenStream;
21use quote::quote;
22
23/// Build an URI with a `'static` lifetime at compile time.
24///
25/// This macro expects a single string literal token representing the URI.
26#[proc_macro]
27pub fn uri(tokens: TokenStream) -> TokenStream {
28	match syn::parse::<syn::LitStr>(tokens) {
29		Ok(lit) => match UriBuf::new(lit.value().into_bytes()) {
30			Ok(uri) => {
31				let value = uri.as_bytes();
32				quote! {
33					unsafe {
34						::iref::Uri::new_unchecked(&[#(#value),*])
35					}
36				}
37				.into()
38			}
39			Err(_) => produce_error("invalid URI"),
40		},
41		Err(e) => e.to_compile_error().into(),
42	}
43}
44
45/// Build an URI reference with a `'static` lifetime at compile time.
46///
47/// This macro expects a single string literal token representing the URI reference.
48#[proc_macro]
49pub fn uri_ref(tokens: TokenStream) -> TokenStream {
50	match syn::parse::<syn::LitStr>(tokens) {
51		Ok(lit) => match UriRefBuf::new(lit.value().into_bytes()) {
52			Ok(uri_ref) => {
53				let value = uri_ref.as_bytes();
54				quote! {
55					unsafe {
56						::iref::UriRef::new_unchecked(&[#(#value),*])
57					}
58				}
59				.into()
60			}
61			Err(_) => produce_error("invalid URI reference"),
62		},
63		Err(e) => e.to_compile_error().into(),
64	}
65}
66
67/// Build an IRI with a `'static` lifetime at compile time.
68///
69/// This macro expects a single string literal token representing the IRI.
70#[proc_macro]
71pub fn iri(tokens: TokenStream) -> TokenStream {
72	match syn::parse::<syn::LitStr>(tokens) {
73		Ok(lit) => match IriBuf::new(lit.value()) {
74			Ok(iri) => {
75				let value = iri.as_str();
76				quote! {
77					unsafe {
78						::iref::Iri::new_unchecked(#value)
79					}
80				}
81				.into()
82			}
83			Err(_) => produce_error("invalid IRI"),
84		},
85		Err(e) => e.to_compile_error().into(),
86	}
87}
88
89/// Build an IRI reference with a `'static` lifetime at compile time.
90///
91/// This macro expects a single string literal token representing the IRI reference.
92#[proc_macro]
93pub fn iri_ref(tokens: TokenStream) -> TokenStream {
94	match syn::parse::<syn::LitStr>(tokens) {
95		Ok(lit) => match IriRefBuf::new(lit.value()) {
96			Ok(iri_ref) => {
97				let value = iri_ref.as_str();
98				quote! {
99					unsafe {
100						::iref::IriRef::new_unchecked(#value)
101					}
102				}
103				.into()
104			}
105			Err(_) => produce_error("invalid IRI reference"),
106		},
107		Err(e) => e.to_compile_error().into(),
108	}
109}
110
111fn produce_error(msg: &str) -> TokenStream {
112	format!("compile_error!(\"{}\")", msg).parse().unwrap()
113}