1#![cfg_attr(not(check_cfg), allow(unexpected_cfgs))]
2#![allow(
3 clippy::cast_lossless,
4 clippy::manual_range_contains,
5 clippy::match_same_arms,
6 clippy::needless_pass_by_value,
7 clippy::uninlined_format_args,
8 clippy::unnecessary_wraps
9)]
10#![cfg_attr(all(test, exhaustive), feature(non_exhaustive_omitted_patterns_lint))]
11
12use proc_macro::TokenStream;
13use proc_macro2::{Ident, Span, TokenStream as TokenStream2};
14use quote::{quote, ToTokens};
15use std::mem;
16use syn::{parse_macro_input, Error, Lit, LitInt, Result};
17
18const K: usize = 6;
20
21#[allow(non_snake_case)]
22#[proc_macro]
23pub fn MustBe(input: TokenStream) -> TokenStream {
24 let lit = parse_macro_input!(input as Lit);
25
26 #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
27 let expanded = match lit {
28 Lit::Str(lit) => must_be_str(lit.value()),
29 Lit::Byte(lit) => must_be_byte(lit.value()),
30 Lit::Char(lit) => must_be_char(lit.value()),
31 Lit::Int(lit) => must_be_int(lit),
32 Lit::Bool(lit) => must_be_bool(lit.value),
33 Lit::ByteStr(_) | Lit::CStr(_) | Lit::Float(_) | Lit::Verbatim(_) => unsupported(lit),
34 _ => unsupported(lit),
35 };
36
37 expanded.unwrap_or_else(Error::into_compile_error).into()
38}
39
40enum StrNode {
65 Char(char),
66 Tuple(Vec<StrNode>),
67}
68
69impl ToTokens for StrNode {
70 fn to_tokens(&self, tokens: &mut TokenStream2) {
71 tokens.extend(match self {
72 StrNode::Char(ch) => {
73 if let 'A'..='Z' | 'a'..='z' = ch {
74 let mut buf = [0];
75 let name = ch.encode_utf8(&mut buf);
76 let ident = Ident::new(name, Span::call_site());
77 quote!(::monostate::alphabet::#ident)
78 } else {
79 match ch.len_utf8() {
80 1 => quote!(::monostate::alphabet::char<#ch>),
81 2 => quote!(::monostate::alphabet::two::char<#ch>),
82 3 => quote!(::monostate::alphabet::three::char<#ch>),
83 4 => quote!(::monostate::alphabet::four::char<#ch>),
84 _ => unreachable!(),
85 }
86 }
87 }
88 StrNode::Tuple(vec) => {
89 let len = vec.len();
90 assert!(len >= 2 && len <= K, "len={}", len);
91 quote!((#(#vec),*))
92 }
93 });
94 }
95}
96
97fn must_be_str(value: String) -> Result<TokenStream2> {
98 if value.is_empty() {
99 return Ok(quote!(::monostate::MustBeStr::<()>));
100 }
101 let mut nodes = Vec::new();
102 for ch in value.chars() {
103 nodes.push(StrNode::Char(ch));
104 }
105 let mut pow = 1;
107 while pow * K < nodes.len() {
108 pow *= K;
109 }
110 while nodes.len() > 1 {
111 let overage = nodes.len() - pow;
113 let num_tuple_nodes = (overage + K - 2) / (K - 1);
118 let mut remainder = num_tuple_nodes + overage;
120 let mut read = nodes.len() - remainder;
122 let mut write = read;
124 let mut make_tuple = true;
126 while let Some(node) = nodes.get_mut(read) {
127 let next = mem::replace(node, StrNode::Char('\0'));
128 if make_tuple {
129 nodes[write] = StrNode::Tuple(Vec::with_capacity(K));
130 }
131 if let StrNode::Tuple(vec) = &mut nodes[write] {
132 vec.push(next);
133 } else {
134 unreachable!();
135 }
136 remainder -= 1;
137 make_tuple = remainder % K == 0;
138 write += make_tuple as usize;
139 read += 1;
140 }
141 nodes.truncate(pow);
142 pow /= K;
143 }
144 let encoded = &nodes[0];
145 Ok(quote!(::monostate::MustBeStr::<#encoded>))
146}
147
148fn must_be_byte(value: u8) -> Result<TokenStream2> {
149 Ok(quote!(::monostate::MustBeU8::<#value>))
150}
151
152fn must_be_char(value: char) -> Result<TokenStream2> {
153 Ok(quote!(::monostate::MustBeChar::<#value>))
154}
155
156fn must_be_int(lit: LitInt) -> Result<TokenStream2> {
157 let token = lit.token();
158 match lit.suffix() {
159 "u8" => Ok(quote!(::monostate::MustBeU8::<#token>)),
160 "u16" => Ok(quote!(::monostate::MustBeU16::<#token>)),
161 "u32" => Ok(quote!(::monostate::MustBeU32::<#token>)),
162 "u64" => Ok(quote!(::monostate::MustBeU64::<#token>)),
163 "u128" => Ok(quote!(::monostate::MustBeU128::<#token>)),
164 "i8" => Ok(quote!(::monostate::MustBeI8::<#token>)),
165 "i16" => Ok(quote!(::monostate::MustBeI16::<#token>)),
166 "i32" => Ok(quote!(::monostate::MustBeI32::<#token>)),
167 "i64" => Ok(quote!(::monostate::MustBeI64::<#token>)),
168 "i128" => Ok(quote!(::monostate::MustBeI128::<#token>)),
169 "" => {
170 if lit.base10_digits().starts_with('-') {
171 Ok(quote!(::monostate::MustBeNegInt::<#token>))
172 } else {
173 Ok(quote!(::monostate::MustBePosInt::<#token>))
174 }
175 }
176 suffix @ ("usize" | "isize") => {
177 let msg = format!(
178 "serde data model only uses consistently sized integer types, not {}",
179 suffix,
180 );
181 Err(Error::new(lit.span(), msg))
182 }
183 suffix => {
184 let msg = format!("unsupported integers suffix `{}`", suffix);
185 Err(Error::new(lit.span(), msg))
186 }
187 }
188}
189
190fn must_be_bool(value: bool) -> Result<TokenStream2> {
191 Ok(quote!(::monostate::MustBeBool::<#value>))
192}
193
194fn unsupported(lit: Lit) -> Result<TokenStream2> {
195 Err(Error::new(lit.span(), "unsupported monostate literal kind"))
196}