// force-host // no-prefer-dynamic #![crate_type = "proc-macro"] extern crate proc_macro; use proc_macro::{TokenStream, TokenTree as Tt}; use std::str::FromStr; // String containing the current version number of the tip, i.e. "1.41.2" static VERSION_NUMBER: &str = include_str!("../../../../../src/version"); #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] struct Version { major: i16, minor: i16, patch: i16, } fn parse_version(s: &str) -> Option { let mut digits = s.splitn(3, '.'); let major = digits.next()?.parse().ok()?; let minor = digits.next()?.parse().ok()?; let patch = digits.next().unwrap_or("0").trim().parse().ok()?; Some(Version { major, minor, patch }) } #[proc_macro_attribute] /// Emits a #[cfg(version)] relative to the current one, so passing /// -1 as argument on compiler 1.50 will emit #[cfg(version("1.49.0"))], /// while 1 will emit #[cfg(version("1.51.0"))] pub fn ver_cfg_rel(attr: TokenStream, input: TokenStream) -> TokenStream { let mut v_rel = None; for a in attr.into_iter() { match a { Tt::Literal(l) => { let mut s = l.to_string(); let s = s.trim_matches('"'); let v: i16 = s.parse().unwrap(); v_rel = Some(v); break; }, _ => panic!("{:?}", a), } } let v_rel = v_rel.unwrap(); let mut v = parse_version(VERSION_NUMBER).unwrap(); v.minor += v_rel; let attr_str = format!("#[cfg(version(\"{}.{}.{}\"))]", v.major, v.minor, v.patch); let mut res = Vec::::new(); res.extend(TokenStream::from_str(&attr_str).unwrap().into_iter()); res.extend(input.into_iter()); res.into_iter().collect() }