extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
#[cfg(feature = "command")]
mod command;
#[cfg(feature = "time")]
mod time;
#[cfg(feature = "version")]
mod version;
#[cfg(feature = "time")]
#[proc_macro]
pub fn date(input: TokenStream) -> TokenStream {
use quote::format_ident;
use syn::parse_macro_input;
use time::TimeInput;
let input = parse_macro_input!(input as TimeInput);
let now = match input.now() {
Ok(now) => now,
Err(err) => return err.into_compile_error().into(),
};
let date = now.date();
let year = date.year();
let month = format_ident!("{}", format!("{:?}", date.month()));
let day = date.day();
let time_prefix = quote! { ::compile_time::__re_exports::time };
quote! {
const {
match #time_prefix::Date::from_calendar_date(#year, #time_prefix::Month::#month, #day) {
Ok(date) => date,
_ => ::core::unreachable!(),
}
}
}
.into()
}
#[cfg(feature = "time")]
#[proc_macro]
pub fn date_str(input: TokenStream) -> TokenStream {
use syn::parse_macro_input;
use time03::format_description;
use time::TimeInput;
let input = parse_macro_input!(input as TimeInput);
let now = match input.now() {
Ok(now) => now,
Err(err) => return err.into_compile_error().into(),
};
let date = now.date();
let fmt = format_description::parse_borrowed::<3>("[year]-[month]-[day]").unwrap();
let date_str = date.format(&fmt).unwrap();
quote! { #date_str }.into()
}
#[cfg(feature = "time")]
#[proc_macro]
pub fn time(input: TokenStream) -> TokenStream {
use syn::parse_macro_input;
use time::TimeInput;
let input = parse_macro_input!(input as TimeInput);
let now = match input.now() {
Ok(now) => now,
Err(err) => return err.into_compile_error().into(),
};
let time = now.time();
let hour = time.hour();
let minute = time.minute();
let second = time.second();
let time_prefix = quote! { ::compile_time::__re_exports::time };
quote! {
const {
match #time_prefix::Time::from_hms(#hour, #minute, #second) {
Ok(time) => time,
_ => ::core::unreachable!(),
}
}
}
.into()
}
#[cfg(feature = "time")]
#[proc_macro]
pub fn time_str(input: TokenStream) -> TokenStream {
use syn::parse_macro_input;
use time03::format_description;
use time::TimeInput;
let input = parse_macro_input!(input as TimeInput);
let now = match input.now() {
Ok(now) => now,
Err(err) => return err.into_compile_error().into(),
};
let time = now.time();
let fmt = format_description::parse_borrowed::<3>("[hour]:[minute]:[second]").unwrap();
let time_str = time.format(&fmt).unwrap();
quote! { #time_str }.into()
}
#[cfg(feature = "time")]
#[proc_macro]
pub fn datetime(input: TokenStream) -> TokenStream {
use quote::format_ident;
use syn::parse_macro_input;
use time::TimeInput;
let input = parse_macro_input!(input as TimeInput);
let now = match input.now() {
Ok(now) => now,
Err(err) => return err.into_compile_error().into(),
};
let datetime = now;
let year = datetime.year();
let month = format_ident!("{}", format!("{:?}", datetime.month()));
let day = datetime.day();
let hour = datetime.hour();
let minute = datetime.minute();
let second = datetime.second();
let time_prefix = quote! { ::compile_time::__re_exports::time };
let date = quote! {
match #time_prefix::Date::from_calendar_date(#year, #time_prefix::Month::#month, #day) {
Ok(date) => date,
_ => ::core::unreachable!(),
}
};
let time = quote! {
match #time_prefix::Time::from_hms(#hour, #minute, #second) {
Ok(time) => time,
_ => ::core::unreachable!(),
}
};
quote! {
const { #time_prefix::PrimitiveDateTime::new(#date, #time).assume_utc() }
}
.into()
}
#[cfg(feature = "time")]
#[proc_macro]
pub fn datetime_str(input: TokenStream) -> TokenStream {
use syn::parse_macro_input;
use time03::format_description;
use time::TimeInput;
let input = parse_macro_input!(input as TimeInput);
let now = match input.now() {
Ok(now) => now,
Err(err) => return err.into_compile_error().into(),
};
let datetime = now;
let fmt = format_description::parse_borrowed::<3>("[year]-[month]-[day]T[hour]:[minute]:[second]Z").unwrap();
let datetime_str = datetime.format(&fmt).unwrap();
quote! { #datetime_str }.into()
}
#[cfg(feature = "time")]
#[proc_macro]
pub fn unix(_input: TokenStream) -> TokenStream {
let datetime = time::utc();
let unix_timestamp = proc_macro2::Literal::i64_unsuffixed(datetime.unix_timestamp());
quote! {
#unix_timestamp
}
.into()
}
#[cfg(feature = "version")]
#[proc_macro]
pub fn rustc_version(_item: TokenStream) -> TokenStream {
match version::rustc() {
Ok(rustc_version::Version { major, minor, patch, pre, build }) => {
let semver_prefix = quote! { ::compile_time::__re_exports::semver };
let pre = if pre.is_empty() {
quote! { #semver_prefix::Prerelease::EMPTY }
} else {
let pre = pre.as_str();
quote! {
if let Ok(pre) = #semver_prefix::Prerelease::new(#pre) {
pre
} else {
::core::unreachable!()
}
}
};
let build = if build.is_empty() {
quote! { #semver_prefix::BuildMetadata::EMPTY }
} else {
let build = build.as_str();
quote! {
if let Ok(build) = #semver_prefix::BuildMetadata::new(#build) {
build
} else {
::core::unreachable!()
}
}
};
quote! {
#semver_prefix::Version {
major: #major,
minor: #minor,
patch: #patch,
pre: #pre,
build: #build,
}
}
},
Err(err) => err.into_compile_error(),
}
.into()
}
#[cfg(feature = "version")]
#[proc_macro]
pub fn rustc_version_str(_item: TokenStream) -> TokenStream {
match version::rustc() {
Ok(rustc_version) => {
let rustc_version_string = rustc_version.to_string();
quote! { #rustc_version_string }
},
Err(err) => err.into_compile_error(),
}
.into()
}
#[cfg(feature = "version")]
#[proc_macro]
pub fn rustc_version_major(_item: TokenStream) -> TokenStream {
use quote::ToTokens;
match version::rustc() {
Ok(rustc_version) => {
let major = rustc_version.major;
proc_macro2::Literal::u64_unsuffixed(major).to_token_stream()
},
Err(err) => err.into_compile_error(),
}
.into()
}
#[cfg(feature = "version")]
#[proc_macro]
pub fn rustc_version_minor(_item: TokenStream) -> TokenStream {
use quote::ToTokens;
match version::rustc() {
Ok(rustc_version) => {
let minor = rustc_version.minor;
proc_macro2::Literal::u64_unsuffixed(minor).to_token_stream()
},
Err(err) => err.into_compile_error(),
}
.into()
}
#[cfg(feature = "version")]
#[proc_macro]
pub fn rustc_version_patch(_item: TokenStream) -> TokenStream {
use quote::ToTokens;
match version::rustc() {
Ok(rustc_version) => {
let patch = rustc_version.patch;
proc_macro2::Literal::u64_unsuffixed(patch).to_token_stream()
},
Err(err) => err.into_compile_error(),
}
.into()
}
#[cfg(feature = "version")]
#[proc_macro]
pub fn rustc_version_pre(_item: TokenStream) -> TokenStream {
match version::rustc() {
Ok(rustc_version) => {
let pre = rustc_version.pre.as_str();
quote! { #pre }
},
Err(err) => err.into_compile_error(),
}
.into()
}
#[cfg(feature = "version")]
#[proc_macro]
pub fn rustc_version_build(_input: TokenStream) -> TokenStream {
match version::rustc() {
Ok(rustc_version) => {
let build = rustc_version.build.as_str();
quote! { #build }
},
Err(err) => err.into_compile_error(),
}
.into()
}
#[proc_macro]
#[cfg(feature = "command")]
pub fn command_bytes(input: TokenStream) -> TokenStream {
use proc_macro2::Span;
use syn::{parse_macro_input, LitByteStr};
use command::CommandInput;
let input = parse_macro_input!(input as CommandInput);
match command::output(input) {
Ok(output) => {
let output = LitByteStr::new(&output, Span::call_site());
quote! { #output }
},
Err(err) => err.into_compile_error(),
}
.into()
}
#[proc_macro]
#[cfg(feature = "command")]
pub fn command_str(input: TokenStream) -> TokenStream {
use proc_macro2::Span;
use syn::{parse_macro_input, LitStr};
use command::CommandInput;
let input = parse_macro_input!(input as CommandInput);
match command::output(input) {
Ok(output) => match String::from_utf8(output) {
Ok(output_string) => {
let output = LitStr::new(&output_string, Span::call_site());
quote! { #output }
},
Err(_) => quote! {
::core::compile_error!("Command output is not valid UTF-8.")
},
},
Err(err) => err.into_compile_error(),
}
.into()
}