four_char_code_macros_impl/
lib.rs1extern crate proc_macro;
2extern crate syn;
3
4use std::{cmp::Ordering, str::FromStr};
5
6use proc_macro::TokenStream;
7use proc_macro_hack::proc_macro_hack;
8use syn::{parse_macro_input, LitStr};
9
10#[proc_macro_hack]
11pub fn four_char_code(input: TokenStream) -> TokenStream {
12 let input = &parse_macro_input!(input as LitStr);
13 let mut bytes = {
14 let value = input.value();
15
16 match value.len().cmp(&4) {
17 Ordering::Less => {
18 return syn::Error::new_spanned(input, "four char code is too short")
19 .into_compile_error()
20 .into();
21 }
22 Ordering::Greater => {
23 return syn::Error::new_spanned(input, "four char code is too long")
24 .into_compile_error()
25 .into();
26 }
27 _ => (),
28 }
29 let value = value.as_bytes();
30 unsafe {
31 [
32 *value.get_unchecked(0),
33 *value.get_unchecked(1),
34 *value.get_unchecked(2),
35 *value.get_unchecked(3),
36 ]
37 }
38 };
39
40 {
41 let mut null_streak = true;
42
43 let mut i = 3usize;
44 loop {
45 let mut c = bytes[i];
46 if c == 0 {
47 if null_streak {
48 c = 0x20;
49 bytes[i] = c;
50 } else {
51 return syn::Error::new_spanned(input, "invalid char in four char code")
52 .into_compile_error()
53 .into();
54 }
55 } else {
56 null_streak = false;
57 }
58
59 if c <= b'\x1f' || c >= b'\x7f' {
60 return syn::Error::new_spanned(input, "invalid char in four char code")
61 .into_compile_error()
62 .into();
63 }
64
65 if i == 0 {
66 break;
67 }
68 i -= 1;
69 }
70 }
71
72 proc_macro::TokenStream::from_str(
73 &proc_macro::Literal::u32_suffixed(u32::from_be_bytes(bytes)).to_string(),
74 )
75 .unwrap()
76}