Skip to main content

ab_riscv_macros_common/
code_utils.rs

1//! This module contains hacks for Rust nightly syntax to make it compatible with `syn`
2// TODO: Remove this module once `syn` supports used Rust nightly syntax
3
4const FROM_TRAIT_CONST_1: &str = "const trait ";
5const TO_TRAIT_CONST_1: &str = "trait _const";
6const FROM_TRAIT_CONST_2: &str = "const unsafe trait ";
7const TO_TRAIT_CONST_2: &str = "unsafe trait _const";
8const FROM_IMPL_CONST_1: &str = "const impl";
9const TO_IMPL_CONST_1: &str = "#[cst]impl";
10const FROM_IMPL_CONST_2: &str = "const unsafe impl";
11const TO_IMPL_CONST_2: &str = "#[cst]unsafe impl";
12const FROM_IMPL_CONST_3: &str = "const  impl";
13const TO_IMPL_CONST_3: &str = "#[cst]\nimpl";
14const FROM_IMPL_CONST_4: &str = "const  unsafe impl";
15const TO_IMPL_CONST_4: &str = "#[cst]\nunsafe impl";
16const FROM_IMPL_CONST_REVERT_1: &str = "pub cnst::";
17const TO_IMPL_CONST_REVERT_1: &str = "pub const ";
18const FROM_IMPL_CONST_REVERT_2: &str = "pub cnst ::";
19const TO_IMPL_CONST_REVERT_2: &str = "pub const  ";
20const FROM_IMPL_CONST_REVERT_3: &str = ") cnst::";
21const TO_IMPL_CONST_REVERT_3: &str = ") const ";
22const FROM_IMPL_CONST_REVERT_4: &str = ") cnst ::";
23const TO_IMPL_CONST_REVERT_4: &str = ") const  ";
24const FROM_IMPL_CONST_REVERT_5: &str = "cnst::fn";
25const TO_IMPL_CONST_REVERT_5: &str = "const fn";
26
27const FROM_BRACKETS_CONST_1: &str = "[const] ";
28const TO_BRACKETS_CONST_1: &str = "BRCONST+";
29const FROM_BRACKETS_CONST_2: &str = " [const] ";
30const TO_BRACKETS_CONST_2: &str = "BRCONST +";
31const FROM_BRACKETS_CONST_3: &str = ": [const]\n        ";
32const TO_BRACKETS_CONST_3: &str = ": BRCONST\n       +";
33const FROM_BRACKETS_CONST_4: &str = ": [const]\n         ";
34const TO_BRACKETS_CONST_4: &str = ": BRCONST\n        +";
35
36const FROM_WHERE_CONST_1: &str = ": const ";
37const TO_WHERE_CONST_1: &str = ": CONST+";
38const FROM_WHERE_CONST_2: &str = ": const  ";
39const TO_WHERE_CONST_2: &str = ": CONST +";
40
41/// Replace bits of Rust nightly syntax with something that is technically valid in stable Rust, so
42/// `syn` can parse it
43pub fn pre_process_rust_code(s: &mut str) {
44    replace_inplace(s, FROM_TRAIT_CONST_1, TO_TRAIT_CONST_1);
45    replace_inplace(s, FROM_TRAIT_CONST_2, TO_TRAIT_CONST_2);
46    replace_inplace(s, FROM_IMPL_CONST_1, TO_IMPL_CONST_1);
47    replace_inplace(s, FROM_IMPL_CONST_2, TO_IMPL_CONST_2);
48    replace_inplace(s, FROM_IMPL_CONST_3, TO_IMPL_CONST_3);
49    replace_inplace(s, FROM_IMPL_CONST_4, TO_IMPL_CONST_4);
50    replace_inplace(s, FROM_IMPL_CONST_REVERT_1, TO_IMPL_CONST_REVERT_1);
51    replace_inplace(s, FROM_IMPL_CONST_REVERT_2, TO_IMPL_CONST_REVERT_2);
52    replace_inplace(s, FROM_IMPL_CONST_REVERT_3, TO_IMPL_CONST_REVERT_3);
53    replace_inplace(s, FROM_IMPL_CONST_REVERT_4, TO_IMPL_CONST_REVERT_4);
54    replace_inplace(s, FROM_IMPL_CONST_REVERT_5, TO_IMPL_CONST_REVERT_5);
55    replace_inplace(s, FROM_BRACKETS_CONST_1, TO_BRACKETS_CONST_1);
56    replace_inplace(s, FROM_BRACKETS_CONST_2, TO_BRACKETS_CONST_2);
57    replace_inplace(s, FROM_BRACKETS_CONST_3, TO_BRACKETS_CONST_3);
58    replace_inplace(s, FROM_BRACKETS_CONST_4, TO_BRACKETS_CONST_4);
59    replace_inplace(s, FROM_WHERE_CONST_1, TO_WHERE_CONST_1);
60    replace_inplace(s, FROM_WHERE_CONST_2, TO_WHERE_CONST_2);
61}
62
63/// The inverse of [`pre_process_rust_code()`]
64pub fn post_process_rust_code(s: &mut str) {
65    replace_inplace(s, TO_TRAIT_CONST_2, FROM_TRAIT_CONST_2);
66    replace_inplace(s, TO_TRAIT_CONST_1, FROM_TRAIT_CONST_1);
67    replace_inplace(s, TO_IMPL_CONST_1, FROM_IMPL_CONST_1);
68    replace_inplace(s, TO_IMPL_CONST_2, FROM_IMPL_CONST_2);
69    replace_inplace(s, TO_IMPL_CONST_3, FROM_IMPL_CONST_3);
70    replace_inplace(s, TO_IMPL_CONST_4, FROM_IMPL_CONST_4);
71    replace_inplace(s, TO_BRACKETS_CONST_1, FROM_BRACKETS_CONST_1);
72    replace_inplace(s, TO_BRACKETS_CONST_2, FROM_BRACKETS_CONST_2);
73    replace_inplace(s, TO_BRACKETS_CONST_3, FROM_BRACKETS_CONST_3);
74    replace_inplace(s, TO_BRACKETS_CONST_4, FROM_BRACKETS_CONST_4);
75    replace_inplace(s, TO_WHERE_CONST_1, FROM_WHERE_CONST_1);
76    replace_inplace(s, TO_WHERE_CONST_2, FROM_WHERE_CONST_2);
77}
78
79fn replace_inplace(mut s: &mut str, from: &str, to: &str) {
80    assert_eq!(from.len(), to.len(), "`{from}` != `{to}`");
81
82    if from.is_empty() {
83        return;
84    }
85
86    #[expect(clippy::string_slice, reason = "Offset is a search result")]
87    while let Some(found) = s.find(from) {
88        let start = found;
89        let end = found + from.len();
90
91        // SAFETY: Replacing a valid string with a valid string of the same length
92        unsafe { s.as_bytes_mut() }
93            .get_mut(start..end)
94            .expect("Just found a string of the desired length; qed")
95            .copy_from_slice(to.as_bytes());
96
97        s = &mut s[end..];
98    }
99}