1use serde_derive_internals::Ctxt;
2use std::collections::{BTreeMap, BTreeSet};
3use syn::Ident;
4
5pub fn get_rename_format_type_params<'a>(
6 errors: &Ctxt,
7 rename_format_string: &syn::LitStr,
8 generics: &'a syn::Generics,
9) -> BTreeSet<&'a Ident> {
10 let mut type_params = BTreeSet::new();
11 let mut str_value = rename_format_string.value();
12
13 if !str_value.contains('{') {
14 return type_params;
15 }
16
17 if str_value.contains("{{") {
18 str_value = str_value.replace("{{", "");
19 }
20
21 if str_value.contains("}}") {
22 str_value = str_value.replace("}}", "");
23 }
24
25 let all_const_params =
26 BTreeSet::from_iter(generics.const_params().map(|c| c.ident.to_string()));
27 let all_type_params = BTreeMap::from_iter(
28 generics
29 .type_params()
30 .map(|c| (c.ident.to_string(), &c.ident)),
31 );
32
33 let mut segments = str_value.split('{');
34
35 if segments.next().unwrap_or_default().contains('}') {
36 errors.error_spanned_by(
38 rename_format_string,
39 "invalid name format string: unmatched `}` found",
40 );
41 }
42
43 for segment in segments {
44 match segment.split_once('}') {
45 Some((param, rest)) => {
46 if rest.contains('}') {
47 errors.error_spanned_by(
48 rename_format_string,
49 "invalid name format string: unmatched `}` found",
50 );
51 }
52
53 if let Some(type_param) = all_type_params.get(param) {
54 type_params.insert(type_param);
55 } else if all_const_params.contains(param) {
56 } else {
59 errors.error_spanned_by(
60 rename_format_string,
61 format_args!(
62 "invalid name format string: expected generic param, found `{param}`"
63 ),
64 );
65 }
66 }
67 None => {
68 errors.error_spanned_by(
69 rename_format_string,
70 "invalid name format string: found `{` without matching `}`",
71 );
72 }
73 }
74 }
75
76 type_params
77}