1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use alloc::{format, string::String, vec, vec::Vec};
use core::{convert::TryFrom, iter::Cycle, ops::RangeInclusive};
use proc_macro2::Span;
use syn::{GenericParam, Generics, Lifetime, LifetimeDef};
pub struct LifetimeGenerator(Vec<(char, Cycle<RangeInclusive<char>>)>);
impl LifetimeGenerator {
fn new() -> Self {
Self(vec![Self::new_item()])
}
fn new_item() -> (char, Cycle<RangeInclusive<char>>) {
let mut cycle = ('a'..='z').cycle();
cycle.next();
('a', cycle)
}
fn get_current_string(&self) -> String {
self.0.iter().map(|(c, _)| *c).collect()
}
fn inc_combo(&mut self, idx: usize) {
let value = self.0.get_mut(idx).unwrap();
let next = value.1.next().unwrap();
value.0 = next;
if next == 'a' {
if idx == 0 {
self.0.push(Self::new_item());
} else {
self.inc_combo(idx - 1);
}
}
}
}
impl Iterator for LifetimeGenerator {
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
let rval = self.get_current_string();
self.inc_combo(self.0.len() - 1);
Some(format!("'{}", rval))
}
}
impl Default for LifetimeGenerator {
fn default() -> Self {
Self::new()
}
}
pub fn create_new_lifetimes<const N: usize>(base: &Generics) -> ([Lifetime; N], Generics) {
let mut seen_lifetimes = Vec::new();
let mut insert_at = 0;
for (i, param) in base.params.iter().enumerate() {
if let GenericParam::Lifetime(ref lifetime) = param {
seen_lifetimes.push(format!("{}", lifetime.lifetime.ident));
} else {
insert_at = i;
break;
}
}
let mut new_lifetimes = Vec::with_capacity(N);
let mut lifetime_gen = LifetimeGenerator::new();
while new_lifetimes.len() < N {
let lf_name = lifetime_gen.next().unwrap();
if !seen_lifetimes.contains(&lf_name) {
let lifetime = Lifetime::new(&lf_name, Span::call_site());
new_lifetimes.push(lifetime);
}
}
let mut generics = base.clone();
for lf in new_lifetimes.iter() {
let param = GenericParam::Lifetime(LifetimeDef::new(lf.clone()));
generics.params.insert(insert_at, param);
}
let new_lifetimes = if let Ok(a) = <[Lifetime; N]>::try_from(new_lifetimes) {
a
} else {
unreachable!();
};
(new_lifetimes, generics)
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_lifetime_generator() {
let mut gen = LifetimeGenerator::new();
for c in 'a'..='z' {
assert_eq!(gen.next().unwrap(), format!("'{}", c));
}
for c in 'a'..='z' {
assert_eq!(gen.next().unwrap(), format!("'a{}", c));
}
for c in 'a'..='z' {
assert_eq!(gen.next().unwrap(), format!("'b{}", c));
}
}
}