blob: f84ff3288305bc3a809fe38665c6aaa29abfc95e [file] [log] [blame]
David Tolnay52759782020-05-03 23:59:40 -07001use crate::syntax::report::Errors;
David Tolnayeebe9b72020-04-14 16:32:18 -07002use crate::syntax::Atom::*;
David Tolnay7db73692019-10-20 14:51:12 -04003use crate::syntax::{
Joel Galensonc03402a2020-04-23 17:31:09 -07004 attrs, error, Api, Doc, Enum, ExternFn, ExternType, Lang, Receiver, Ref, Signature, Slice,
David Tolnaye2f9ec42020-05-07 16:19:33 -07005 Struct, Ty1, Type, TypeAlias, Var, Variant,
David Tolnay7db73692019-10-20 14:51:12 -04006};
David Tolnaye2f9ec42020-05-07 16:19:33 -07007use proc_macro2::TokenStream;
David Tolnayc071b892020-03-18 16:59:53 -07008use quote::{format_ident, quote};
Joel Galenson88547732020-05-05 08:23:42 -07009use std::collections::HashSet;
Joel Galenson8ef1bc82020-05-05 08:45:49 -070010use std::u32;
David Tolnaye2f9ec42020-05-07 16:19:33 -070011use syn::parse::{ParseStream, Parser};
David Tolnaye3a48152020-04-08 19:38:05 -070012use syn::punctuated::Punctuated;
David Tolnay7db73692019-10-20 14:51:12 -040013use syn::{
David Tolnaye2f9ec42020-05-07 16:19:33 -070014 Abi, Attribute, Error, Expr, ExprLit, Fields, FnArg, ForeignItem, ForeignItemFn,
15 ForeignItemType, GenericArgument, Ident, Item, ItemEnum, ItemForeignMod, ItemStruct, Lit, Pat,
16 PathArguments, Result, ReturnType, Token, Type as RustType, TypeBareFn, TypePath,
17 TypeReference, TypeSlice, Variant as RustVariant,
David Tolnay7db73692019-10-20 14:51:12 -040018};
19
David Tolnaye3a48152020-04-08 19:38:05 -070020pub mod kw {
21 syn::custom_keyword!(Result);
22}
23
David Tolnay52759782020-05-03 23:59:40 -070024pub fn parse_items(cx: &mut Errors, items: Vec<Item>) -> Vec<Api> {
David Tolnay7db73692019-10-20 14:51:12 -040025 let mut apis = Vec::new();
26 for item in items {
27 match item {
David Tolnay3e628882020-05-10 15:30:14 -070028 Item::Struct(item) => match parse_struct(cx, item) {
David Tolnay52759782020-05-03 23:59:40 -070029 Ok(strct) => apis.push(strct),
30 Err(err) => cx.push(err),
31 },
David Tolnay3e628882020-05-10 15:30:14 -070032 Item::Enum(item) => match parse_enum(cx, item) {
David Tolnay52759782020-05-03 23:59:40 -070033 Ok(enm) => apis.push(enm),
34 Err(err) => cx.push(err),
35 },
36 Item::ForeignMod(foreign_mod) => parse_foreign_mod(cx, foreign_mod, &mut apis),
37 Item::Use(item) => cx.error(item, error::USE_NOT_ALLOWED),
38 _ => cx.error(item, "unsupported item"),
David Tolnay7db73692019-10-20 14:51:12 -040039 }
40 }
David Tolnay52759782020-05-03 23:59:40 -070041 apis
David Tolnay7db73692019-10-20 14:51:12 -040042}
43
David Tolnay3e628882020-05-10 15:30:14 -070044fn parse_struct(cx: &mut Errors, item: ItemStruct) -> Result<Api> {
David Tolnay7db73692019-10-20 14:51:12 -040045 let generics = &item.generics;
46 if !generics.params.is_empty() || generics.where_clause.is_some() {
47 let struct_token = item.struct_token;
48 let ident = &item.ident;
49 let where_clause = &generics.where_clause;
50 let span = quote!(#struct_token #ident #generics #where_clause);
51 return Err(Error::new_spanned(
52 span,
53 "struct with generic parameters is not supported yet",
54 ));
55 }
56
57 let mut doc = Doc::new();
58 let mut derives = Vec::new();
David Tolnayb129ea72020-05-10 14:29:30 -070059 attrs::parse(
David Tolnay3e628882020-05-10 15:30:14 -070060 cx,
David Tolnayb129ea72020-05-10 14:29:30 -070061 &item.attrs,
62 attrs::Parser {
63 doc: Some(&mut doc),
64 derives: Some(&mut derives),
65 },
David Tolnay3e628882020-05-10 15:30:14 -070066 );
David Tolnay09462ac2020-03-20 14:58:41 -070067
68 let fields = match item.fields {
69 Fields::Named(fields) => fields,
70 Fields::Unit => return Err(Error::new_spanned(item, "unit structs are not supported")),
71 Fields::Unnamed(_) => {
72 return Err(Error::new_spanned(item, "tuple structs are not supported"))
73 }
74 };
75
76 Ok(Api::Struct(Struct {
77 doc,
78 derives,
79 struct_token: item.struct_token,
80 ident: item.ident,
81 brace_token: fields.brace_token,
82 fields: fields
83 .named
84 .into_iter()
85 .map(|field| {
86 Ok(Var {
87 ident: field.ident.unwrap(),
88 ty: parse_type(&field.ty)?,
David Tolnay7db73692019-10-20 14:51:12 -040089 })
David Tolnay09462ac2020-03-20 14:58:41 -070090 })
91 .collect::<Result<_>>()?,
92 }))
David Tolnay7db73692019-10-20 14:51:12 -040093}
94
David Tolnay3e628882020-05-10 15:30:14 -070095fn parse_enum(cx: &mut Errors, item: ItemEnum) -> Result<Api> {
Joel Galensonc03402a2020-04-23 17:31:09 -070096 let generics = &item.generics;
97 if !generics.params.is_empty() || generics.where_clause.is_some() {
98 let enum_token = item.enum_token;
99 let ident = &item.ident;
100 let where_clause = &generics.where_clause;
101 let span = quote!(#enum_token #ident #generics #where_clause);
102 return Err(Error::new_spanned(
103 span,
104 "enums with generic parameters are not allowed",
105 ));
106 }
107
David Tolnay3e628882020-05-10 15:30:14 -0700108 let doc = attrs::parse_doc(cx, &item.attrs);
Joel Galensonc03402a2020-04-23 17:31:09 -0700109
Joel Galenson88547732020-05-05 08:23:42 -0700110 let mut variants = Vec::new();
111 let mut discriminants = HashSet::new();
112 let mut prev_discriminant = None;
113 for variant in item.variants {
114 match variant.fields {
Joel Galensonc03402a2020-04-23 17:31:09 -0700115 Fields::Unit => {}
116 _ => {
117 return Err(Error::new_spanned(
118 variant,
David Tolnayd7984c22020-04-30 20:09:31 -0700119 "enums with data are not supported yet",
Joel Galenson88547732020-05-05 08:23:42 -0700120 ));
Joel Galensonc03402a2020-04-23 17:31:09 -0700121 }
122 }
David Tolnay4301f3c2020-05-05 10:29:52 -0700123 if variant.discriminant.is_none() && prev_discriminant == Some(u32::MAX) {
David Tolnaya3f64072020-05-05 10:24:24 -0700124 let msg = format!("discriminant overflow on value after {}", u32::MAX);
125 return Err(Error::new_spanned(variant, msg));
Joel Galenson88547732020-05-05 08:23:42 -0700126 }
127 let discriminant =
128 parse_discriminant(&variant)?.unwrap_or_else(|| prev_discriminant.map_or(0, |n| n + 1));
129 if !discriminants.insert(discriminant) {
130 let msg = format!("discriminant value `{}` already exists", discriminant);
131 return Err(Error::new_spanned(variant, msg));
132 }
133 variants.push(Variant {
134 ident: variant.ident,
David Tolnay7ae018f2020-05-05 10:11:30 -0700135 discriminant,
Joel Galenson88547732020-05-05 08:23:42 -0700136 });
137 prev_discriminant = Some(discriminant);
Joel Galensonc03402a2020-04-23 17:31:09 -0700138 }
139
140 Ok(Api::Enum(Enum {
141 doc,
142 enum_token: item.enum_token,
143 ident: item.ident,
144 brace_token: item.brace_token,
David Tolnay7ae018f2020-05-05 10:11:30 -0700145 variants,
Joel Galensonc03402a2020-04-23 17:31:09 -0700146 }))
147}
148
Joel Galenson88547732020-05-05 08:23:42 -0700149fn parse_discriminant(variant: &RustVariant) -> Result<Option<u32>> {
Joel Galensonc03402a2020-04-23 17:31:09 -0700150 match &variant.discriminant {
Joel Galenson88547732020-05-05 08:23:42 -0700151 None => Ok(None),
Joel Galensonc03402a2020-04-23 17:31:09 -0700152 Some((
153 _,
154 Expr::Lit(ExprLit {
155 lit: Lit::Int(n), ..
156 }),
David Tolnayd7984c22020-04-30 20:09:31 -0700157 )) => match n.base10_parse() {
Joel Galenson88547732020-05-05 08:23:42 -0700158 Ok(val) => Ok(Some(val)),
Joel Galensonc03402a2020-04-23 17:31:09 -0700159 Err(_) => Err(Error::new_spanned(
160 variant,
161 "cannot parse enum discriminant as an integer",
162 )),
163 },
164 _ => Err(Error::new_spanned(
165 variant,
David Tolnayd7984c22020-04-30 20:09:31 -0700166 "enums with non-integer literal discriminants are not supported yet",
Joel Galensonc03402a2020-04-23 17:31:09 -0700167 )),
168 }
169}
170
David Tolnay52759782020-05-03 23:59:40 -0700171fn parse_foreign_mod(cx: &mut Errors, foreign_mod: ItemForeignMod, out: &mut Vec<Api>) {
172 let lang = match parse_lang(foreign_mod.abi) {
173 Ok(lang) => lang,
174 Err(err) => return cx.push(err),
175 };
David Tolnay7db73692019-10-20 14:51:12 -0400176
Joel Galensone1e969d2020-04-21 12:50:20 -0700177 let mut items = Vec::new();
178 for foreign in &foreign_mod.items {
179 match foreign {
David Tolnay3e628882020-05-10 15:30:14 -0700180 ForeignItem::Type(foreign) => match parse_extern_type(cx, foreign, lang) {
David Tolnay295ef6b2020-05-07 16:10:22 -0700181 Ok(ety) => items.push(ety),
David Tolnay52759782020-05-03 23:59:40 -0700182 Err(err) => cx.push(err),
183 },
David Tolnay3e628882020-05-10 15:30:14 -0700184 ForeignItem::Fn(foreign) => match parse_extern_fn(cx, foreign, lang) {
David Tolnay295ef6b2020-05-07 16:10:22 -0700185 Ok(efn) => items.push(efn),
David Tolnay52759782020-05-03 23:59:40 -0700186 Err(err) => cx.push(err),
187 },
David Tolnay7db73692019-10-20 14:51:12 -0400188 ForeignItem::Macro(foreign) if foreign.mac.path.is_ident("include") => {
David Tolnay52759782020-05-03 23:59:40 -0700189 match foreign.mac.parse_body() {
190 Ok(include) => items.push(Api::Include(include)),
191 Err(err) => cx.push(err),
192 }
David Tolnay7db73692019-10-20 14:51:12 -0400193 }
David Tolnay3e628882020-05-10 15:30:14 -0700194 ForeignItem::Verbatim(tokens) => match parse_extern_verbatim(cx, tokens, lang) {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700195 Ok(api) => items.push(api),
196 Err(err) => cx.push(err),
197 },
David Tolnay52759782020-05-03 23:59:40 -0700198 _ => cx.error(foreign, "unsupported foreign item"),
David Tolnay7db73692019-10-20 14:51:12 -0400199 }
200 }
David Tolnaya1f29c42020-04-22 18:01:38 -0700201
202 let mut types = items.iter().filter_map(|item| match item {
David Tolnaye5a015a2020-05-07 21:54:26 -0700203 Api::CxxType(ty) | Api::RustType(ty) => Some(&ty.ident),
204 Api::TypeAlias(alias) => Some(&alias.ident),
David Tolnaya1f29c42020-04-22 18:01:38 -0700205 _ => None,
206 });
207 if let (Some(single_type), None) = (types.next(), types.next()) {
David Tolnaye5a015a2020-05-07 21:54:26 -0700208 let single_type = single_type.clone();
David Tolnaya1f29c42020-04-22 18:01:38 -0700209 for item in &mut items {
210 if let Api::CxxFunction(efn) | Api::RustFunction(efn) = item {
211 if let Some(receiver) = &mut efn.receiver {
212 if receiver.ty == "Self" {
213 receiver.ty = single_type.clone();
214 }
215 }
216 }
217 }
218 }
219
David Tolnay52759782020-05-03 23:59:40 -0700220 out.extend(items);
David Tolnay7db73692019-10-20 14:51:12 -0400221}
222
223fn parse_lang(abi: Abi) -> Result<Lang> {
224 let name = match &abi.name {
225 Some(name) => name,
226 None => {
227 return Err(Error::new_spanned(
228 abi,
229 "ABI name is required, extern \"C\" or extern \"Rust\"",
230 ));
231 }
232 };
233 match name.value().as_str() {
David Tolnay0b76aea2020-03-18 12:54:24 -0700234 "C" | "C++" => Ok(Lang::Cxx),
David Tolnay7db73692019-10-20 14:51:12 -0400235 "Rust" => Ok(Lang::Rust),
236 _ => Err(Error::new_spanned(abi, "unrecognized ABI")),
237 }
238}
239
David Tolnay3e628882020-05-10 15:30:14 -0700240fn parse_extern_type(cx: &mut Errors, foreign_type: &ForeignItemType, lang: Lang) -> Result<Api> {
241 let doc = attrs::parse_doc(cx, &foreign_type.attrs);
David Tolnay7db73692019-10-20 14:51:12 -0400242 let type_token = foreign_type.type_token;
243 let ident = foreign_type.ident.clone();
David Tolnay295ef6b2020-05-07 16:10:22 -0700244 let api_type = match lang {
245 Lang::Cxx => Api::CxxType,
246 Lang::Rust => Api::RustType,
247 };
248 Ok(api_type(ExternType {
David Tolnay7db73692019-10-20 14:51:12 -0400249 doc,
250 type_token,
251 ident,
David Tolnay295ef6b2020-05-07 16:10:22 -0700252 }))
David Tolnay7db73692019-10-20 14:51:12 -0400253}
254
David Tolnay3e628882020-05-10 15:30:14 -0700255fn parse_extern_fn(cx: &mut Errors, foreign_fn: &ForeignItemFn, lang: Lang) -> Result<Api> {
David Tolnay7db73692019-10-20 14:51:12 -0400256 let generics = &foreign_fn.sig.generics;
257 if !generics.params.is_empty() || generics.where_clause.is_some() {
258 return Err(Error::new_spanned(
259 foreign_fn,
260 "extern function with generic parameters is not supported yet",
261 ));
262 }
263 if let Some(variadic) = &foreign_fn.sig.variadic {
264 return Err(Error::new_spanned(
265 variadic,
266 "variadic function is not supported yet",
267 ));
268 }
269
270 let mut receiver = None;
David Tolnaye3a48152020-04-08 19:38:05 -0700271 let mut args = Punctuated::new();
272 for arg in foreign_fn.sig.inputs.pairs() {
273 let (arg, comma) = arg.into_tuple();
David Tolnay7db73692019-10-20 14:51:12 -0400274 match arg {
David Tolnay1dd11a12020-04-22 12:31:48 -0700275 FnArg::Receiver(arg) => {
David Tolnaya1f29c42020-04-22 18:01:38 -0700276 if let Some((ampersand, lifetime)) = &arg.reference {
277 receiver = Some(Receiver {
278 ampersand: *ampersand,
279 lifetime: lifetime.clone(),
280 mutability: arg.mutability,
281 var: arg.self_token,
282 ty: Token![Self](arg.self_token.span).into(),
283 shorthand: true,
284 });
285 continue;
Joel Galensone1e969d2020-04-21 12:50:20 -0700286 }
David Tolnay1dd11a12020-04-22 12:31:48 -0700287 return Err(Error::new_spanned(arg, "unsupported signature"));
David Tolnay7db73692019-10-20 14:51:12 -0400288 }
289 FnArg::Typed(arg) => {
290 let ident = match arg.pat.as_ref() {
291 Pat::Ident(pat) => pat.ident.clone(),
Joel Galensonba676072020-04-27 15:55:45 -0700292 Pat::Wild(pat) => {
293 Ident::new(&format!("_{}", args.len()), pat.underscore_token.span)
294 }
David Tolnay7db73692019-10-20 14:51:12 -0400295 _ => return Err(Error::new_spanned(arg, "unsupported signature")),
296 };
297 let ty = parse_type(&arg.ty)?;
298 if ident != "self" {
David Tolnaye3a48152020-04-08 19:38:05 -0700299 args.push_value(Var { ident, ty });
300 if let Some(comma) = comma {
301 args.push_punct(*comma);
302 }
David Tolnay7db73692019-10-20 14:51:12 -0400303 continue;
304 }
305 if let Type::Ref(reference) = ty {
306 if let Type::Ident(ident) = reference.inner {
307 receiver = Some(Receiver {
David Tolnayfb6e3862020-04-20 01:33:23 -0700308 ampersand: reference.ampersand,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700309 lifetime: reference.lifetime,
David Tolnay7db73692019-10-20 14:51:12 -0400310 mutability: reference.mutability,
David Tolnay05e11cc2020-04-20 02:13:56 -0700311 var: Token![self](ident.span()),
312 ty: ident,
David Tolnay62d360c2020-04-22 16:26:21 -0700313 shorthand: false,
David Tolnay7db73692019-10-20 14:51:12 -0400314 });
315 continue;
316 }
317 }
318 return Err(Error::new_spanned(arg, "unsupported method receiver"));
319 }
320 }
321 }
David Tolnay59b7ede2020-03-16 00:30:23 -0700322
David Tolnaye3a48152020-04-08 19:38:05 -0700323 let mut throws_tokens = None;
324 let ret = parse_return_type(&foreign_fn.sig.output, &mut throws_tokens)?;
325 let throws = throws_tokens.is_some();
David Tolnay3e628882020-05-10 15:30:14 -0700326 let doc = attrs::parse_doc(cx, &foreign_fn.attrs);
David Tolnay7db73692019-10-20 14:51:12 -0400327 let fn_token = foreign_fn.sig.fn_token;
328 let ident = foreign_fn.sig.ident.clone();
David Tolnaye3a48152020-04-08 19:38:05 -0700329 let paren_token = foreign_fn.sig.paren_token;
David Tolnay7db73692019-10-20 14:51:12 -0400330 let semi_token = foreign_fn.semi_token;
David Tolnay295ef6b2020-05-07 16:10:22 -0700331 let api_function = match lang {
332 Lang::Cxx => Api::CxxFunction,
333 Lang::Rust => Api::RustFunction,
334 };
David Tolnayd95b1192020-03-18 20:07:46 -0700335
David Tolnay295ef6b2020-05-07 16:10:22 -0700336 Ok(api_function(ExternFn {
David Tolnay6cde49f2020-03-16 12:25:45 -0700337 lang,
David Tolnay7db73692019-10-20 14:51:12 -0400338 doc,
David Tolnay7db73692019-10-20 14:51:12 -0400339 ident,
David Tolnay16448732020-03-18 12:39:36 -0700340 sig: Signature {
341 fn_token,
342 receiver,
343 args,
344 ret,
345 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700346 paren_token,
347 throws_tokens,
David Tolnay16448732020-03-18 12:39:36 -0700348 },
David Tolnay7db73692019-10-20 14:51:12 -0400349 semi_token,
David Tolnay295ef6b2020-05-07 16:10:22 -0700350 }))
David Tolnay7db73692019-10-20 14:51:12 -0400351}
352
David Tolnay3e628882020-05-10 15:30:14 -0700353fn parse_extern_verbatim(cx: &mut Errors, tokens: &TokenStream, lang: Lang) -> Result<Api> {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700354 // type Alias = crate::path::to::Type;
David Tolnay3e628882020-05-10 15:30:14 -0700355 let parse = |input: ParseStream| -> Result<TypeAlias> {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700356 let attrs = input.call(Attribute::parse_outer)?;
357 let type_token: Token![type] = match input.parse()? {
358 Some(type_token) => type_token,
359 None => {
360 let span = input.cursor().token_stream();
361 return Err(Error::new_spanned(span, "unsupported foreign item"));
362 }
363 };
364 let ident: Ident = input.parse()?;
365 let eq_token: Token![=] = input.parse()?;
366 let ty: RustType = input.parse()?;
367 let semi_token: Token![;] = input.parse()?;
David Tolnay3e628882020-05-10 15:30:14 -0700368 attrs::parse_doc(cx, &attrs);
David Tolnaye2f9ec42020-05-07 16:19:33 -0700369
370 Ok(TypeAlias {
371 type_token,
372 ident,
373 eq_token,
374 ty,
375 semi_token,
376 })
David Tolnay3e628882020-05-10 15:30:14 -0700377 };
David Tolnaye2f9ec42020-05-07 16:19:33 -0700378
379 let type_alias = parse.parse2(tokens.clone())?;
380 match lang {
381 Lang::Cxx => Ok(Api::TypeAlias(type_alias)),
382 Lang::Rust => {
383 let (type_token, semi_token) = (type_alias.type_token, type_alias.semi_token);
384 let span = quote!(#type_token #semi_token);
385 let msg = "type alias in extern \"Rust\" block is not supported";
386 Err(Error::new_spanned(span, msg))
387 }
388 }
389}
390
David Tolnay7db73692019-10-20 14:51:12 -0400391fn parse_type(ty: &RustType) -> Result<Type> {
David Tolnay59b7ede2020-03-16 00:30:23 -0700392 match ty {
David Tolnayb40b9db2020-03-18 13:50:31 -0700393 RustType::Reference(ty) => parse_type_reference(ty),
394 RustType::Path(ty) => parse_type_path(ty),
David Tolnayeebe9b72020-04-14 16:32:18 -0700395 RustType::Slice(ty) => parse_type_slice(ty),
David Tolnayc071b892020-03-18 16:59:53 -0700396 RustType::BareFn(ty) => parse_type_fn(ty),
David Tolnayb40b9db2020-03-18 13:50:31 -0700397 RustType::Tuple(ty) if ty.elems.is_empty() => Ok(Type::Void(ty.paren_token.span)),
398 _ => Err(Error::new_spanned(ty, "unsupported type")),
399 }
400}
401
402fn parse_type_reference(ty: &TypeReference) -> Result<Type> {
403 let inner = parse_type(&ty.elem)?;
404 let which = match &inner {
405 Type::Ident(ident) if ident == "str" => {
406 if ty.mutability.is_some() {
407 return Err(Error::new_spanned(ty, "unsupported type"));
408 } else {
409 Type::Str
David Tolnay7db73692019-10-20 14:51:12 -0400410 }
411 }
David Tolnayeebe9b72020-04-14 16:32:18 -0700412 Type::Slice(slice) => match &slice.inner {
413 Type::Ident(ident) if ident == U8 && ty.mutability.is_none() => Type::SliceRefU8,
414 _ => Type::Ref,
David Tolnayeb952ba2020-04-14 15:02:24 -0700415 },
David Tolnayb40b9db2020-03-18 13:50:31 -0700416 _ => Type::Ref,
417 };
418 Ok(which(Box::new(Ref {
419 ampersand: ty.and_token,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700420 lifetime: ty.lifetime.clone(),
David Tolnayb40b9db2020-03-18 13:50:31 -0700421 mutability: ty.mutability,
422 inner,
423 })))
424}
425
426fn parse_type_path(ty: &TypePath) -> Result<Type> {
427 let path = &ty.path;
428 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
429 let segment = &path.segments[0];
430 let ident = segment.ident.clone();
431 match &segment.arguments {
432 PathArguments::None => return Ok(Type::Ident(ident)),
433 PathArguments::AngleBracketed(generic) => {
434 if ident == "UniquePtr" && generic.args.len() == 1 {
435 if let GenericArgument::Type(arg) = &generic.args[0] {
436 let inner = parse_type(arg)?;
437 return Ok(Type::UniquePtr(Box::new(Ty1 {
438 name: ident,
439 langle: generic.lt_token,
440 inner,
441 rangle: generic.gt_token,
442 })));
443 }
David Tolnaye1dcdf72020-04-24 17:40:55 -0700444 } else if ident == "CxxVector" && generic.args.len() == 1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700445 if let GenericArgument::Type(arg) = &generic.args[0] {
446 let inner = parse_type(arg)?;
David Tolnay4377a9e2020-04-24 15:20:26 -0700447 return Ok(Type::CxxVector(Box::new(Ty1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700448 name: ident,
449 langle: generic.lt_token,
450 inner,
451 rangle: generic.gt_token,
452 })));
453 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700454 } else if ident == "Box" && generic.args.len() == 1 {
455 if let GenericArgument::Type(arg) = &generic.args[0] {
456 let inner = parse_type(arg)?;
457 return Ok(Type::RustBox(Box::new(Ty1 {
458 name: ident,
459 langle: generic.lt_token,
460 inner,
461 rangle: generic.gt_token,
462 })));
463 }
Myron Ahneba35cf2020-02-05 19:41:51 +0700464 } else if ident == "Vec" && generic.args.len() == 1 {
465 if let GenericArgument::Type(arg) = &generic.args[0] {
466 let inner = parse_type(arg)?;
467 return Ok(Type::RustVec(Box::new(Ty1 {
468 name: ident,
469 langle: generic.lt_token,
470 inner,
471 rangle: generic.gt_token,
472 })));
473 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700474 }
475 }
476 PathArguments::Parenthesized(_) => {}
David Tolnayfb134ed2020-03-15 23:17:48 -0700477 }
David Tolnay7db73692019-10-20 14:51:12 -0400478 }
479 Err(Error::new_spanned(ty, "unsupported type"))
480}
481
David Tolnayeebe9b72020-04-14 16:32:18 -0700482fn parse_type_slice(ty: &TypeSlice) -> Result<Type> {
483 let inner = parse_type(&ty.elem)?;
484 Ok(Type::Slice(Box::new(Slice {
485 bracket: ty.bracket_token,
486 inner,
487 })))
488}
489
David Tolnayc071b892020-03-18 16:59:53 -0700490fn parse_type_fn(ty: &TypeBareFn) -> Result<Type> {
491 if ty.lifetimes.is_some() {
492 return Err(Error::new_spanned(
493 ty,
494 "function pointer with lifetime parameters is not supported yet",
495 ));
496 }
497 if ty.variadic.is_some() {
498 return Err(Error::new_spanned(
499 ty,
500 "variadic function pointer is not supported yet",
501 ));
502 }
503 let args = ty
504 .inputs
505 .iter()
506 .enumerate()
507 .map(|(i, arg)| {
508 let ty = parse_type(&arg.ty)?;
509 let ident = match &arg.name {
510 Some(ident) => ident.0.clone(),
511 None => format_ident!("_{}", i),
512 };
513 Ok(Var { ident, ty })
514 })
515 .collect::<Result<_>>()?;
David Tolnaye3a48152020-04-08 19:38:05 -0700516 let mut throws_tokens = None;
517 let ret = parse_return_type(&ty.output, &mut throws_tokens)?;
518 let throws = throws_tokens.is_some();
David Tolnayc071b892020-03-18 16:59:53 -0700519 Ok(Type::Fn(Box::new(Signature {
520 fn_token: ty.fn_token,
521 receiver: None,
522 args,
523 ret,
524 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700525 paren_token: ty.paren_token,
526 throws_tokens,
David Tolnayc071b892020-03-18 16:59:53 -0700527 })))
528}
529
David Tolnaye3a48152020-04-08 19:38:05 -0700530fn parse_return_type(
531 ty: &ReturnType,
532 throws_tokens: &mut Option<(kw::Result, Token![<], Token![>])>,
533) -> Result<Option<Type>> {
David Tolnayc071b892020-03-18 16:59:53 -0700534 let mut ret = match ty {
535 ReturnType::Default => return Ok(None),
536 ReturnType::Type(_, ret) => ret.as_ref(),
537 };
538 if let RustType::Path(ty) = ret {
539 let path = &ty.path;
540 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
541 let segment = &path.segments[0];
542 let ident = segment.ident.clone();
543 if let PathArguments::AngleBracketed(generic) = &segment.arguments {
544 if ident == "Result" && generic.args.len() == 1 {
545 if let GenericArgument::Type(arg) = &generic.args[0] {
546 ret = arg;
David Tolnaye3a48152020-04-08 19:38:05 -0700547 *throws_tokens =
548 Some((kw::Result(ident.span()), generic.lt_token, generic.gt_token));
David Tolnayc071b892020-03-18 16:59:53 -0700549 }
550 }
551 }
552 }
553 }
554 match parse_type(ret)? {
555 Type::Void(_) => Ok(None),
556 ty => Ok(Some(ty)),
557 }
558}