blob: 1525fbcff7cc88a624d014468dfee669772d5c35 [file] [log] [blame]
David Tolnay17e137f2020-05-08 15:55:28 -07001use crate::syntax::discriminant::DiscriminantSet;
David Tolnay52759782020-05-03 23:59:40 -07002use crate::syntax::report::Errors;
David Tolnayeebe9b72020-04-14 16:32:18 -07003use crate::syntax::Atom::*;
David Tolnay7db73692019-10-20 14:51:12 -04004use crate::syntax::{
Joel Galensonc03402a2020-04-23 17:31:09 -07005 attrs, error, Api, Doc, Enum, ExternFn, ExternType, Lang, Receiver, Ref, Signature, Slice,
David Tolnaye2f9ec42020-05-07 16:19:33 -07006 Struct, Ty1, Type, TypeAlias, Var, Variant,
David Tolnay7db73692019-10-20 14:51:12 -04007};
David Tolnaye2f9ec42020-05-07 16:19:33 -07008use proc_macro2::TokenStream;
David Tolnaye2e303f2020-05-10 20:52:00 -07009use quote::{format_ident, quote, quote_spanned};
David Tolnaye2f9ec42020-05-07 16:19:33 -070010use syn::parse::{ParseStream, Parser};
David Tolnaye3a48152020-04-08 19:38:05 -070011use syn::punctuated::Punctuated;
David Tolnay7db73692019-10-20 14:51:12 -040012use syn::{
David Tolnay17e137f2020-05-08 15:55:28 -070013 Abi, Attribute, Error, Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemType,
14 GenericArgument, Ident, Item, ItemEnum, ItemForeignMod, ItemStruct, Pat, PathArguments, Result,
15 ReturnType, Token, Type as RustType, TypeBareFn, TypePath, TypeReference, TypeSlice,
David Tolnay7db73692019-10-20 14:51:12 -040016};
17
David Tolnaye3a48152020-04-08 19:38:05 -070018pub mod kw {
19 syn::custom_keyword!(Result);
20}
21
David Tolnay52759782020-05-03 23:59:40 -070022pub fn parse_items(cx: &mut Errors, items: Vec<Item>) -> Vec<Api> {
David Tolnay7db73692019-10-20 14:51:12 -040023 let mut apis = Vec::new();
24 for item in items {
25 match item {
David Tolnay3e628882020-05-10 15:30:14 -070026 Item::Struct(item) => match parse_struct(cx, item) {
David Tolnay52759782020-05-03 23:59:40 -070027 Ok(strct) => apis.push(strct),
28 Err(err) => cx.push(err),
29 },
David Tolnay3e628882020-05-10 15:30:14 -070030 Item::Enum(item) => match parse_enum(cx, item) {
David Tolnay52759782020-05-03 23:59:40 -070031 Ok(enm) => apis.push(enm),
32 Err(err) => cx.push(err),
33 },
34 Item::ForeignMod(foreign_mod) => parse_foreign_mod(cx, foreign_mod, &mut apis),
35 Item::Use(item) => cx.error(item, error::USE_NOT_ALLOWED),
36 _ => cx.error(item, "unsupported item"),
David Tolnay7db73692019-10-20 14:51:12 -040037 }
38 }
David Tolnay52759782020-05-03 23:59:40 -070039 apis
David Tolnay7db73692019-10-20 14:51:12 -040040}
41
David Tolnay3e628882020-05-10 15:30:14 -070042fn parse_struct(cx: &mut Errors, item: ItemStruct) -> Result<Api> {
David Tolnay7db73692019-10-20 14:51:12 -040043 let generics = &item.generics;
44 if !generics.params.is_empty() || generics.where_clause.is_some() {
45 let struct_token = item.struct_token;
46 let ident = &item.ident;
47 let where_clause = &generics.where_clause;
48 let span = quote!(#struct_token #ident #generics #where_clause);
49 return Err(Error::new_spanned(
50 span,
51 "struct with generic parameters is not supported yet",
52 ));
53 }
54
55 let mut doc = Doc::new();
56 let mut derives = Vec::new();
David Tolnayb129ea72020-05-10 14:29:30 -070057 attrs::parse(
David Tolnay3e628882020-05-10 15:30:14 -070058 cx,
David Tolnayb129ea72020-05-10 14:29:30 -070059 &item.attrs,
60 attrs::Parser {
61 doc: Some(&mut doc),
62 derives: Some(&mut derives),
63 },
David Tolnay3e628882020-05-10 15:30:14 -070064 );
David Tolnay09462ac2020-03-20 14:58:41 -070065
66 let fields = match item.fields {
67 Fields::Named(fields) => fields,
68 Fields::Unit => return Err(Error::new_spanned(item, "unit structs are not supported")),
69 Fields::Unnamed(_) => {
70 return Err(Error::new_spanned(item, "tuple structs are not supported"))
71 }
72 };
73
74 Ok(Api::Struct(Struct {
75 doc,
76 derives,
77 struct_token: item.struct_token,
78 ident: item.ident,
79 brace_token: fields.brace_token,
80 fields: fields
81 .named
82 .into_iter()
83 .map(|field| {
84 Ok(Var {
85 ident: field.ident.unwrap(),
86 ty: parse_type(&field.ty)?,
David Tolnay7db73692019-10-20 14:51:12 -040087 })
David Tolnay09462ac2020-03-20 14:58:41 -070088 })
89 .collect::<Result<_>>()?,
90 }))
David Tolnay7db73692019-10-20 14:51:12 -040091}
92
David Tolnay3e628882020-05-10 15:30:14 -070093fn parse_enum(cx: &mut Errors, item: ItemEnum) -> Result<Api> {
Joel Galensonc03402a2020-04-23 17:31:09 -070094 let generics = &item.generics;
95 if !generics.params.is_empty() || generics.where_clause.is_some() {
96 let enum_token = item.enum_token;
97 let ident = &item.ident;
98 let where_clause = &generics.where_clause;
99 let span = quote!(#enum_token #ident #generics #where_clause);
100 return Err(Error::new_spanned(
101 span,
102 "enums with generic parameters are not allowed",
103 ));
104 }
105
David Tolnay3e628882020-05-10 15:30:14 -0700106 let doc = attrs::parse_doc(cx, &item.attrs);
Joel Galensonc03402a2020-04-23 17:31:09 -0700107
Joel Galenson88547732020-05-05 08:23:42 -0700108 let mut variants = Vec::new();
David Tolnay17e137f2020-05-08 15:55:28 -0700109 let mut discriminants = DiscriminantSet::new();
Joel Galenson88547732020-05-05 08:23:42 -0700110 for variant in item.variants {
111 match variant.fields {
Joel Galensonc03402a2020-04-23 17:31:09 -0700112 Fields::Unit => {}
113 _ => {
114 return Err(Error::new_spanned(
115 variant,
David Tolnayd7984c22020-04-30 20:09:31 -0700116 "enums with data are not supported yet",
Joel Galenson88547732020-05-05 08:23:42 -0700117 ));
Joel Galensonc03402a2020-04-23 17:31:09 -0700118 }
119 }
David Tolnay17e137f2020-05-08 15:55:28 -0700120 let expr = variant.discriminant.as_ref().map(|(_, expr)| expr);
121 let try_discriminant = match &expr {
122 Some(lit) => discriminants.insert(lit),
123 None => discriminants.insert_next(),
124 };
125 let discriminant = match try_discriminant {
126 Ok(discriminant) => discriminant,
127 Err(err) => return Err(Error::new_spanned(variant, err)),
128 };
David Tolnay2b8bf6d2020-05-10 17:37:16 -0700129 let expr = variant.discriminant.map(|(_, expr)| expr);
Joel Galenson88547732020-05-05 08:23:42 -0700130 variants.push(Variant {
131 ident: variant.ident,
David Tolnay7ae018f2020-05-05 10:11:30 -0700132 discriminant,
David Tolnay2b8bf6d2020-05-10 17:37:16 -0700133 expr,
Joel Galenson88547732020-05-05 08:23:42 -0700134 });
Joel Galensonc03402a2020-04-23 17:31:09 -0700135 }
136
David Tolnaye2e303f2020-05-10 20:52:00 -0700137 let enum_token = item.enum_token;
138 let brace_token = item.brace_token;
139
140 let repr = match discriminants.inferred_repr() {
141 Ok(repr) => repr,
142 Err(err) => {
143 let span = quote_spanned!(brace_token.span=> #enum_token {});
144 return Err(Error::new_spanned(span, err));
145 }
146 };
147
Joel Galensonc03402a2020-04-23 17:31:09 -0700148 Ok(Api::Enum(Enum {
149 doc,
David Tolnaye2e303f2020-05-10 20:52:00 -0700150 enum_token,
Joel Galensonc03402a2020-04-23 17:31:09 -0700151 ident: item.ident,
David Tolnaye2e303f2020-05-10 20:52:00 -0700152 brace_token,
David Tolnay7ae018f2020-05-05 10:11:30 -0700153 variants,
David Tolnaye2e303f2020-05-10 20:52:00 -0700154 repr,
Joel Galensonc03402a2020-04-23 17:31:09 -0700155 }))
156}
157
David Tolnay52759782020-05-03 23:59:40 -0700158fn parse_foreign_mod(cx: &mut Errors, foreign_mod: ItemForeignMod, out: &mut Vec<Api>) {
159 let lang = match parse_lang(foreign_mod.abi) {
160 Ok(lang) => lang,
161 Err(err) => return cx.push(err),
162 };
David Tolnay7db73692019-10-20 14:51:12 -0400163
Joel Galensone1e969d2020-04-21 12:50:20 -0700164 let mut items = Vec::new();
165 for foreign in &foreign_mod.items {
166 match foreign {
David Tolnay3e628882020-05-10 15:30:14 -0700167 ForeignItem::Type(foreign) => match parse_extern_type(cx, foreign, lang) {
David Tolnay295ef6b2020-05-07 16:10:22 -0700168 Ok(ety) => items.push(ety),
David Tolnay52759782020-05-03 23:59:40 -0700169 Err(err) => cx.push(err),
170 },
David Tolnay3e628882020-05-10 15:30:14 -0700171 ForeignItem::Fn(foreign) => match parse_extern_fn(cx, foreign, lang) {
David Tolnay295ef6b2020-05-07 16:10:22 -0700172 Ok(efn) => items.push(efn),
David Tolnay52759782020-05-03 23:59:40 -0700173 Err(err) => cx.push(err),
174 },
David Tolnay7db73692019-10-20 14:51:12 -0400175 ForeignItem::Macro(foreign) if foreign.mac.path.is_ident("include") => {
David Tolnay52759782020-05-03 23:59:40 -0700176 match foreign.mac.parse_body() {
177 Ok(include) => items.push(Api::Include(include)),
178 Err(err) => cx.push(err),
179 }
David Tolnay7db73692019-10-20 14:51:12 -0400180 }
David Tolnay3e628882020-05-10 15:30:14 -0700181 ForeignItem::Verbatim(tokens) => match parse_extern_verbatim(cx, tokens, lang) {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700182 Ok(api) => items.push(api),
183 Err(err) => cx.push(err),
184 },
David Tolnay52759782020-05-03 23:59:40 -0700185 _ => cx.error(foreign, "unsupported foreign item"),
David Tolnay7db73692019-10-20 14:51:12 -0400186 }
187 }
David Tolnaya1f29c42020-04-22 18:01:38 -0700188
189 let mut types = items.iter().filter_map(|item| match item {
David Tolnaye5a015a2020-05-07 21:54:26 -0700190 Api::CxxType(ty) | Api::RustType(ty) => Some(&ty.ident),
191 Api::TypeAlias(alias) => Some(&alias.ident),
David Tolnaya1f29c42020-04-22 18:01:38 -0700192 _ => None,
193 });
194 if let (Some(single_type), None) = (types.next(), types.next()) {
David Tolnaye5a015a2020-05-07 21:54:26 -0700195 let single_type = single_type.clone();
David Tolnaya1f29c42020-04-22 18:01:38 -0700196 for item in &mut items {
197 if let Api::CxxFunction(efn) | Api::RustFunction(efn) = item {
198 if let Some(receiver) = &mut efn.receiver {
199 if receiver.ty == "Self" {
200 receiver.ty = single_type.clone();
201 }
202 }
203 }
204 }
205 }
206
David Tolnay52759782020-05-03 23:59:40 -0700207 out.extend(items);
David Tolnay7db73692019-10-20 14:51:12 -0400208}
209
210fn parse_lang(abi: Abi) -> Result<Lang> {
211 let name = match &abi.name {
212 Some(name) => name,
213 None => {
214 return Err(Error::new_spanned(
215 abi,
216 "ABI name is required, extern \"C\" or extern \"Rust\"",
217 ));
218 }
219 };
220 match name.value().as_str() {
David Tolnay0b76aea2020-03-18 12:54:24 -0700221 "C" | "C++" => Ok(Lang::Cxx),
David Tolnay7db73692019-10-20 14:51:12 -0400222 "Rust" => Ok(Lang::Rust),
223 _ => Err(Error::new_spanned(abi, "unrecognized ABI")),
224 }
225}
226
David Tolnay3e628882020-05-10 15:30:14 -0700227fn parse_extern_type(cx: &mut Errors, foreign_type: &ForeignItemType, lang: Lang) -> Result<Api> {
228 let doc = attrs::parse_doc(cx, &foreign_type.attrs);
David Tolnay7db73692019-10-20 14:51:12 -0400229 let type_token = foreign_type.type_token;
230 let ident = foreign_type.ident.clone();
David Tolnay295ef6b2020-05-07 16:10:22 -0700231 let api_type = match lang {
232 Lang::Cxx => Api::CxxType,
233 Lang::Rust => Api::RustType,
234 };
235 Ok(api_type(ExternType {
David Tolnay7db73692019-10-20 14:51:12 -0400236 doc,
237 type_token,
238 ident,
David Tolnay295ef6b2020-05-07 16:10:22 -0700239 }))
David Tolnay7db73692019-10-20 14:51:12 -0400240}
241
David Tolnay3e628882020-05-10 15:30:14 -0700242fn parse_extern_fn(cx: &mut Errors, foreign_fn: &ForeignItemFn, lang: Lang) -> Result<Api> {
David Tolnay7db73692019-10-20 14:51:12 -0400243 let generics = &foreign_fn.sig.generics;
244 if !generics.params.is_empty() || generics.where_clause.is_some() {
245 return Err(Error::new_spanned(
246 foreign_fn,
247 "extern function with generic parameters is not supported yet",
248 ));
249 }
250 if let Some(variadic) = &foreign_fn.sig.variadic {
251 return Err(Error::new_spanned(
252 variadic,
253 "variadic function is not supported yet",
254 ));
255 }
256
257 let mut receiver = None;
David Tolnaye3a48152020-04-08 19:38:05 -0700258 let mut args = Punctuated::new();
259 for arg in foreign_fn.sig.inputs.pairs() {
260 let (arg, comma) = arg.into_tuple();
David Tolnay7db73692019-10-20 14:51:12 -0400261 match arg {
David Tolnay1dd11a12020-04-22 12:31:48 -0700262 FnArg::Receiver(arg) => {
David Tolnaya1f29c42020-04-22 18:01:38 -0700263 if let Some((ampersand, lifetime)) = &arg.reference {
264 receiver = Some(Receiver {
265 ampersand: *ampersand,
266 lifetime: lifetime.clone(),
267 mutability: arg.mutability,
268 var: arg.self_token,
269 ty: Token![Self](arg.self_token.span).into(),
270 shorthand: true,
271 });
272 continue;
Joel Galensone1e969d2020-04-21 12:50:20 -0700273 }
David Tolnay1dd11a12020-04-22 12:31:48 -0700274 return Err(Error::new_spanned(arg, "unsupported signature"));
David Tolnay7db73692019-10-20 14:51:12 -0400275 }
276 FnArg::Typed(arg) => {
277 let ident = match arg.pat.as_ref() {
278 Pat::Ident(pat) => pat.ident.clone(),
Joel Galensonba676072020-04-27 15:55:45 -0700279 Pat::Wild(pat) => {
280 Ident::new(&format!("_{}", args.len()), pat.underscore_token.span)
281 }
David Tolnay7db73692019-10-20 14:51:12 -0400282 _ => return Err(Error::new_spanned(arg, "unsupported signature")),
283 };
284 let ty = parse_type(&arg.ty)?;
285 if ident != "self" {
David Tolnaye3a48152020-04-08 19:38:05 -0700286 args.push_value(Var { ident, ty });
287 if let Some(comma) = comma {
288 args.push_punct(*comma);
289 }
David Tolnay7db73692019-10-20 14:51:12 -0400290 continue;
291 }
292 if let Type::Ref(reference) = ty {
293 if let Type::Ident(ident) = reference.inner {
294 receiver = Some(Receiver {
David Tolnayfb6e3862020-04-20 01:33:23 -0700295 ampersand: reference.ampersand,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700296 lifetime: reference.lifetime,
David Tolnay7db73692019-10-20 14:51:12 -0400297 mutability: reference.mutability,
David Tolnay05e11cc2020-04-20 02:13:56 -0700298 var: Token![self](ident.span()),
299 ty: ident,
David Tolnay62d360c2020-04-22 16:26:21 -0700300 shorthand: false,
David Tolnay7db73692019-10-20 14:51:12 -0400301 });
302 continue;
303 }
304 }
305 return Err(Error::new_spanned(arg, "unsupported method receiver"));
306 }
307 }
308 }
David Tolnay59b7ede2020-03-16 00:30:23 -0700309
David Tolnaye3a48152020-04-08 19:38:05 -0700310 let mut throws_tokens = None;
311 let ret = parse_return_type(&foreign_fn.sig.output, &mut throws_tokens)?;
312 let throws = throws_tokens.is_some();
David Tolnay3e628882020-05-10 15:30:14 -0700313 let doc = attrs::parse_doc(cx, &foreign_fn.attrs);
David Tolnay7db73692019-10-20 14:51:12 -0400314 let fn_token = foreign_fn.sig.fn_token;
315 let ident = foreign_fn.sig.ident.clone();
David Tolnaye3a48152020-04-08 19:38:05 -0700316 let paren_token = foreign_fn.sig.paren_token;
David Tolnay7db73692019-10-20 14:51:12 -0400317 let semi_token = foreign_fn.semi_token;
David Tolnay295ef6b2020-05-07 16:10:22 -0700318 let api_function = match lang {
319 Lang::Cxx => Api::CxxFunction,
320 Lang::Rust => Api::RustFunction,
321 };
David Tolnayd95b1192020-03-18 20:07:46 -0700322
David Tolnay295ef6b2020-05-07 16:10:22 -0700323 Ok(api_function(ExternFn {
David Tolnay6cde49f2020-03-16 12:25:45 -0700324 lang,
David Tolnay7db73692019-10-20 14:51:12 -0400325 doc,
David Tolnay7db73692019-10-20 14:51:12 -0400326 ident,
David Tolnay16448732020-03-18 12:39:36 -0700327 sig: Signature {
328 fn_token,
329 receiver,
330 args,
331 ret,
332 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700333 paren_token,
334 throws_tokens,
David Tolnay16448732020-03-18 12:39:36 -0700335 },
David Tolnay7db73692019-10-20 14:51:12 -0400336 semi_token,
David Tolnay295ef6b2020-05-07 16:10:22 -0700337 }))
David Tolnay7db73692019-10-20 14:51:12 -0400338}
339
David Tolnay3e628882020-05-10 15:30:14 -0700340fn parse_extern_verbatim(cx: &mut Errors, tokens: &TokenStream, lang: Lang) -> Result<Api> {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700341 // type Alias = crate::path::to::Type;
David Tolnay3e628882020-05-10 15:30:14 -0700342 let parse = |input: ParseStream| -> Result<TypeAlias> {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700343 let attrs = input.call(Attribute::parse_outer)?;
344 let type_token: Token![type] = match input.parse()? {
345 Some(type_token) => type_token,
346 None => {
347 let span = input.cursor().token_stream();
348 return Err(Error::new_spanned(span, "unsupported foreign item"));
349 }
350 };
351 let ident: Ident = input.parse()?;
352 let eq_token: Token![=] = input.parse()?;
353 let ty: RustType = input.parse()?;
354 let semi_token: Token![;] = input.parse()?;
David Tolnay3e628882020-05-10 15:30:14 -0700355 attrs::parse_doc(cx, &attrs);
David Tolnaye2f9ec42020-05-07 16:19:33 -0700356
357 Ok(TypeAlias {
358 type_token,
359 ident,
360 eq_token,
361 ty,
362 semi_token,
363 })
David Tolnay3e628882020-05-10 15:30:14 -0700364 };
David Tolnaye2f9ec42020-05-07 16:19:33 -0700365
366 let type_alias = parse.parse2(tokens.clone())?;
367 match lang {
368 Lang::Cxx => Ok(Api::TypeAlias(type_alias)),
369 Lang::Rust => {
370 let (type_token, semi_token) = (type_alias.type_token, type_alias.semi_token);
371 let span = quote!(#type_token #semi_token);
372 let msg = "type alias in extern \"Rust\" block is not supported";
373 Err(Error::new_spanned(span, msg))
374 }
375 }
376}
377
David Tolnay7db73692019-10-20 14:51:12 -0400378fn parse_type(ty: &RustType) -> Result<Type> {
David Tolnay59b7ede2020-03-16 00:30:23 -0700379 match ty {
David Tolnayb40b9db2020-03-18 13:50:31 -0700380 RustType::Reference(ty) => parse_type_reference(ty),
381 RustType::Path(ty) => parse_type_path(ty),
David Tolnayeebe9b72020-04-14 16:32:18 -0700382 RustType::Slice(ty) => parse_type_slice(ty),
David Tolnayc071b892020-03-18 16:59:53 -0700383 RustType::BareFn(ty) => parse_type_fn(ty),
David Tolnayb40b9db2020-03-18 13:50:31 -0700384 RustType::Tuple(ty) if ty.elems.is_empty() => Ok(Type::Void(ty.paren_token.span)),
385 _ => Err(Error::new_spanned(ty, "unsupported type")),
386 }
387}
388
389fn parse_type_reference(ty: &TypeReference) -> Result<Type> {
390 let inner = parse_type(&ty.elem)?;
391 let which = match &inner {
392 Type::Ident(ident) if ident == "str" => {
393 if ty.mutability.is_some() {
394 return Err(Error::new_spanned(ty, "unsupported type"));
395 } else {
396 Type::Str
David Tolnay7db73692019-10-20 14:51:12 -0400397 }
398 }
David Tolnayeebe9b72020-04-14 16:32:18 -0700399 Type::Slice(slice) => match &slice.inner {
400 Type::Ident(ident) if ident == U8 && ty.mutability.is_none() => Type::SliceRefU8,
401 _ => Type::Ref,
David Tolnayeb952ba2020-04-14 15:02:24 -0700402 },
David Tolnayb40b9db2020-03-18 13:50:31 -0700403 _ => Type::Ref,
404 };
405 Ok(which(Box::new(Ref {
406 ampersand: ty.and_token,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700407 lifetime: ty.lifetime.clone(),
David Tolnayb40b9db2020-03-18 13:50:31 -0700408 mutability: ty.mutability,
409 inner,
410 })))
411}
412
413fn parse_type_path(ty: &TypePath) -> Result<Type> {
414 let path = &ty.path;
415 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
416 let segment = &path.segments[0];
417 let ident = segment.ident.clone();
418 match &segment.arguments {
419 PathArguments::None => return Ok(Type::Ident(ident)),
420 PathArguments::AngleBracketed(generic) => {
421 if ident == "UniquePtr" && generic.args.len() == 1 {
422 if let GenericArgument::Type(arg) = &generic.args[0] {
423 let inner = parse_type(arg)?;
424 return Ok(Type::UniquePtr(Box::new(Ty1 {
425 name: ident,
426 langle: generic.lt_token,
427 inner,
428 rangle: generic.gt_token,
429 })));
430 }
David Tolnaye1dcdf72020-04-24 17:40:55 -0700431 } else if ident == "CxxVector" && generic.args.len() == 1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700432 if let GenericArgument::Type(arg) = &generic.args[0] {
433 let inner = parse_type(arg)?;
David Tolnay4377a9e2020-04-24 15:20:26 -0700434 return Ok(Type::CxxVector(Box::new(Ty1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700435 name: ident,
436 langle: generic.lt_token,
437 inner,
438 rangle: generic.gt_token,
439 })));
440 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700441 } else if ident == "Box" && generic.args.len() == 1 {
442 if let GenericArgument::Type(arg) = &generic.args[0] {
443 let inner = parse_type(arg)?;
444 return Ok(Type::RustBox(Box::new(Ty1 {
445 name: ident,
446 langle: generic.lt_token,
447 inner,
448 rangle: generic.gt_token,
449 })));
450 }
Myron Ahneba35cf2020-02-05 19:41:51 +0700451 } else if ident == "Vec" && generic.args.len() == 1 {
452 if let GenericArgument::Type(arg) = &generic.args[0] {
453 let inner = parse_type(arg)?;
454 return Ok(Type::RustVec(Box::new(Ty1 {
455 name: ident,
456 langle: generic.lt_token,
457 inner,
458 rangle: generic.gt_token,
459 })));
460 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700461 }
462 }
463 PathArguments::Parenthesized(_) => {}
David Tolnayfb134ed2020-03-15 23:17:48 -0700464 }
David Tolnay7db73692019-10-20 14:51:12 -0400465 }
466 Err(Error::new_spanned(ty, "unsupported type"))
467}
468
David Tolnayeebe9b72020-04-14 16:32:18 -0700469fn parse_type_slice(ty: &TypeSlice) -> Result<Type> {
470 let inner = parse_type(&ty.elem)?;
471 Ok(Type::Slice(Box::new(Slice {
472 bracket: ty.bracket_token,
473 inner,
474 })))
475}
476
David Tolnayc071b892020-03-18 16:59:53 -0700477fn parse_type_fn(ty: &TypeBareFn) -> Result<Type> {
478 if ty.lifetimes.is_some() {
479 return Err(Error::new_spanned(
480 ty,
481 "function pointer with lifetime parameters is not supported yet",
482 ));
483 }
484 if ty.variadic.is_some() {
485 return Err(Error::new_spanned(
486 ty,
487 "variadic function pointer is not supported yet",
488 ));
489 }
490 let args = ty
491 .inputs
492 .iter()
493 .enumerate()
494 .map(|(i, arg)| {
495 let ty = parse_type(&arg.ty)?;
496 let ident = match &arg.name {
497 Some(ident) => ident.0.clone(),
498 None => format_ident!("_{}", i),
499 };
500 Ok(Var { ident, ty })
501 })
502 .collect::<Result<_>>()?;
David Tolnaye3a48152020-04-08 19:38:05 -0700503 let mut throws_tokens = None;
504 let ret = parse_return_type(&ty.output, &mut throws_tokens)?;
505 let throws = throws_tokens.is_some();
David Tolnayc071b892020-03-18 16:59:53 -0700506 Ok(Type::Fn(Box::new(Signature {
507 fn_token: ty.fn_token,
508 receiver: None,
509 args,
510 ret,
511 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700512 paren_token: ty.paren_token,
513 throws_tokens,
David Tolnayc071b892020-03-18 16:59:53 -0700514 })))
515}
516
David Tolnaye3a48152020-04-08 19:38:05 -0700517fn parse_return_type(
518 ty: &ReturnType,
519 throws_tokens: &mut Option<(kw::Result, Token![<], Token![>])>,
520) -> Result<Option<Type>> {
David Tolnayc071b892020-03-18 16:59:53 -0700521 let mut ret = match ty {
522 ReturnType::Default => return Ok(None),
523 ReturnType::Type(_, ret) => ret.as_ref(),
524 };
525 if let RustType::Path(ty) = ret {
526 let path = &ty.path;
527 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
528 let segment = &path.segments[0];
529 let ident = segment.ident.clone();
530 if let PathArguments::AngleBracketed(generic) = &segment.arguments {
531 if ident == "Result" && generic.args.len() == 1 {
532 if let GenericArgument::Type(arg) = &generic.args[0] {
533 ret = arg;
David Tolnaye3a48152020-04-08 19:38:05 -0700534 *throws_tokens =
535 Some((kw::Result(ident.span()), generic.lt_token, generic.gt_token));
David Tolnayc071b892020-03-18 16:59:53 -0700536 }
537 }
538 }
539 }
540 }
541 match parse_type(ret)? {
542 Type::Void(_) => Ok(None),
543 ty => Ok(Some(ty)),
544 }
545}