blob: b41f3df632f64d2fce8712fee8a934f81f267549 [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 Tolnay52759782020-05-03 23:59:40 -070028 Item::Struct(item) => match parse_struct(item) {
29 Ok(strct) => apis.push(strct),
30 Err(err) => cx.push(err),
31 },
32 Item::Enum(item) => match parse_enum(item) {
33 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
44fn parse_struct(item: ItemStruct) -> Result<Api> {
45 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();
59 attrs::parse(&item.attrs, &mut doc, Some(&mut derives))?;
David Tolnay09462ac2020-03-20 14:58:41 -070060
61 let fields = match item.fields {
62 Fields::Named(fields) => fields,
63 Fields::Unit => return Err(Error::new_spanned(item, "unit structs are not supported")),
64 Fields::Unnamed(_) => {
65 return Err(Error::new_spanned(item, "tuple structs are not supported"))
66 }
67 };
68
69 Ok(Api::Struct(Struct {
70 doc,
71 derives,
72 struct_token: item.struct_token,
73 ident: item.ident,
74 brace_token: fields.brace_token,
75 fields: fields
76 .named
77 .into_iter()
78 .map(|field| {
79 Ok(Var {
80 ident: field.ident.unwrap(),
81 ty: parse_type(&field.ty)?,
David Tolnay7db73692019-10-20 14:51:12 -040082 })
David Tolnay09462ac2020-03-20 14:58:41 -070083 })
84 .collect::<Result<_>>()?,
85 }))
David Tolnay7db73692019-10-20 14:51:12 -040086}
87
Joel Galensonc03402a2020-04-23 17:31:09 -070088fn parse_enum(item: ItemEnum) -> Result<Api> {
89 let generics = &item.generics;
90 if !generics.params.is_empty() || generics.where_clause.is_some() {
91 let enum_token = item.enum_token;
92 let ident = &item.ident;
93 let where_clause = &generics.where_clause;
94 let span = quote!(#enum_token #ident #generics #where_clause);
95 return Err(Error::new_spanned(
96 span,
97 "enums with generic parameters are not allowed",
98 ));
99 }
100
David Tolnayd7984c22020-04-30 20:09:31 -0700101 let doc = attrs::parse_doc(&item.attrs)?;
Joel Galensonc03402a2020-04-23 17:31:09 -0700102
Joel Galenson88547732020-05-05 08:23:42 -0700103 let mut variants = Vec::new();
104 let mut discriminants = HashSet::new();
105 let mut prev_discriminant = None;
106 for variant in item.variants {
107 match variant.fields {
Joel Galensonc03402a2020-04-23 17:31:09 -0700108 Fields::Unit => {}
109 _ => {
110 return Err(Error::new_spanned(
111 variant,
David Tolnayd7984c22020-04-30 20:09:31 -0700112 "enums with data are not supported yet",
Joel Galenson88547732020-05-05 08:23:42 -0700113 ));
Joel Galensonc03402a2020-04-23 17:31:09 -0700114 }
115 }
David Tolnay4301f3c2020-05-05 10:29:52 -0700116 if variant.discriminant.is_none() && prev_discriminant == Some(u32::MAX) {
David Tolnaya3f64072020-05-05 10:24:24 -0700117 let msg = format!("discriminant overflow on value after {}", u32::MAX);
118 return Err(Error::new_spanned(variant, msg));
Joel Galenson88547732020-05-05 08:23:42 -0700119 }
120 let discriminant =
121 parse_discriminant(&variant)?.unwrap_or_else(|| prev_discriminant.map_or(0, |n| n + 1));
122 if !discriminants.insert(discriminant) {
123 let msg = format!("discriminant value `{}` already exists", discriminant);
124 return Err(Error::new_spanned(variant, msg));
125 }
126 variants.push(Variant {
127 ident: variant.ident,
David Tolnay7ae018f2020-05-05 10:11:30 -0700128 discriminant,
Joel Galenson88547732020-05-05 08:23:42 -0700129 });
130 prev_discriminant = Some(discriminant);
Joel Galensonc03402a2020-04-23 17:31:09 -0700131 }
132
133 Ok(Api::Enum(Enum {
134 doc,
135 enum_token: item.enum_token,
136 ident: item.ident,
137 brace_token: item.brace_token,
David Tolnay7ae018f2020-05-05 10:11:30 -0700138 variants,
Joel Galensonc03402a2020-04-23 17:31:09 -0700139 }))
140}
141
Joel Galenson88547732020-05-05 08:23:42 -0700142fn parse_discriminant(variant: &RustVariant) -> Result<Option<u32>> {
Joel Galensonc03402a2020-04-23 17:31:09 -0700143 match &variant.discriminant {
Joel Galenson88547732020-05-05 08:23:42 -0700144 None => Ok(None),
Joel Galensonc03402a2020-04-23 17:31:09 -0700145 Some((
146 _,
147 Expr::Lit(ExprLit {
148 lit: Lit::Int(n), ..
149 }),
David Tolnayd7984c22020-04-30 20:09:31 -0700150 )) => match n.base10_parse() {
Joel Galenson88547732020-05-05 08:23:42 -0700151 Ok(val) => Ok(Some(val)),
Joel Galensonc03402a2020-04-23 17:31:09 -0700152 Err(_) => Err(Error::new_spanned(
153 variant,
154 "cannot parse enum discriminant as an integer",
155 )),
156 },
157 _ => Err(Error::new_spanned(
158 variant,
David Tolnayd7984c22020-04-30 20:09:31 -0700159 "enums with non-integer literal discriminants are not supported yet",
Joel Galensonc03402a2020-04-23 17:31:09 -0700160 )),
161 }
162}
163
David Tolnay52759782020-05-03 23:59:40 -0700164fn parse_foreign_mod(cx: &mut Errors, foreign_mod: ItemForeignMod, out: &mut Vec<Api>) {
165 let lang = match parse_lang(foreign_mod.abi) {
166 Ok(lang) => lang,
167 Err(err) => return cx.push(err),
168 };
David Tolnay7db73692019-10-20 14:51:12 -0400169
Joel Galensone1e969d2020-04-21 12:50:20 -0700170 let mut items = Vec::new();
171 for foreign in &foreign_mod.items {
172 match foreign {
David Tolnay295ef6b2020-05-07 16:10:22 -0700173 ForeignItem::Type(foreign) => match parse_extern_type(foreign, lang) {
174 Ok(ety) => items.push(ety),
David Tolnay52759782020-05-03 23:59:40 -0700175 Err(err) => cx.push(err),
176 },
177 ForeignItem::Fn(foreign) => match parse_extern_fn(foreign, lang) {
David Tolnay295ef6b2020-05-07 16:10:22 -0700178 Ok(efn) => items.push(efn),
David Tolnay52759782020-05-03 23:59:40 -0700179 Err(err) => cx.push(err),
180 },
David Tolnay7db73692019-10-20 14:51:12 -0400181 ForeignItem::Macro(foreign) if foreign.mac.path.is_ident("include") => {
David Tolnay52759782020-05-03 23:59:40 -0700182 match foreign.mac.parse_body() {
183 Ok(include) => items.push(Api::Include(include)),
184 Err(err) => cx.push(err),
185 }
David Tolnay7db73692019-10-20 14:51:12 -0400186 }
David Tolnaye2f9ec42020-05-07 16:19:33 -0700187 ForeignItem::Verbatim(tokens) => match parse_extern_verbatim(tokens, lang) {
188 Ok(api) => items.push(api),
189 Err(err) => cx.push(err),
190 },
David Tolnay52759782020-05-03 23:59:40 -0700191 _ => cx.error(foreign, "unsupported foreign item"),
David Tolnay7db73692019-10-20 14:51:12 -0400192 }
193 }
David Tolnaya1f29c42020-04-22 18:01:38 -0700194
195 let mut types = items.iter().filter_map(|item| match item {
196 Api::CxxType(ty) | Api::RustType(ty) => Some(ty),
197 _ => None,
198 });
199 if let (Some(single_type), None) = (types.next(), types.next()) {
200 let single_type = single_type.ident.clone();
201 for item in &mut items {
202 if let Api::CxxFunction(efn) | Api::RustFunction(efn) = item {
203 if let Some(receiver) = &mut efn.receiver {
204 if receiver.ty == "Self" {
205 receiver.ty = single_type.clone();
206 }
207 }
208 }
209 }
210 }
211
David Tolnay52759782020-05-03 23:59:40 -0700212 out.extend(items);
David Tolnay7db73692019-10-20 14:51:12 -0400213}
214
215fn parse_lang(abi: Abi) -> Result<Lang> {
216 let name = match &abi.name {
217 Some(name) => name,
218 None => {
219 return Err(Error::new_spanned(
220 abi,
221 "ABI name is required, extern \"C\" or extern \"Rust\"",
222 ));
223 }
224 };
225 match name.value().as_str() {
David Tolnay0b76aea2020-03-18 12:54:24 -0700226 "C" | "C++" => Ok(Lang::Cxx),
David Tolnay7db73692019-10-20 14:51:12 -0400227 "Rust" => Ok(Lang::Rust),
228 _ => Err(Error::new_spanned(abi, "unrecognized ABI")),
229 }
230}
231
David Tolnay295ef6b2020-05-07 16:10:22 -0700232fn parse_extern_type(foreign_type: &ForeignItemType, lang: Lang) -> Result<Api> {
David Tolnay7db73692019-10-20 14:51:12 -0400233 let doc = attrs::parse_doc(&foreign_type.attrs)?;
234 let type_token = foreign_type.type_token;
235 let ident = foreign_type.ident.clone();
David Tolnay295ef6b2020-05-07 16:10:22 -0700236 let api_type = match lang {
237 Lang::Cxx => Api::CxxType,
238 Lang::Rust => Api::RustType,
239 };
240 Ok(api_type(ExternType {
David Tolnay7db73692019-10-20 14:51:12 -0400241 doc,
242 type_token,
243 ident,
David Tolnay295ef6b2020-05-07 16:10:22 -0700244 }))
David Tolnay7db73692019-10-20 14:51:12 -0400245}
246
David Tolnay295ef6b2020-05-07 16:10:22 -0700247fn parse_extern_fn(foreign_fn: &ForeignItemFn, lang: Lang) -> Result<Api> {
David Tolnay7db73692019-10-20 14:51:12 -0400248 let generics = &foreign_fn.sig.generics;
249 if !generics.params.is_empty() || generics.where_clause.is_some() {
250 return Err(Error::new_spanned(
251 foreign_fn,
252 "extern function with generic parameters is not supported yet",
253 ));
254 }
255 if let Some(variadic) = &foreign_fn.sig.variadic {
256 return Err(Error::new_spanned(
257 variadic,
258 "variadic function is not supported yet",
259 ));
260 }
261
262 let mut receiver = None;
David Tolnaye3a48152020-04-08 19:38:05 -0700263 let mut args = Punctuated::new();
264 for arg in foreign_fn.sig.inputs.pairs() {
265 let (arg, comma) = arg.into_tuple();
David Tolnay7db73692019-10-20 14:51:12 -0400266 match arg {
David Tolnay1dd11a12020-04-22 12:31:48 -0700267 FnArg::Receiver(arg) => {
David Tolnaya1f29c42020-04-22 18:01:38 -0700268 if let Some((ampersand, lifetime)) = &arg.reference {
269 receiver = Some(Receiver {
270 ampersand: *ampersand,
271 lifetime: lifetime.clone(),
272 mutability: arg.mutability,
273 var: arg.self_token,
274 ty: Token![Self](arg.self_token.span).into(),
275 shorthand: true,
276 });
277 continue;
Joel Galensone1e969d2020-04-21 12:50:20 -0700278 }
David Tolnay1dd11a12020-04-22 12:31:48 -0700279 return Err(Error::new_spanned(arg, "unsupported signature"));
David Tolnay7db73692019-10-20 14:51:12 -0400280 }
281 FnArg::Typed(arg) => {
282 let ident = match arg.pat.as_ref() {
283 Pat::Ident(pat) => pat.ident.clone(),
Joel Galensonba676072020-04-27 15:55:45 -0700284 Pat::Wild(pat) => {
285 Ident::new(&format!("_{}", args.len()), pat.underscore_token.span)
286 }
David Tolnay7db73692019-10-20 14:51:12 -0400287 _ => return Err(Error::new_spanned(arg, "unsupported signature")),
288 };
289 let ty = parse_type(&arg.ty)?;
290 if ident != "self" {
David Tolnaye3a48152020-04-08 19:38:05 -0700291 args.push_value(Var { ident, ty });
292 if let Some(comma) = comma {
293 args.push_punct(*comma);
294 }
David Tolnay7db73692019-10-20 14:51:12 -0400295 continue;
296 }
297 if let Type::Ref(reference) = ty {
298 if let Type::Ident(ident) = reference.inner {
299 receiver = Some(Receiver {
David Tolnayfb6e3862020-04-20 01:33:23 -0700300 ampersand: reference.ampersand,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700301 lifetime: reference.lifetime,
David Tolnay7db73692019-10-20 14:51:12 -0400302 mutability: reference.mutability,
David Tolnay05e11cc2020-04-20 02:13:56 -0700303 var: Token![self](ident.span()),
304 ty: ident,
David Tolnay62d360c2020-04-22 16:26:21 -0700305 shorthand: false,
David Tolnay7db73692019-10-20 14:51:12 -0400306 });
307 continue;
308 }
309 }
310 return Err(Error::new_spanned(arg, "unsupported method receiver"));
311 }
312 }
313 }
David Tolnay59b7ede2020-03-16 00:30:23 -0700314
David Tolnaye3a48152020-04-08 19:38:05 -0700315 let mut throws_tokens = None;
316 let ret = parse_return_type(&foreign_fn.sig.output, &mut throws_tokens)?;
317 let throws = throws_tokens.is_some();
David Tolnay7db73692019-10-20 14:51:12 -0400318 let doc = attrs::parse_doc(&foreign_fn.attrs)?;
319 let fn_token = foreign_fn.sig.fn_token;
320 let ident = foreign_fn.sig.ident.clone();
David Tolnaye3a48152020-04-08 19:38:05 -0700321 let paren_token = foreign_fn.sig.paren_token;
David Tolnay7db73692019-10-20 14:51:12 -0400322 let semi_token = foreign_fn.semi_token;
David Tolnay295ef6b2020-05-07 16:10:22 -0700323 let api_function = match lang {
324 Lang::Cxx => Api::CxxFunction,
325 Lang::Rust => Api::RustFunction,
326 };
David Tolnayd95b1192020-03-18 20:07:46 -0700327
David Tolnay295ef6b2020-05-07 16:10:22 -0700328 Ok(api_function(ExternFn {
David Tolnay6cde49f2020-03-16 12:25:45 -0700329 lang,
David Tolnay7db73692019-10-20 14:51:12 -0400330 doc,
David Tolnay7db73692019-10-20 14:51:12 -0400331 ident,
David Tolnay16448732020-03-18 12:39:36 -0700332 sig: Signature {
333 fn_token,
334 receiver,
335 args,
336 ret,
337 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700338 paren_token,
339 throws_tokens,
David Tolnay16448732020-03-18 12:39:36 -0700340 },
David Tolnay7db73692019-10-20 14:51:12 -0400341 semi_token,
David Tolnay295ef6b2020-05-07 16:10:22 -0700342 }))
David Tolnay7db73692019-10-20 14:51:12 -0400343}
344
David Tolnaye2f9ec42020-05-07 16:19:33 -0700345fn parse_extern_verbatim(tokens: &TokenStream, lang: Lang) -> Result<Api> {
346 // type Alias = crate::path::to::Type;
347 fn parse(input: ParseStream) -> Result<TypeAlias> {
348 let attrs = input.call(Attribute::parse_outer)?;
349 let type_token: Token![type] = match input.parse()? {
350 Some(type_token) => type_token,
351 None => {
352 let span = input.cursor().token_stream();
353 return Err(Error::new_spanned(span, "unsupported foreign item"));
354 }
355 };
356 let ident: Ident = input.parse()?;
357 let eq_token: Token![=] = input.parse()?;
358 let ty: RustType = input.parse()?;
359 let semi_token: Token![;] = input.parse()?;
360 attrs::parse_doc(&attrs)?;
361
362 Ok(TypeAlias {
363 type_token,
364 ident,
365 eq_token,
366 ty,
367 semi_token,
368 })
369 }
370
371 let type_alias = parse.parse2(tokens.clone())?;
372 match lang {
373 Lang::Cxx => Ok(Api::TypeAlias(type_alias)),
374 Lang::Rust => {
375 let (type_token, semi_token) = (type_alias.type_token, type_alias.semi_token);
376 let span = quote!(#type_token #semi_token);
377 let msg = "type alias in extern \"Rust\" block is not supported";
378 Err(Error::new_spanned(span, msg))
379 }
380 }
381}
382
David Tolnay7db73692019-10-20 14:51:12 -0400383fn parse_type(ty: &RustType) -> Result<Type> {
David Tolnay59b7ede2020-03-16 00:30:23 -0700384 match ty {
David Tolnayb40b9db2020-03-18 13:50:31 -0700385 RustType::Reference(ty) => parse_type_reference(ty),
386 RustType::Path(ty) => parse_type_path(ty),
David Tolnayeebe9b72020-04-14 16:32:18 -0700387 RustType::Slice(ty) => parse_type_slice(ty),
David Tolnayc071b892020-03-18 16:59:53 -0700388 RustType::BareFn(ty) => parse_type_fn(ty),
David Tolnayb40b9db2020-03-18 13:50:31 -0700389 RustType::Tuple(ty) if ty.elems.is_empty() => Ok(Type::Void(ty.paren_token.span)),
390 _ => Err(Error::new_spanned(ty, "unsupported type")),
391 }
392}
393
394fn parse_type_reference(ty: &TypeReference) -> Result<Type> {
395 let inner = parse_type(&ty.elem)?;
396 let which = match &inner {
397 Type::Ident(ident) if ident == "str" => {
398 if ty.mutability.is_some() {
399 return Err(Error::new_spanned(ty, "unsupported type"));
400 } else {
401 Type::Str
David Tolnay7db73692019-10-20 14:51:12 -0400402 }
403 }
David Tolnayeebe9b72020-04-14 16:32:18 -0700404 Type::Slice(slice) => match &slice.inner {
405 Type::Ident(ident) if ident == U8 && ty.mutability.is_none() => Type::SliceRefU8,
406 _ => Type::Ref,
David Tolnayeb952ba2020-04-14 15:02:24 -0700407 },
David Tolnayb40b9db2020-03-18 13:50:31 -0700408 _ => Type::Ref,
409 };
410 Ok(which(Box::new(Ref {
411 ampersand: ty.and_token,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700412 lifetime: ty.lifetime.clone(),
David Tolnayb40b9db2020-03-18 13:50:31 -0700413 mutability: ty.mutability,
414 inner,
415 })))
416}
417
418fn parse_type_path(ty: &TypePath) -> Result<Type> {
419 let path = &ty.path;
420 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
421 let segment = &path.segments[0];
422 let ident = segment.ident.clone();
423 match &segment.arguments {
424 PathArguments::None => return Ok(Type::Ident(ident)),
425 PathArguments::AngleBracketed(generic) => {
426 if ident == "UniquePtr" && generic.args.len() == 1 {
427 if let GenericArgument::Type(arg) = &generic.args[0] {
428 let inner = parse_type(arg)?;
429 return Ok(Type::UniquePtr(Box::new(Ty1 {
430 name: ident,
431 langle: generic.lt_token,
432 inner,
433 rangle: generic.gt_token,
434 })));
435 }
David Tolnaye1dcdf72020-04-24 17:40:55 -0700436 } else if ident == "CxxVector" && generic.args.len() == 1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700437 if let GenericArgument::Type(arg) = &generic.args[0] {
438 let inner = parse_type(arg)?;
David Tolnay4377a9e2020-04-24 15:20:26 -0700439 return Ok(Type::CxxVector(Box::new(Ty1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700440 name: ident,
441 langle: generic.lt_token,
442 inner,
443 rangle: generic.gt_token,
444 })));
445 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700446 } else if ident == "Box" && generic.args.len() == 1 {
447 if let GenericArgument::Type(arg) = &generic.args[0] {
448 let inner = parse_type(arg)?;
449 return Ok(Type::RustBox(Box::new(Ty1 {
450 name: ident,
451 langle: generic.lt_token,
452 inner,
453 rangle: generic.gt_token,
454 })));
455 }
Myron Ahneba35cf2020-02-05 19:41:51 +0700456 } else if ident == "Vec" && generic.args.len() == 1 {
457 if let GenericArgument::Type(arg) = &generic.args[0] {
458 let inner = parse_type(arg)?;
459 return Ok(Type::RustVec(Box::new(Ty1 {
460 name: ident,
461 langle: generic.lt_token,
462 inner,
463 rangle: generic.gt_token,
464 })));
465 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700466 }
467 }
468 PathArguments::Parenthesized(_) => {}
David Tolnayfb134ed2020-03-15 23:17:48 -0700469 }
David Tolnay7db73692019-10-20 14:51:12 -0400470 }
471 Err(Error::new_spanned(ty, "unsupported type"))
472}
473
David Tolnayeebe9b72020-04-14 16:32:18 -0700474fn parse_type_slice(ty: &TypeSlice) -> Result<Type> {
475 let inner = parse_type(&ty.elem)?;
476 Ok(Type::Slice(Box::new(Slice {
477 bracket: ty.bracket_token,
478 inner,
479 })))
480}
481
David Tolnayc071b892020-03-18 16:59:53 -0700482fn parse_type_fn(ty: &TypeBareFn) -> Result<Type> {
483 if ty.lifetimes.is_some() {
484 return Err(Error::new_spanned(
485 ty,
486 "function pointer with lifetime parameters is not supported yet",
487 ));
488 }
489 if ty.variadic.is_some() {
490 return Err(Error::new_spanned(
491 ty,
492 "variadic function pointer is not supported yet",
493 ));
494 }
495 let args = ty
496 .inputs
497 .iter()
498 .enumerate()
499 .map(|(i, arg)| {
500 let ty = parse_type(&arg.ty)?;
501 let ident = match &arg.name {
502 Some(ident) => ident.0.clone(),
503 None => format_ident!("_{}", i),
504 };
505 Ok(Var { ident, ty })
506 })
507 .collect::<Result<_>>()?;
David Tolnaye3a48152020-04-08 19:38:05 -0700508 let mut throws_tokens = None;
509 let ret = parse_return_type(&ty.output, &mut throws_tokens)?;
510 let throws = throws_tokens.is_some();
David Tolnayc071b892020-03-18 16:59:53 -0700511 Ok(Type::Fn(Box::new(Signature {
512 fn_token: ty.fn_token,
513 receiver: None,
514 args,
515 ret,
516 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700517 paren_token: ty.paren_token,
518 throws_tokens,
David Tolnayc071b892020-03-18 16:59:53 -0700519 })))
520}
521
David Tolnaye3a48152020-04-08 19:38:05 -0700522fn parse_return_type(
523 ty: &ReturnType,
524 throws_tokens: &mut Option<(kw::Result, Token![<], Token![>])>,
525) -> Result<Option<Type>> {
David Tolnayc071b892020-03-18 16:59:53 -0700526 let mut ret = match ty {
527 ReturnType::Default => return Ok(None),
528 ReturnType::Type(_, ret) => ret.as_ref(),
529 };
530 if let RustType::Path(ty) = ret {
531 let path = &ty.path;
532 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
533 let segment = &path.segments[0];
534 let ident = segment.ident.clone();
535 if let PathArguments::AngleBracketed(generic) = &segment.arguments {
536 if ident == "Result" && generic.args.len() == 1 {
537 if let GenericArgument::Type(arg) = &generic.args[0] {
538 ret = arg;
David Tolnaye3a48152020-04-08 19:38:05 -0700539 *throws_tokens =
540 Some((kw::Result(ident.span()), generic.lt_token, generic.gt_token));
David Tolnayc071b892020-03-18 16:59:53 -0700541 }
542 }
543 }
544 }
545 }
546 match parse_type(ret)? {
547 Type::Void(_) => Ok(None),
548 ty => Ok(Some(ty)),
549 }
550}