1use quote::ToTokens;
11
12use once_cell::sync::Lazy;
13
14use std::collections::{HashMap, HashSet};
15use std::sync::Mutex;
16
17use crate::enum_dispatch_item;
18
19#[derive(PartialEq, Eq, Hash, Clone)]
21struct UniqueItemId {
22 item_name: String,
23 num_generics: usize,
24}
25
26impl UniqueItemId {
27 pub fn new(item_name: String, num_generics: usize) -> Self {
29 Self {
30 item_name,
31 num_generics,
32 }
33 }
34}
35
36static TRAIT_DEFS: Lazy<Mutex<HashMap<UniqueItemId, String>>> =
39 Lazy::new(|| Mutex::new(HashMap::new()));
40static ENUM_DEFS: Lazy<Mutex<HashMap<UniqueItemId, String>>> =
41 Lazy::new(|| Mutex::new(HashMap::new()));
42static DEFERRED_LINKS: Lazy<Mutex<HashMap<UniqueItemId, Vec<UniqueItemId>>>> =
43 Lazy::new(|| Mutex::new(HashMap::new()));
44static ENUM_CONVERSION_IMPLS_DEFS: Lazy<Mutex<HashSet<UniqueItemId>>> =
45 Lazy::new(|| Mutex::new(HashSet::new()));
46
47pub fn cache_trait(item: syn::ItemTrait) {
49 let num_generics = crate::supported_generics::num_supported_generics(&item.generics);
50 let uid = UniqueItemId::new(item.ident.to_string(), num_generics);
51 TRAIT_DEFS
52 .lock()
53 .unwrap()
54 .insert(uid, item.into_token_stream().to_string());
55}
56
57pub fn cache_enum_dispatch(item: enum_dispatch_item::EnumDispatchItem) {
59 let num_generics = crate::supported_generics::num_supported_generics(&item.generics);
60 let uid = UniqueItemId::new(item.ident.to_string(), num_generics);
61 ENUM_DEFS
62 .lock()
63 .unwrap()
64 .insert(uid, item.into_token_stream().to_string());
65}
66
67pub fn cache_enum_conversion_impls_defined(item: syn::Ident, num_generics: usize) {
69 let uid = UniqueItemId::new(item.to_string(), num_generics);
70 ENUM_CONVERSION_IMPLS_DEFS.lock().unwrap().insert(uid);
71}
72
73pub fn defer_link(
78 (needed, needed_num_generics): (&::proc_macro2::Ident, usize),
79 (cached, cached_num_generics): (&::proc_macro2::Ident, usize),
80) {
81 use std::collections::hash_map::Entry;
82
83 let (needed, cached) = (
84 UniqueItemId::new(needed.to_string(), needed_num_generics),
85 UniqueItemId::new(cached.to_string(), cached_num_generics),
86 );
87 let mut deferred_links = DEFERRED_LINKS.lock().unwrap();
88 if deferred_links.contains_key(&needed) {
89 deferred_links
90 .get_mut(&needed)
91 .unwrap()
92 .push(cached.to_owned());
93 } else {
94 deferred_links.insert(needed.to_owned(), vec![cached.to_owned()]);
95 }
96 if let Entry::Vacant(e) = deferred_links.entry(cached.clone()) {
97 e.insert(vec![needed]);
98 } else {
99 deferred_links.get_mut(&cached).unwrap().push(needed);
100 }
101}
102
103pub fn fulfilled_by_enum(
106 defname: &::proc_macro2::Ident,
107 num_generic_args: usize,
108) -> Vec<syn::ItemTrait> {
109 let idents = match DEFERRED_LINKS
110 .lock()
111 .unwrap()
112 .remove_entry(&UniqueItemId::new(defname.to_string(), num_generic_args))
113 {
114 Some((_, links)) => links,
115 None => vec![],
116 };
117 idents
118 .iter()
119 .filter_map(
120 |ident_string| TRAIT_DEFS.lock().unwrap().get(ident_string).map(|entry| syn::parse(entry.parse().unwrap()).unwrap())
121 )
122 .collect()
123}
124
125pub fn fulfilled_by_trait(
128 defname: &::proc_macro2::Ident,
129 num_generic_args: usize,
130) -> Vec<enum_dispatch_item::EnumDispatchItem> {
131 let idents = match DEFERRED_LINKS
132 .lock()
133 .unwrap()
134 .remove_entry(&UniqueItemId::new(defname.to_string(), num_generic_args))
135 {
136 Some((_, links)) => links,
137 None => vec![],
138 };
139 idents
140 .iter()
141 .filter_map(
142 |ident_string| ENUM_DEFS.lock().unwrap().get(ident_string).map(|entry| syn::parse(entry.parse().unwrap()).unwrap())
143 )
144 .collect()
145}
146
147pub fn conversion_impls_def_by_enum(item: &syn::Ident, num_generics: usize) -> bool {
149 ENUM_CONVERSION_IMPLS_DEFS
150 .lock()
151 .unwrap()
152 .contains(&UniqueItemId::new(item.to_string(), num_generics))
153}