1 | use std::io::Write; |
2 | use std::ops::Deref; |
3 | |
4 | use syn::ext::IdentExt; |
5 | |
6 | use crate::bindgen::cdecl; |
7 | use crate::bindgen::config::{Config, Language}; |
8 | use crate::bindgen::declarationtyperesolver::{DeclarationType, DeclarationTypeResolver}; |
9 | use crate::bindgen::ir::{ConstExpr, Path, Type}; |
10 | use crate::bindgen::utilities::IterHelpers; |
11 | use crate::bindgen::writer::{Source, SourceWriter}; |
12 | |
13 | #[derive (Debug, Clone)] |
14 | pub enum GenericParamType { |
15 | Type, |
16 | Const(Type), |
17 | } |
18 | |
19 | #[derive (Debug, Clone)] |
20 | pub struct GenericParam { |
21 | name: Path, |
22 | ty: GenericParamType, |
23 | } |
24 | |
25 | impl GenericParam { |
26 | pub fn new_type_param(name: &str) -> Self { |
27 | GenericParam { |
28 | name: Path::new(name), |
29 | ty: GenericParamType::Type, |
30 | } |
31 | } |
32 | |
33 | pub fn load(param: &syn::GenericParam) -> Result<Option<Self>, String> { |
34 | match *param { |
35 | syn::GenericParam::Type(syn::TypeParam { ref ident, .. }) => Ok(Some(GenericParam { |
36 | name: Path::new(ident.unraw().to_string()), |
37 | ty: GenericParamType::Type, |
38 | })), |
39 | |
40 | syn::GenericParam::Lifetime(_) => Ok(None), |
41 | |
42 | syn::GenericParam::Const(syn::ConstParam { |
43 | ref ident, ref ty, .. |
44 | }) => match Type::load(ty)? { |
45 | None => { |
46 | // A type that evaporates, like PhantomData. |
47 | Err(format!("unsupported const generic type: {:?}" , ty)) |
48 | } |
49 | Some(ty) => Ok(Some(GenericParam { |
50 | name: Path::new(ident.unraw().to_string()), |
51 | ty: GenericParamType::Const(ty), |
52 | })), |
53 | }, |
54 | } |
55 | } |
56 | |
57 | pub fn name(&self) -> &Path { |
58 | &self.name |
59 | } |
60 | } |
61 | |
62 | #[derive (Default, Debug, Clone)] |
63 | pub struct GenericParams(pub Vec<GenericParam>); |
64 | |
65 | impl GenericParams { |
66 | pub fn load(generics: &syn::Generics) -> Result<Self, String> { |
67 | let mut params = vec![]; |
68 | for param in &generics.params { |
69 | if let Some(p) = GenericParam::load(param)? { |
70 | params.push(p); |
71 | } |
72 | } |
73 | |
74 | Ok(GenericParams(params)) |
75 | } |
76 | |
77 | /// Associate each parameter with an argument. |
78 | pub fn call<'out>( |
79 | &'out self, |
80 | item_name: &str, |
81 | arguments: &'out [GenericArgument], |
82 | ) -> Vec<(&'out Path, &'out GenericArgument)> { |
83 | assert!(self.len() > 0, " {} is not generic" , item_name); |
84 | assert!( |
85 | self.len() == arguments.len(), |
86 | " {} has {} params but is being instantiated with {} values" , |
87 | item_name, |
88 | self.len(), |
89 | arguments.len(), |
90 | ); |
91 | self.iter() |
92 | .map(|param| param.name()) |
93 | .zip(arguments.iter()) |
94 | .collect() |
95 | } |
96 | |
97 | fn write_internal<F: Write>( |
98 | &self, |
99 | config: &Config, |
100 | out: &mut SourceWriter<F>, |
101 | with_default: bool, |
102 | ) { |
103 | if !self.0.is_empty() && config.language == Language::Cxx { |
104 | out.write("template<" ); |
105 | for (i, item) in self.0.iter().enumerate() { |
106 | if i != 0 { |
107 | out.write(", " ); |
108 | } |
109 | match item.ty { |
110 | GenericParamType::Type => { |
111 | write!(out, "typename {}" , item.name); |
112 | if with_default { |
113 | write!(out, " = void" ); |
114 | } |
115 | } |
116 | GenericParamType::Const(ref ty) => { |
117 | cdecl::write_field(out, ty, item.name.name(), config); |
118 | if with_default { |
119 | write!(out, " = 0" ); |
120 | } |
121 | } |
122 | } |
123 | } |
124 | out.write(">" ); |
125 | out.new_line(); |
126 | } |
127 | } |
128 | |
129 | pub fn write_with_default<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) { |
130 | self.write_internal(config, out, true); |
131 | } |
132 | } |
133 | |
134 | impl Deref for GenericParams { |
135 | type Target = [GenericParam]; |
136 | |
137 | fn deref(&self) -> &[GenericParam] { |
138 | &self.0 |
139 | } |
140 | } |
141 | |
142 | impl Source for GenericParams { |
143 | fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) { |
144 | self.write_internal(config, out, with_default:false); |
145 | } |
146 | } |
147 | |
148 | /// A (non-lifetime) argument passed to a generic, either a type or a constant expression. |
149 | /// |
150 | /// Note: Both arguments in a type like `Array<T, N>` are represented as |
151 | /// `GenericArgument::Type`s, even if `N` is actually the name of a const. This |
152 | /// is a consequence of `syn::GenericArgument` doing the same thing. |
153 | #[derive (Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] |
154 | pub enum GenericArgument { |
155 | Type(Type), |
156 | Const(ConstExpr), |
157 | } |
158 | |
159 | impl GenericArgument { |
160 | pub fn specialize(&self, mappings: &[(&Path, &GenericArgument)]) -> GenericArgument { |
161 | match *self { |
162 | GenericArgument::Type(ref ty) => { |
163 | if let Type::Path(ref path) = *ty { |
164 | if path.is_single_identifier() { |
165 | // See note on `GenericArgument` above: `ty` may |
166 | // actually be the name of a const. Check for that now. |
167 | for &(name, value) in mappings { |
168 | if *name == path.path { |
169 | return value.clone(); |
170 | } |
171 | } |
172 | } |
173 | } |
174 | GenericArgument::Type(ty.specialize(mappings)) |
175 | } |
176 | GenericArgument::Const(ref expr) => GenericArgument::Const(expr.clone()), |
177 | } |
178 | } |
179 | |
180 | pub fn rename_for_config(&mut self, config: &Config, generic_params: &GenericParams) { |
181 | match *self { |
182 | GenericArgument::Type(ref mut ty) => ty.rename_for_config(config, generic_params), |
183 | GenericArgument::Const(ref mut expr) => expr.rename_for_config(config), |
184 | } |
185 | } |
186 | } |
187 | |
188 | impl Source for GenericArgument { |
189 | fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) { |
190 | match *self { |
191 | GenericArgument::Type(ref ty: &Type) => ty.write(config, out), |
192 | GenericArgument::Const(ref expr: &ConstExpr) => expr.write(config, out), |
193 | } |
194 | } |
195 | } |
196 | |
197 | #[derive (Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] |
198 | pub struct GenericPath { |
199 | path: Path, |
200 | export_name: String, |
201 | generics: Vec<GenericArgument>, |
202 | ctype: Option<DeclarationType>, |
203 | } |
204 | |
205 | impl GenericPath { |
206 | pub fn new(path: Path, generics: Vec<GenericArgument>) -> Self { |
207 | let export_name = path.name().to_owned(); |
208 | Self { |
209 | path, |
210 | export_name, |
211 | generics, |
212 | ctype: None, |
213 | } |
214 | } |
215 | |
216 | pub fn self_path() -> Self { |
217 | Self::new(Path::new("Self" ), vec![]) |
218 | } |
219 | |
220 | pub fn replace_self_with(&mut self, self_ty: &Path) { |
221 | if self.path.replace_self_with(self_ty) { |
222 | self.export_name = self_ty.name().to_owned(); |
223 | } |
224 | // Caller deals with generics. |
225 | } |
226 | |
227 | pub fn path(&self) -> &Path { |
228 | &self.path |
229 | } |
230 | |
231 | pub fn generics(&self) -> &[GenericArgument] { |
232 | &self.generics |
233 | } |
234 | |
235 | pub fn generics_mut(&mut self) -> &mut [GenericArgument] { |
236 | &mut self.generics |
237 | } |
238 | |
239 | pub fn ctype(&self) -> Option<&DeclarationType> { |
240 | self.ctype.as_ref() |
241 | } |
242 | |
243 | pub fn name(&self) -> &str { |
244 | self.path.name() |
245 | } |
246 | |
247 | pub fn export_name(&self) -> &str { |
248 | &self.export_name |
249 | } |
250 | |
251 | pub fn is_single_identifier(&self) -> bool { |
252 | self.generics.is_empty() |
253 | } |
254 | |
255 | pub fn rename_for_config(&mut self, config: &Config, generic_params: &GenericParams) { |
256 | for generic in &mut self.generics { |
257 | generic.rename_for_config(config, generic_params); |
258 | } |
259 | if !generic_params.iter().any(|param| param.name == self.path) { |
260 | config.export.rename(&mut self.export_name); |
261 | } |
262 | } |
263 | |
264 | pub fn resolve_declaration_types(&mut self, resolver: &DeclarationTypeResolver) { |
265 | self.ctype = resolver.type_for(&self.path); |
266 | } |
267 | |
268 | pub fn load(path: &syn::Path) -> Result<Self, String> { |
269 | assert!( |
270 | !path.segments.is_empty(), |
271 | " {:?} doesn't have any segments" , |
272 | path |
273 | ); |
274 | let last_segment = path.segments.last().unwrap(); |
275 | let name = last_segment.ident.unraw().to_string(); |
276 | |
277 | let path = Path::new(name); |
278 | let phantom_data_path = Path::new("PhantomData" ); |
279 | if path == phantom_data_path { |
280 | return Ok(Self::new(path, Vec::new())); |
281 | } |
282 | |
283 | let generics = match last_segment.arguments { |
284 | syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { |
285 | ref args, |
286 | .. |
287 | }) => args.iter().try_skip_map(|x| match *x { |
288 | syn::GenericArgument::Type(ref x) => Ok(Type::load(x)?.map(GenericArgument::Type)), |
289 | syn::GenericArgument::Lifetime(_) => Ok(None), |
290 | syn::GenericArgument::Const(ref x) => { |
291 | Ok(Some(GenericArgument::Const(ConstExpr::load(x)?))) |
292 | } |
293 | _ => Err(format!("can't handle generic argument {:?}" , x)), |
294 | })?, |
295 | syn::PathArguments::Parenthesized(_) => { |
296 | return Err("Path contains parentheses." .to_owned()); |
297 | } |
298 | _ => Vec::new(), |
299 | }; |
300 | |
301 | Ok(Self::new(path, generics)) |
302 | } |
303 | } |
304 | |