derive_deftly_macros/
semver.rs

1//! Macro impl for `template_export_semver_check!`
2
3use super::prelude::*;
4
5#[derive(Debug, Clone)]
6struct SemverCheckInput {
7    span: Span,
8    major: u32,
9    minor: u32,
10    patch: u32,
11}
12
13impl Display for SemverCheckInput {
14    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
15        write!(f, "{}.{}.x", self.major, self.minor)
16    }
17}
18
19impl Parse for SemverCheckInput {
20    fn parse(input: ParseStream) -> syn::Result<Self> {
21        let lit: syn::LitStr = input.parse()?;
22        let span = lit.span();
23        let s = lit.value();
24        let mut nums = s.split('.');
25
26        let mut next_num = || {
27            let n = match nums.next() {
28                Some(y) => y,
29                None => return Ok(None),
30            };
31            let n = n.parse().map_err(|e| {
32                span.error(format_args!("bad number: {}", e)) //
33            })?;
34            Ok::<_, syn::Error>(Some(n))
35        };
36        let mut next_num_must = || {
37            next_num()?.ok_or_else(|| {
38                span.error("too few components in version number")
39            })
40        };
41        let major = next_num_must()?;
42        let minor = next_num_must()?;
43        let patch = next_num()?.unwrap_or(0);
44        if nums.next().is_some() {
45            return Err(span.error("too many components in version number"));
46        }
47        Ok(SemverCheckInput {
48            major,
49            minor,
50            patch,
51            span,
52        })
53    }
54}
55
56impl Spanned for SemverCheckInput {
57    fn span(&self) -> Span {
58        self.span
59    }
60}
61
62/// This is `template_export_semver_check!`
63pub fn template_export_semver_check_func_macro(
64    input: TokenStream,
65) -> Result<TokenStream, syn::Error> {
66    let version: SemverCheckInput = syn::parse2(input)?;
67
68    let mk_err = |e: &dyn Display| Err(version.error(e));
69    let too_new = || {
70        mk_err(
71            &"declared version is greater than this version of derive-deftly!",
72        )
73    };
74    let too_old = || {
75        mk_err(&format_args!(
76            r#"derive-deftly has been updated!
77Please check the changelog for breaking changes since {}
78Search for section titles containing "template export semver"."#,
79            version,
80        ))
81    };
82
83    match (version.major, version.minor, version.patch) {
84        (0, 0..=11, _) => return too_old(),
85        // We tolerate "too new" within the same minor version,
86        // since otherwise updating the patchlevel is too tedious.
87        // There are tests to catch failure to update this.
88        (0, 12, 0) => return too_old(),
89        (0, 12, 1..) => {}
90        (0, 13.., _) => {}
91        (1, 0..=6, _) => {}
92        (1, 7.., _) => return too_new(),
93        (2.., _, _) => return too_new(),
94    }
95
96    Ok(TokenStream::new())
97}