checked_rs_macro_impl/
lib.rs

1//! # checked-rs-macro-impl
2//!
3//! > Implementation of the procedural macros for checked-rs. This crate is not intended to be used directly.
4//! > Instead, you should use the `checked-rs` crate, which re-exports the public macros from this crate.
5//!
6
7use proc_macro2::TokenStream;
8
9pub mod common_impl;
10pub mod enum_impl;
11pub mod hard_impl;
12pub mod soft_impl;
13
14pub mod item;
15pub mod params;
16mod range_seq;
17
18use item::ClampedItem;
19use params::NumberValueRange;
20
21pub fn clamped(item: ClampedItem) -> TokenStream {
22    let params = match item.params() {
23        Ok(params) => params,
24        Err(err) => return err.to_compile_error(),
25    };
26
27    match item {
28        ClampedItem::Enum(item) => match enum_impl::define_mod(&params, &item.variants) {
29            Ok(ts) => ts,
30            Err(err) => err.to_compile_error(),
31        },
32        ClampedItem::Struct(item) => {
33            let ranges = item
34                .field
35                .ranges
36                .iter()
37                .map(|range| NumberValueRange::from_arg_range(range.clone(), params.integer))
38                .collect::<syn::Result<Vec<_>>>();
39
40            let ranges = match ranges {
41                Ok(ranges) => ranges,
42                Err(err) => return err.to_compile_error(),
43            };
44
45            match item.as_soft_or_hard {
46                None => match soft_impl::define_mod(&params, &ranges) {
47                    Ok(ts) => ts,
48                    Err(err) => err.to_compile_error(),
49                },
50                Some(params::AsSoftOrHard::Soft { .. }) => {
51                    match soft_impl::define_mod(&params, &ranges) {
52                        Ok(ts) => ts,
53                        Err(err) => err.to_compile_error(),
54                    }
55                }
56                Some(params::AsSoftOrHard::Hard { .. }) => {
57                    match hard_impl::define_mod(&params, &ranges) {
58                        Ok(ts) => ts,
59                        Err(err) => err.to_compile_error(),
60                    }
61                }
62            }
63        }
64    }
65}
66
67#[cfg(test)]
68macro_rules! snapshot {
69    ($ty:ty => { $($tt:tt)* }) => {{
70        let ts: $ty = match syn::parse2(quote::quote!($($tt)*)) {
71            Ok(ts) => ts,
72            Err(err) => panic!("Failed to parse as `{}`: {}", stringify!($ty), err),
73        };
74
75        insta::assert_snapshot!(&ts.to_token_stream().to_string());
76    }};
77    ($ty:ty => { $($tt:tt)* } => Formatted) => {{
78        let ts: $ty = match syn::parse2(quote::quote!($($tt)*)) {
79            Ok(ts) => ts,
80            Err(err) => panic!("Failed to parse as `{}`: {}", stringify!($ty), err),
81        };
82
83        insta::assert_snapshot!(prettyplease::unparse(
84            &syn::parse_file(&ts.to_token_stream().to_string()).unwrap()
85        ));
86    }};
87}
88
89#[cfg(test)]
90pub(crate) use snapshot;
91
92#[cfg(test)]
93macro_rules! assert_parse {
94    ($ty:ty => { $($tt:tt)* }) => {{
95        match syn::parse2::<$ty>(quote::quote!($($tt)*)) {
96            Ok(..) => { /* Success */ },
97            Err(err) => panic!("Failed to parse: {}", err),
98        };
99    }};
100
101    ($ty:ty => { $($tt:tt)* } => !) => {{
102        match syn::parse2::<$ty>(quote::quote!($($tt)*)) {
103            Ok(..) => panic!("Expected to fail parsing"),
104            Err(..) => { /* Success */ }
105        }
106    }};
107
108    ($ty:ty => { $($tt:tt)* } => { $($exp:tt)* }) => {{
109        let x = match syn::parse2::<$ty>(quote::quote!($($tt)*)) {
110            Ok(x) => x,
111            Err(err) => panic!("Failed to parse: {}", err),
112        };
113
114        if !matches!(x, $($exp)*) {
115            panic!("Expected {:?}, got {:?}", quote::quote!($($exp)*), quote::quote!(x));
116        }
117    }};
118}
119
120#[cfg(test)]
121pub(crate) use assert_parse;