1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
use std::env;

use proc_macro::{Span, TokenTree};

use crate::{
    error::{Error, Result},
    iter::Iter,
    version::{Channel, Version},
};

pub enum Expr {
    Msrv,
}

impl Expr {
    pub fn eval(&self, rustc: Version) -> bool {
        use self::Expr::*;

        match self {
            Msrv => {
                let cargo_rust_version = env::var("CARGO_PKG_RUST_VERSION")
                    .expect("manifest should specify a rust-version to use the msrv macro");
                let mut cargo_rust_version = cargo_rust_version.splitn(3, '.');

                let _maj = cargo_rust_version.next().unwrap();
                let min = cargo_rust_version.next().unwrap().parse::<u16>().unwrap();
                let patch = cargo_rust_version
                    .next()
                    .map_or(0, |val| val.parse().unwrap());

                rustc.channel == Channel::Stable && rustc.minor == min && rustc.patch >= patch
            }
        }
    }
}

pub fn parse(iter: Iter) -> Result<Expr> {
    match &iter.next() {
        Some(TokenTree::Ident(i)) if i.to_string() == "msrv" => Ok(Expr::Msrv),
        unexpected => {
            let span = unexpected
                .as_ref()
                .map_or_else(Span::call_site, TokenTree::span);
            Err(Error::new(span, "expected `msrv`"))
        }
    }
}