musli_macros/internals/
ctxt.rs
1use std::cell::RefCell;
2use std::collections::HashMap;
3use std::fmt::{self, Write};
4use std::rc::Rc;
5
6use proc_macro2::Span;
7
8use super::attr::{ModeIdent, ModeKind};
9use super::build::Field;
10use super::ATTR;
11
12struct Inner {
13 b1: String,
14 modes: HashMap<ModeKind, ModeIdent>,
15 errors: Vec<syn::Error>,
16 #[cfg(not(feature = "verbose"))]
17 names: HashMap<String, usize>,
18 #[cfg(not(feature = "verbose"))]
19 types: usize,
20}
21
22pub(crate) struct Ctxt {
23 inner: RefCell<Inner>,
24}
25
26impl Ctxt {
27 pub(crate) fn new() -> Self {
29 Self {
30 inner: RefCell::new(Inner {
31 b1: String::new(),
32 modes: HashMap::new(),
33 errors: Vec::new(),
34 #[cfg(not(feature = "verbose"))]
35 names: HashMap::new(),
36 #[cfg(not(feature = "verbose"))]
37 types: 0,
38 }),
39 }
40 }
41
42 pub(crate) fn transparent_diagnostics(&self, span: Span, fields: &[Rc<Field>]) {
45 if fields.is_empty() {
46 self.error_span(
47 span,
48 format_args!("#[{ATTR}(transparent)] types must have a single unskipped field"),
49 );
50 } else {
51 self.error_span(
52 span,
53 format_args!(
54 "#[{ATTR}(transparent)] can only be used on types which have a single field",
55 ),
56 );
57 }
58 }
59
60 pub(crate) fn register_mode(&self, mode: ModeIdent) {
62 self.inner
63 .borrow_mut()
64 .modes
65 .insert(mode.kind.clone(), mode);
66 }
67
68 pub(crate) fn has_errors(&self) -> bool {
70 !self.inner.borrow().errors.is_empty()
71 }
72
73 pub(crate) fn error_span<T>(&self, span: Span, message: T)
75 where
76 T: fmt::Display,
77 {
78 self.inner
79 .borrow_mut()
80 .errors
81 .push(syn::Error::new(span, message));
82 }
83
84 pub(crate) fn syn_error(&self, error: syn::Error) {
86 self.inner.borrow_mut().errors.push(error);
87 }
88
89 pub(crate) fn into_errors(self) -> Vec<syn::Error> {
91 std::mem::take(&mut self.inner.borrow_mut().errors)
92 }
93
94 pub(crate) fn modes(&self) -> Vec<ModeIdent> {
96 self.inner.borrow().modes.values().cloned().collect()
97 }
98
99 pub(crate) fn reset(&self) {
100 #[cfg(not(feature = "verbose"))]
101 {
102 let mut inner = self.inner.borrow_mut();
103 inner.names.clear();
104 inner.types = 0;
105 }
106 }
107
108 #[allow(unused)]
110 pub(crate) fn lifetime(&self, name: &str) -> syn::Lifetime {
111 self.with_string("'", name, "", |s| syn::Lifetime::new(s, Span::call_site()))
112 }
113
114 pub(crate) fn ident(&self, name: &str) -> syn::Ident {
116 self.ident_with_span(name, Span::call_site(), "")
117 }
118
119 pub(crate) fn ident_with_span(&self, name: &str, span: Span, extra: &str) -> syn::Ident {
121 self.with_string("", name, extra, |s| syn::Ident::new(s, span))
122 }
123
124 fn with_string<F, O>(&self, prefix: &str, name: &str, suffix: &str, f: F) -> O
125 where
126 F: FnOnce(&str) -> O,
127 {
128 let mut inner = self.inner.borrow_mut();
129
130 #[cfg(not(feature = "verbose"))]
131 {
132 let index = if let Some(index) = inner.names.get(name) {
133 *index
134 } else {
135 let index = inner.names.len();
136 inner.names.insert(name.to_owned(), index);
137 index
138 };
139
140 _ = write!(inner.b1, "{prefix}_{index}{suffix}");
141 }
142
143 #[cfg(feature = "verbose")]
144 {
145 let name = name.strip_prefix('_').unwrap_or(name);
146 _ = write!(inner.b1, "{prefix}_{name}{suffix}");
147 }
148
149 let ident = f(&inner.b1);
150 inner.b1.clear();
151 ident
152 }
153
154 pub(crate) fn type_with_span<N>(
156 &self,
157 #[cfg_attr(not(feature = "verbose"), allow(unused))] name: N,
158 span: Span,
159 ) -> syn::Ident
160 where
161 N: fmt::Display,
162 {
163 let mut inner = self.inner.borrow_mut();
164
165 #[cfg(not(feature = "verbose"))]
166 {
167 let index = inner.types;
168 inner.types += 1;
169 _ = write!(inner.b1, "T{index}");
170 }
171
172 #[cfg(feature = "verbose")]
173 {
174 _ = write!(inner.b1, "{name}");
175 }
176
177 let ident = syn::Ident::new(&inner.b1, span);
178 inner.b1.clear();
179 ident
180 }
181}