### rustversion expand.rs: cfg() and try_attr() implementation Source: https://docs.rs/rustversion/latest/src/rustversion/expand.rs.html The full source of expand.rs from rustversion 1.0.23. It defines the public cfg() entry point, the internal try_cfg() and try_attr() helpers, and the allow_incompatible_msrv() wrapper that prepends #[allow(clippy::incompatible_msrv)] to the output. The code is truncated at the end of the displayed source. ```rust use crate::attr::{self, Then}; use crate::error::{Error, Result}; use crate::{constfn, expr, iter, token}; use proc_macro::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree}; use std::iter::FromIterator; pub fn cfg(introducer: &str, args: TokenStream, input: TokenStream) -> TokenStream { try_cfg(introducer, args, input).unwrap_or_else(Error::into_compile_error) } fn try_cfg(introducer: &str, args: TokenStream, input: TokenStream) -> Result { let introducer = Ident::new(introducer, Span::call_site()); let mut full_args = TokenStream::from(TokenTree::Ident(introducer)); if !args.is_empty() { full_args.extend(std::iter::once(TokenTree::Group(Group::new( Delimiter::Parenthesis, args, )))); } let ref mut full_args = iter::new(full_args); let expr = expr::parse(full_args)?; token::parse_end(full_args)?; if expr.eval(crate::RUSTVERSION) { Ok(allow_incompatible_msrv(input)) } else { Ok(TokenStream::new()) } } pub fn try_attr(args: attr::Args, input: TokenStream) -> Result { if !args.condition.eval(crate::RUSTVERSION) { return Ok(input); } let output = match args.then { Then::Const(const_token) => constfn::insert_const(input, const_token)?, Then::Attribute(then) => { TokenStream::from_iter( // #[cfg_attr(all(), #then)] ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(), [TokenTree::Punct(Punct::new('#', Spacing::Alone)), TokenTree::Group(Group::new(Delimiter::Bracket, TokenStream::from_iter(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(), [TokenTree::Ident(Ident::new("cfg_attr", Span::call_site())), TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::from_iter(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(), [TokenTree::Ident(Ident::new("all", Span::call_site())), TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())), TokenTree::Punct(Punct::new(',', Spacing::Alone))])).into_iter().chain(then))))])))))]))vec![ TokenTree::Punct(Punct::new('#', Spacing::Alone)), TokenTree::Group(Group::new( Delimiter::Bracket, TokenStream::from_iter(vec![ TokenTree::Ident(Ident::new("cfg_attr", Span::call_site())), TokenTree::Group(Group::new( Delimiter::Parenthesis, TokenStream::from_iter( vec![ TokenTree::Ident(Ident::new("all", Span::call_site())), TokenTree::Group(Group::new( Delimiter::Parenthesis, TokenStream::new(), )), TokenTree::Punct(Punct::new(',', Spacing::Alone)), ] .into_iter() .chain(then), ), )), ]), )), ] .into_iter() .chain(input), ) } }; Ok(allow_incompatible_msrv(output)) } fn allow_incompatible_msrv(input: TokenStream) -> TokenStream { TokenStream::from_iter( // #[allow(clippy::incompatible_msrv)] ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(), [TokenTree::Punct(Punct::new('#', Spacing::Alone)), ``` -------------------------------- ### rustversion Procedural Macros Source: https://docs.rs/rustversion/latest/src/rustversion/lib.rs.html This documentation covers the procedural macros provided by the rustversion crate, which allow conditional compilation based on the Rust compiler version. ```APIDOC ## [PROC_MACRO_ATTRIBUTE] stable ### Description Conditionally compiles the annotated item only when the Rust compiler is a stable release. ### Method proc_macro_attribute ### Parameters - **args** (TokenStream) - Required - Arguments passed to the attribute macro. - **input** (TokenStream) - Required - The item the attribute is applied to. ### Returns TokenStream - The transformed token stream. ## [PROC_MACRO_ATTRIBUTE] beta ### Description Conditionally compiles the annotated item only when the Rust compiler is a beta release. ### Method proc_macro_attribute ### Parameters - **args** (TokenStream) - Required - Arguments passed to the attribute macro. - **input** (TokenStream) - Required - The item the attribute is applied to. ### Returns TokenStream - The transformed token stream. ## [PROC_MACRO_ATTRIBUTE] nightly ### Description Conditionally compiles the annotated item only when the Rust compiler is a nightly release. ### Method proc_macro_attribute ### Parameters - **args** (TokenStream) - Required - Arguments passed to the attribute macro. - **input** (TokenStream) - Required - The item the attribute is applied to. ### Returns TokenStream - The transformed token stream. ## [PROC_MACRO_ATTRIBUTE] since ### Description Conditionally compiles the annotated item only when the Rust compiler version is at least the specified version. ### Method proc_macro_attribute ### Parameters - **args** (TokenStream) - Required - Arguments specifying the minimum version, e.g., `since(1.33)`. - **input** (TokenStream) - Required - The item the attribute is applied to. ### Returns TokenStream - The transformed token stream. ## [PROC_MACRO_ATTRIBUTE] before ### Description Conditionally compiles the annotated item only when the Rust compiler version is less than the specified version. ### Method proc_macro_attribute ### Parameters - **args** (TokenStream) - Required - Arguments specifying the maximum version, e.g., `before(1.33)`. - **input** (TokenStream) - Required - The item the attribute is applied to. ### Returns TokenStream - The transformed token stream. ## [PROC_MACRO_ATTRIBUTE] not ### Description Conditionally compiles the annotated item when the given condition is false. ### Method proc_macro_attribute ### Parameters - **args** (TokenStream) - Required - Arguments specifying the condition to negate. - **input** (TokenStream) - Required - The item the attribute is applied to. ### Returns TokenStream - The transformed token stream. ## [PROC_MACRO_ATTRIBUTE] any ### Description Conditionally compiles the annotated item when any of the given conditions are true. ### Method proc_macro_attribute ### Parameters - **args** (TokenStream) - Required - Arguments specifying multiple conditions, e.g., `any(since(1.33), before(1.30))`. - **input** (TokenStream) - Required - The item the attribute is applied to. ### Returns TokenStream - The transformed token stream. ## [PROC_MACRO_ATTRIBUTE] all ### Description Conditionally compiles the annotated item when all of the given conditions are true. ### Method proc_macro_attribute ### Parameters - **args** (TokenStream) - Required - Arguments specifying multiple conditions, e.g., `all(since(1.33), before(1.40))`. - **input** (TokenStream) - Required - The item the attribute is applied to. ### Returns TokenStream - The transformed token stream. ## [PROC_MACRO_ATTRIBUTE] attr ### Description Conditionally applies an attribute to the annotated item based on the Rust version. ### Method proc_macro_attribute ### Parameters - **args** (TokenStream) - Required - Arguments specifying the version condition and the attribute to apply, e.g., `attr(since(1.33), repr(packed(2)))`. - **input** (TokenStream) - Required - The item the attribute is applied to. ### Returns TokenStream - The transformed token stream. ## [PROC_MACRO] cfg ### Description Evaluates a Rust version condition and expands to the boolean literal `true` or `false`. ### Method proc_macro ### Parameters - **input** (TokenStream) - Required - The condition expression to evaluate, e.g., `rustversion::cfg!(since(1.36))`. ### Returns TokenStream - A token stream containing the boolean literal `true` or `false`. ``` -------------------------------- ### any attribute macro syntax Source: https://docs.rs/rustversion/latest/rustversion/attr.any.html The syntax for using the any attribute macro. ```rust #[any] ``` -------------------------------- ### rustversion::beta Source: https://docs.rs/rustversion/latest/rustversion Attribute macro that is true on any beta compiler. ```APIDOC ## #[rustversion::beta] ### Description True on any beta compiler. ### Usage rust #[rustversion::beta] ``` -------------------------------- ### rustversion::all Source: https://docs.rs/rustversion/latest/rustversion Attribute macro that is true if all of the comma-separated selectors are true. ```APIDOC ## #[rustversion::all] ### Description True if all of the comma-separated selectors are true; for example #[rustversion::all(since(1.31), before(1.34))]. ### Usage rust #[rustversion::all(since(1.31), before(1.34))] ### Parameters - **selectors** (comma-separated selectors) - One or more rustversion selectors, e.g., `since(...)`, `before(...)`, `stable`, `beta`, etc. ``` -------------------------------- ### rustversion::cfg! Source: https://docs.rs/rustversion/latest/rustversion Macro that provides an expression form of any of the above attributes. ```APIDOC ## rustversion::cfg! ### Description An expression form of any of the above attributes; for example `if rustversion::cfg!(any(stable, beta)) { ... }`. ### Usage rust if rustversion::cfg!(any(stable, beta)) { // ... } ### Parameters - **selector** (selector) - A rustversion selector, e.g., `any(stable, beta)`, `since(1.36)`, `nightly`, etc. ### Returns - **bool** - `true` if the selector is true for the current compiler, `false` otherwise. ``` -------------------------------- ### rustversion::any Source: https://docs.rs/rustversion/latest/rustversion Attribute macro that is true if any of the comma-separated selectors is true. ```APIDOC ## #[rustversion::any] ### Description True if any of the comma-separated selectors is true; for example #[rustversion::any(stable, beta)]. ### Usage rust #[rustversion::any(stable, beta)] ### Parameters - **selectors** (comma-separated selectors) - One or more rustversion selectors, e.g., `stable`, `beta`, `nightly`, `since(...)`, etc. ``` -------------------------------- ### rustversion::before Source: https://docs.rs/rustversion/latest/rustversion Attribute macro that is the negative of #[rustversion::since(...)]. ```APIDOC ## #[rustversion::before] ### Description Negative of #[rustversion::since(...)]. True on compilers before the specified version or date. ### Usage rust #[rustversion::before(1.34)] // or #[rustversion::before(2025-01-01)] ### Parameters - **version_or_date** (string) - A stable version (e.g., "1.34") or a nightly date (e.g., "2025-01-01"). ### Behavior - True on compilers earlier than the specified version or date. ``` -------------------------------- ### Constructing TokenTree for clippy attribute Source: https://docs.rs/rustversion/latest/src/rustversion/expand.rs.html This snippet demonstrates the manual construction of a TokenTree group representing an allow attribute for clippy::incompatible_msrv. ```rust TokenTree::Group(Group::new(Delimiter::Bracket, TokenStream::from_iter(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(), [TokenTree::Ident(Ident::new("allow", Span::call_site())), TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::from_iter(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(), [TokenTree::Ident(Ident::new("clippy", Span::call_site())), TokenTree::Punct(Punct::new(':', Spacing::Joint)), TokenTree::Punct(Punct::new(':', Spacing::Alone)), TokenTree::Ident(Ident::new("incompatible_msrv", Span::call_site()))])))))])))))])) ``` -------------------------------- ### rustversion::since Source: https://docs.rs/rustversion/latest/rustversion Attribute macro that is true on the specified stable release or nightly and any later compiler. ```APIDOC ## #[rustversion::since] ### Description True on that stable release and any later compiler, including beta and nightly. When a date is specified, true on that nightly and all newer ones. ### Usage rust #[rustversion::since(1.34)] // or #[rustversion::since(2025-01-01)] ### Parameters - **version_or_date** (string) - A stable version (e.g., "1.34") or a nightly date (e.g., "2025-01-01"). ### Behavior - With a stable version: true on that release and any later compiler. - With a nightly date: true on that nightly and all newer ones. ``` -------------------------------- ### TokenStream expansion with clippy attribute Source: https://docs.rs/rustversion/latest/src/rustversion/expand.rs.html This snippet shows the integration of the clippy attribute into a TokenStream by chaining it with existing input tokens. ```rust vec![ 80 TokenTree::Punct(Punct::new('#', Spacing::Alone)), 81 TokenTree::Group(Group::new( 82 Delimiter::Bracket, 83 TokenStream::from_iter(vec![ 84 TokenTree::Ident(Ident::new("allow", Span::call_site())), 85 TokenTree::Group(Group::new( 86 Delimiter::Parenthesis, 87 TokenStream::from_iter(vec![ 88 TokenTree::Ident(Ident::new("clippy", Span::call_site())), 89 TokenTree::Punct(Punct::new(':', Spacing::Joint)), 90 TokenTree::Punct(Punct::new(':', Spacing::Alone)), 91 TokenTree::Ident(Ident::new("incompatible_msrv", Span::call_site())), 92 ]), 93 )), 94 ]), 95 )), 96 ] 97 .into_iter() 98 .chain(input), 99 ) 100} ``` -------------------------------- ### Version and Channel definitions Source: https://docs.rs/rustversion/latest/src/rustversion/version.rs.html Defines the Version struct and Channel enum with derived traits for Copy, Clone, Debug, and PartialEq. ```rust 1#![allow(dead_code)] 2 3use crate::date::Date; 4 5#[derive(#[automatically_derived] impl ::core::marker::Copy for Version { }Copy, #[automatically_derived] impl ::core::clone::Clone for Version { #[inline] fn clone(&self) -> Version { let _: ::core::clone::AssertParamIsClone; let _: ::core::clone::AssertParamIsClone; *self } }Clone, #[automatically_derived] impl ::core::fmt::Debug for Version { #[inline] fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { ::core::fmt::Formatter::debug_struct_field3_finish(f, "Version", "minor", &self.minor, "patch", &self.patch, "channel", &&self.channel) } }Debug, #[automatically_derived] impl ::core::cmp::PartialEq for Version { #[inline] fn eq(&self, other: &Version) -> bool { self.minor == other.minor && self.patch == other.patch && self.channel == other.channel } }PartialEq)] 6pub struct Version { 7 pub minor: u16, 8 pub patch: u16, 9 pub channel: Channel, 10} 11 12#[derive(#[automatically_derived] impl ::core::marker::Copy for Channel { }Copy, #[automatically_derived] impl ::core::clone::Clone for Channel { #[inline] fn clone(&self) -> Channel { let _: ::core::clone::AssertParamIsClone; *self } }Clone, #[automatically_derived] impl ::core::fmt::Debug for Channel { #[inline] fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { match self { Channel::Stable => ::core::fmt::Formatter::write_str(f, "Stable"), Channel::Beta => ::core::fmt::Formatter::write_str(f, "Beta"), Channel::Nightly(__self_0) => ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Nightly", &__self_0), Channel::Dev => ::core::fmt::Formatter::write_str(f, "Dev"), } } }Debug, #[automatically_derived] impl ::core::cmp::PartialEq for Channel { #[inline] fn eq(&self, other: &Channel) -> bool { let __self_discr = ::core::intrinsics::discriminant_value(self); let __arg1_discr = ::core::intrinsics::discriminant_value(other); __self_discr == __arg1_discr && match (self, other) { (Channel::Nightly(__self_0), Channel::Nightly(__arg1_0)) => __self_0 == __arg1_0, _ => true, } } }PartialEq)] 13pub enum Channel { 14 Stable, 15 Beta, 16 Nightly(Date), 17 Dev, 18} ``` -------------------------------- ### Token Parsing Utilities in token.rs Source: https://docs.rs/rustversion/latest/src/rustversion/token.rs.html A collection of functions for parsing specific token types from an iterator, including punctuation, keywords, literals, and groups. ```rust 1use crate::error::{Error, Result}; 2use crate::iter::Iter; 3use proc_macro::{Delimiter, Group, Ident, Literal, Span, TokenTree}; 4 5pub fn parse_punct(iter: Iter, ch: char) -> Result<()> { 6 match iter.next() { 7 Some(TokenTree::Punct(ref punct)) if punct.as_char() == ch => Ok(()), 8 unexpected => { 9 let span = unexpected 10 .as_ref() 11 .map_or_else(Span::call_site, TokenTree::span); 12 Err(Error::new(span, ::alloc::__export::must_use({ ::alloc::fmt::format(format_args!("expected `{0}`", ch)) })format!("expected `{}`", ch))) 13 } 14 } 15} 16 17pub fn parse_optional_punct(iter: Iter, ch: char) -> Option<()> { 18 match iter.peek() { 19 Some(TokenTree::Punct(punct)) if punct.as_char() == ch => iter.next().map(drop), 20 _ => None, 21 } 22} 23 24pub fn parse_optional_keyword(iter: Iter, keyword: &str) -> Option { 25 match iter.peek() { 26 Some(TokenTree::Ident(ident)) if ident.to_string() == keyword => { 27 Some(iter.next().unwrap().span()) 28 } 29 _ => None, 30 } 31} 32 33pub fn parse_literal(iter: Iter) -> Result { 34 match iter.next() { 35 Some(TokenTree::Literal(literal)) => Ok(literal), 36 unexpected => { 37 let span = unexpected 38 .as_ref() 39 .map_or_else(Span::call_site, TokenTree::span); 40 Err(Error::new(span, "expected literal")) 41 } 42 } 43} 44 45pub fn parse_paren(introducer: &Ident, iter: Iter) -> Result { 46 match iter.peek() { 47 Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Parenthesis => { 48 match iter.next() { 49 Some(TokenTree::Group(group)) => Ok(group), 50 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(), 51 } 52 } 53 Some(unexpected) => Err(Error::new(unexpected.span(), "expected `(`")), 54 None => Err(Error::new( 55 introducer.span(), 56 ::alloc::__export::must_use({ ::alloc::fmt::format(format_args!("expected `(` after `{0}`", introducer)) })format!("expected `(` after `{}`", introducer), 57 )), 58 } 59} 60 61pub fn parse_optional_paren(iter: Iter) -> Option { 62 match iter.peek() { 63 Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Parenthesis => { 64 match iter.next() { 65 Some(TokenTree::Group(group)) => Some(group), 66 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(), 67 } 68 } 69 _ => None, 70 } 71} 72 73pub fn parse_end(iter: Iter) -> Result<()> { 74 match iter.next() { 75 None => Ok(()), 76 Some(unexpected) => Err(Error::new(unexpected.span(), "unexpected token")), 77 } 78} ``` -------------------------------- ### rustversion::not Source: https://docs.rs/rustversion/latest/rustversion Attribute macro that is the negative of any selector. ```APIDOC ## #[rustversion::not] ### Description Negative of any selector; for example #[rustversion::not(nightly)]. ### Usage rust #[rustversion::not(nightly)] ### Parameters - **selector** (selector) - Any rustversion selector, e.g., `nightly`, `stable`, `beta`, `since(...)`, etc. ``` -------------------------------- ### rustversion::stable Source: https://docs.rs/rustversion/latest/rustversion Attribute macro that is true on any stable compiler, or exactly the specified stable compiler version. ```APIDOC ## #[rustversion::stable] ### Description True on any stable compiler. When a version is specified, true on exactly that stable compiler version. ### Usage rust #[rustversion::stable] // or #[rustversion::stable(1.34)] ### Parameters - **version** (optional, string) - The exact stable compiler version to match, e.g., "1.34". ### Behavior - Without arguments: true on any stable compiler. - With a version: true only on that exact stable compiler version. ``` -------------------------------- ### Parse 'any' expression completion Source: https://docs.rs/rustversion/latest/src/rustversion/expr.rs.html Completes the parsing of an 'any' expression by collecting previously parsed comma-separated expressions. ```rust let exprs = parse_comma_separated(inner)?; Ok(Expr::Any(exprs.into_iter().collect())) } ``` -------------------------------- ### Calculate current date with time.rs Source: https://docs.rs/rustversion/latest/src/rustversion/time.rs.html The today function returns the current date, falling back to a default date if the system time cannot be determined or if the environment is configured for UI testing. ```rust 1use crate::date::Date; 2use std::env; 3use std::time::{SystemTime, UNIX_EPOCH}; 4 5// Timestamp of 2016-03-01 00:00:00 in UTC. 6const BASE: u64 = 1456790400; 7const BASE_YEAR: u16 = 2016; 8const BASE_MONTH: u8 = 3; 9 10// Days between leap days. 11const CYCLE: u64 = 365 * 4 + 1; 12 13const DAYS_BY_MONTH: [u8; 12] = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; 14 15pub fn today() -> Date { 16 let default = Date { 17 year: 2025, 18 month: 2, 19 day: 25, 20 }; 21 try_today().unwrap_or(default) 22} 23 24fn try_today() -> Option { 25 if let Some(pkg_name) = env::var_os("CARGO_PKG_NAME") { 26 if pkg_name.to_str() == Some("rustversion-tests") { 27 return None; // Stable date for ui testing. 28 } 29 } 30 31 let now = SystemTime::now(); 32 let since_epoch = now.duration_since(UNIX_EPOCH).ok()?; 33 let secs = since_epoch.as_secs(); 34 35 let approx_days = secs.checked_sub(BASE)? / 60 / 60 / 24; 36 let cycle = approx_days / CYCLE; 37 let mut rem = approx_days % CYCLE; 38 39 let mut year = BASE_YEAR + cycle as u16 * 4; 40 let mut month = BASE_MONTH; 41 loop { 42 let days_in_month = DAYS_BY_MONTH[month as usize - 1]; 43 if rem < days_in_month as u64 { 44 let day = rem as u8 + 1; 45 return Some(Date { year, month, day }); 46 } 47 rem -= days_in_month as u64; 48 year += (month == 12) as u16; 49 month = month % 12 + 1; 50 } 51} ``` -------------------------------- ### rustversion::attr Source: https://docs.rs/rustversion/latest/rustversion Attribute macro for conditional inclusion of attributes; analogous to cfg_attr. ```APIDOC ## #[rustversion::attr] ### Description For conditional inclusion of attributes; analogous to `cfg_attr`. The selector determines whether the attribute is applied. ### Usage rust #[rustversion::attr(before(1.33), repr(packed))] #[rustversion::attr(since(1.33), repr(packed(2)))] struct Six(i16, i32); ### Parameters - **selector** (selector) - A rustversion selector, e.g., `since(1.33)`, `before(1.33)`, `stable`, `nightly`, etc. - **attribute** (attribute) - The attribute to conditionally include, e.g., `repr(packed)`, `const`, etc. ``` -------------------------------- ### rustversion::nightly Source: https://docs.rs/rustversion/latest/rustversion Attribute macro that is true on any nightly compiler or dev build, or exactly one nightly when a date is specified. ```APIDOC ## #[rustversion::nightly] ### Description True on any nightly compiler or dev build. When a date is specified, true on exactly that nightly. ### Usage rust #[rustversion::nightly] // or #[rustversion::nightly(2025-01-01)] ### Parameters - **date** (optional, string) - The exact nightly date to match, e.g., "2025-01-01". ### Behavior - Without arguments: true on any nightly compiler or dev build. - With a date: true only on that exact nightly. ``` -------------------------------- ### Use custom cfg flag in library code Source: https://docs.rs/rustversion Use the custom cfg flag emitted by the build script to conditionally enable no_std support. ```rust // src/lib.rs #![cfg_attr(no_std, no_std)] #[cfg(no_std)] extern crate alloc; ``` -------------------------------- ### Emit Cargo cfg directives in build script Source: https://docs.rs/rustversion Use rustversion::cfg! in a build.rs file to emit custom cfg flags based on the compiler version. ```rust // build.rs fn main() { if rustversion::cfg!(since(1.36)) { println!("cargo:rustc-cfg=no_std"); } } ``` -------------------------------- ### Parse rustc release number into Release struct Source: https://docs.rs/rustversion/latest/src/rustversion/release.rs.html Defines the Release struct with minor and patch fields, and provides parse and try_parse functions to parse a rustc release number like "1.31" from a proc_macro Group. The parser requires the major version to be "1." and returns an error if not; patch is optional and parsed only if a dot follows the minor version. ```rust use crate::error::{Error, Result}; use crate::iter::Iter; use crate::token; use proc_macro::Group; #[derive(#[automatically_derived] impl ::core::marker::Copy for Release { }Copy, #[automatically_derived] impl ::core::clone::Clone for Release { #[inline] fn clone(&self) -> Release { let _: ::core::clone::AssertParamIsClone; let _: ::core::clone::AssertParamIsClone>; *self } }Clone, #[automatically_derived] impl ::core::fmt::Debug for Release { #[inline] fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { ::core::fmt::Formatter::debug_struct_field2_finish(f, "Release", "minor", &self.minor, "patch", &&self.patch) } }Debug, #[automatically_derived] impl ::core::cmp::PartialEq for Release { #[inline] fn eq(&self, other: &Release) -> bool { self.minor == other.minor && self.patch == other.patch } }PartialEq, #[automatically_derived] impl ::core::cmp::Eq for Release { #[inline] #[doc(hidden)] #[coverage(off)] fn assert_fields_are_eq(&self) { let _: ::core::cmp::AssertParamIsEq; let _: ::core::cmp::AssertParamIsEq>; } }Eq, #[automatically_derived] impl ::core::cmp::PartialOrd for Release { #[inline] fn partial_cmp(&self, other: &Release) -> ::core::option::Option<::core::cmp::Ordering> { ::core::option::Option::Some(::core::cmp::Ord::cmp(self, other)) } }PartialOrd, #[automatically_derived] impl ::core::cmp::Ord for Release { #[inline] fn cmp(&self, other: &Release) -> ::core::cmp::Ordering { match ::core::cmp::Ord::cmp(&self.minor, &other.minor) { ::core::cmp::Ordering::Equal => ::core::cmp::Ord::cmp(&self.patch, &other.patch), cmp => cmp, } } }Ord)] pub struct Release { pub minor: u16, pub patch: Option, } pub fn parse(paren: Group, iter: Iter) -> Result { try_parse(iter).map(|()| Error::group(paren, "expected rustc release number, like 1.31")) } fn try_parse(iter: Iter) -> Result { let major_minor = token::parse_literal(iter).map_err(drop)?; let string = major_minor.to_string(); if !string.starts_with("1.") { return Err(()); } let minor: u16 = string[2..].parse().map_err(drop)?; let patch = if token::parse_optional_punct(iter, '.').is_some() { let int = token::parse_literal(iter).map_err(drop)?; Some(int.to_string().parse().map_err(drop)?) } else { None }; Ok(Release { minor, patch }) } ``` -------------------------------- ### rustversion iter.rs: token stream iterator with peek Source: https://docs.rs/rustversion/latest/src/rustversion/iter.rs.html Defines the iterator used by rustversion to flatten token streams, skipping delimiter-less groups. The `peek` method caches the next token, and `next` recursively expands groups with `Delimiter::None`. ```rust use proc_macro::{token_stream, Delimiter, TokenStream, TokenTree}; pub type Iter<'a> = &'a mut IterImpl; pub struct IterImpl { stack: Vec, peeked: Option, } pub fn new(tokens: TokenStream) -> IterImpl { IterImpl { stack: ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(), [tokens.into_iter()]))vec![tokens.into_iter()], peeked: None, } } impl IterImpl { pub fn peek(&mut self) -> Option<&TokenTree> { self.peeked = self.next(); self.peeked.as_ref() } } impl Iterator for IterImpl { type Item = TokenTree; fn next(&mut self) -> Option { if let Some(tt) = self.peeked.take() { return Some(tt); } loop { let top = self.stack.last_mut()?; match top.next() { None => drop(self.stack.pop()), Some(TokenTree::Group(ref group)) if group.delimiter() == Delimiter::None => { self.stack.push(group.stream().into_iter()); } Some(tt) => return Some(tt), } } } } ``` -------------------------------- ### Parsing Functions Source: https://docs.rs/rustversion/latest/src/rustversion/expr.rs.html Functions for parsing token streams into Expr variants, including the main parse function and specific handlers for different expression types. ```rust pub fn parse(iter: Iter) -> Result { match &iter.next() { Some(TokenTree::Ident(i)) if i.to_string() == "stable" => parse_stable(iter), Some(TokenTree::Ident(i)) if i.to_string() == "beta" => Ok(Expr::Beta), Some(TokenTree::Ident(i)) if i.to_string() == "nightly" => parse_nightly(iter), Some(TokenTree::Ident(i)) if i.to_string() == "since" => parse_since(i, iter), Some(TokenTree::Ident(i)) if i.to_string() == "before" => parse_before(i, iter), Some(TokenTree::Ident(i)) if i.to_string() == "not" => parse_not(i, iter), Some(TokenTree::Ident(i)) if i.to_string() == "any" => parse_any(i, iter), Some(TokenTree::Ident(i)) if i.to_string() == "all" => parse_all(i, iter), unexpected => { let span = unexpected .as_ref() .map_or_else(Span::call_site, TokenTree::span); Err(Error::new(span, "expected one of `stable`, `beta`, `nightly`, `since`, `before`, `not`, `any`, `all`")) } } } fn parse_nightly(iter: Iter) -> Result { let paren = match token::parse_optional_paren(iter) { Some(group) => group, None => return Ok(Expr::Nightly), }; let ref mut inner = iter::new(paren.stream()); let date = date::parse(paren, inner)?; token::parse_optional_punct(inner, ','); token::parse_end(inner)?; Ok(Expr::Date(date)) } fn parse_stable(iter: Iter) -> Result { let paren = match token::parse_optional_paren(iter) { Some(group) => group, None => return Ok(Expr::Stable), }; let ref mut inner = iter::new(paren.stream()); let release = release::parse(paren, inner)?; token::parse_optional_punct(inner, ','); token::parse_end(inner)?; Ok(Expr::Release(release)) } fn parse_since(introducer: &Ident, iter: Iter) -> Result { let paren = token::parse_paren(introducer, iter)?; let ref mut inner = iter::new(paren.stream()); let bound = bound::parse(paren, inner)?; token::parse_optional_punct(inner, ','); token::parse_end(inner)?; Ok(Expr::Since(bound)) } fn parse_before(introducer: &Ident, iter: Iter) -> Result { let paren = token::parse_paren(introducer, iter)?; let ref mut inner = iter::new(paren.stream()); let bound = bound::parse(paren, inner)?; token::parse_optional_punct(inner, ','); token::parse_end(inner)?; Ok(Expr::Before(bound)) } fn parse_not(introducer: &Ident, iter: Iter) -> Result { let paren = token::parse_paren(introducer, iter)?; let ref mut inner = iter::new(paren.stream()); let expr = self::parse(inner)?; token::parse_optional_punct(inner, ','); token::parse_end(inner)?; Ok(Expr::Not(Box::new(expr))) } fn parse_any(introducer: &Ident, iter: Iter) -> Result { let paren = token::parse_paren(introducer, iter)?; let ref mut inner = iter::new(paren.stream()); ``` -------------------------------- ### Error struct and methods Source: https://docs.rs/rustversion/latest/src/rustversion/error.rs.html Defines the Error structure and methods for creating errors from spans or groups, and converting them into compile_error! TokenStreams. ```rust 1use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; 2use std::fmt::Display; 3use std::iter::FromIterator; 4 5pub type Result = std::result::Result; 6 7pub struct Error { 8 begin: Span, 9 end: Span, 10 msg: String, 11} 12 13impl Error { 14 pub fn new(span: Span, msg: impl Display) -> Self { 15 Self::new2(span, span, msg) 16 } 17 18 pub fn new2(begin: Span, end: Span, msg: impl Display) -> Self { 19 Error { 20 begin, 21 end, 22 msg: msg.to_string(), 23 } 24 } 25 26 pub fn group(group: Group, msg: impl Display) -> Self { 27 let mut iter = group.stream().into_iter(); 28 let delimiter = group.span(); 29 let begin = iter.next().map_or(delimiter, |t| t.span()); 30 let end = iter.last().map_or(begin, |t| t.span()); 31 Self::new2(begin, end, msg) 32 } 33 34 pub fn into_compile_error(self) -> TokenStream { 35 // compile_error! { $msg } 36 TokenStream::from_iter(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(), [TokenTree::Ident(Ident::new("compile_error", self.begin)), TokenTree::Punct({ let mut punct = Punct::new('!', Spacing::Alone); punct.set_span(self.begin); punct }), TokenTree::Group({ let mut group = Group::new(Delimiter::Brace, { TokenStream::from_iter(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(), [TokenTree::Literal({ let mut string = Literal::string(&self.msg); string.set_span(self.end); string })]))) }); group.set_span(self.end); group })]))vec![ 37 TokenTree::Ident(Ident::new("compile_error", self.begin)), 38 TokenTree::Punct({ 39 let mut punct = Punct::new('!', Spacing::Alone); 40 punct.set_span(self.begin); 41 punct 42 }), 43 TokenTree::Group({ 44 let mut group = Group::new(Delimiter::Brace, { 45 TokenStream::from_iter(vec![TokenTree::Literal({ 46 let mut string = Literal::string(&self.msg); 47 string.set_span(self.end); 48 string 49 })]) 50 }); 51 group.set_span(self.end); 52 group 53 }), 54 ]) 55 } 56} ``` -------------------------------- ### Expr::eval Method Source: https://docs.rs/rustversion/latest/src/rustversion/expr.rs.html Evaluates an expression against a provided Rust version to determine if the condition is met. ```rust impl Expr { pub fn eval(&self, rustc: Version) -> bool { use self::Expr::*; match self { Stable => rustc.channel == Channel::Stable, Beta => rustc.channel == Channel::Beta, Nightly => match rustc.channel { Channel::Nightly(_) | Channel::Dev => true, Channel::Stable | Channel::Beta => false, }, Date(date) => match rustc.channel { Channel::Nightly(rustc) => rustc == *date, Channel::Stable | Channel::Beta | Channel::Dev => false, }, Since(bound) => rustc >= *bound, Before(bound) => rustc < *bound, Release(release) => { rustc.channel == Channel::Stable && rustc.minor == release.minor && release.patch.map_or(true, |patch| rustc.patch == patch) } Not(expr) => !expr.eval(rustc), Any(exprs) => exprs.iter().any(|e| e.eval(rustc)), All(exprs) => exprs.iter().all(|e| e.eval(rustc)), } } } ``` -------------------------------- ### Expr Enum Definition Source: https://docs.rs/rustversion/latest/src/rustversion/expr.rs.html Defines the supported version-related expressions, including stable, beta, nightly, date-based, bounds, release versions, and logical operators. ```rust pub enum Expr { Stable, Beta, Nightly, Date(Date), Since(Bound), Before(Bound), Release(Release), Not(Box), Any(Vec), All(Vec), } ``` -------------------------------- ### Parse 'all' expression Source: https://docs.rs/rustversion/latest/src/rustversion/expr.rs.html Parses an 'all' expression by consuming a parenthesized group and collecting comma-separated expressions within it. ```rust fn parse_all(introducer: &Ident, iter: Iter) -> Result { let paren = token::parse_paren(introducer, iter)?; let ref mut inner = iter::new(paren.stream()); let exprs = parse_comma_separated(inner)?; Ok(Expr::All(exprs.into_iter().collect())) } ``` -------------------------------- ### Conditionally include Pin for Rust 1.33+ Source: https://docs.rs/rustversion/latest/src/rustversion/lib.rs.html Use the rustversion::since attribute to conditionally include the Pin type and its implementation only when compiling with Rust 1.33 or later. ```rust # trait MyTrait {} # #[rustversion::since(1.33)] use std::pin::Pin; #[rustversion::since(1.33)] impl MyTrait for Pin

{ /* ... */ } ``` -------------------------------- ### rustversion attr.rs parse function Source: https://docs.rs/rustversion/latest/src/rustversion/attr.rs.html Parses a condition expression, expects a comma, then either a const keyword or attribute tokens. Returns an error if no attributes follow the comma. Used internally by rustversion's attribute macro. ```rust use crate::error::{Error, Result}; use crate::expr::{self, Expr}; use crate::{iter, token}; use proc_macro::{Span, TokenStream}; pub struct Args { pub condition: Expr, pub then: Then, } pub enum Then { Const(Span), Attribute(TokenStream), } pub fn parse(input: TokenStream) -> Result { let ref mut input = iter::new(input); let condition = expr::parse(input)?; token::parse_punct(input, ',')?; if input.peek().is_none() { return Err(Error::new(Span::call_site(), "expected one or more attrs")); } let const_span = token::parse_optional_keyword(input, "const"); let then = if let Some(const_span) = const_span { token::parse_optional_punct(input, ','); token::parse_end(input)?; Then::Const(const_span) } else { Then::Attribute(input.collect()) }; Ok(Args { condition, then }) } ``` -------------------------------- ### Conditionally implement traits for stabilized types Source: https://docs.rs/rustversion Use rustversion::since to provide trait implementations only when a type is available in the standard library for a specific compiler version. ```rust #[rustversion::since(1.33)] use std::pin::Pin; #[rustversion::since(1.33)] impl MyTrait for Pin

{ /* ... */ } ``` -------------------------------- ### Conditionally apply struct attributes Source: https://docs.rs/rustversion Use rustversion::attr to apply different repr attributes based on the compiler version. ```rust #[rustversion::attr(before(1.33), repr(packed))] #[rustversion::attr(since(1.33), repr(packed(2)))] struct Six(i16, i32); fn main() { println!("{}", std::mem::align_of::()); } ```