blob: eff14c02ec6504b039bcfca6b4c4df7fb4c71f60 [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 Tolnayc071b892020-03-18 16:59:53 -07009use quote::{format_ident, quote};
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 };
Joel Galenson88547732020-05-05 08:23:42 -0700129 variants.push(Variant {
130 ident: variant.ident,
David Tolnay7ae018f2020-05-05 10:11:30 -0700131 discriminant,
Joel Galenson88547732020-05-05 08:23:42 -0700132 });
Joel Galensonc03402a2020-04-23 17:31:09 -0700133 }
134
135 Ok(Api::Enum(Enum {
136 doc,
137 enum_token: item.enum_token,
138 ident: item.ident,
139 brace_token: item.brace_token,
David Tolnay7ae018f2020-05-05 10:11:30 -0700140 variants,
Joel Galensonc03402a2020-04-23 17:31:09 -0700141 }))
142}
143
David Tolnay52759782020-05-03 23:59:40 -0700144fn parse_foreign_mod(cx: &mut Errors, foreign_mod: ItemForeignMod, out: &mut Vec<Api>) {
145 let lang = match parse_lang(foreign_mod.abi) {
146 Ok(lang) => lang,
147 Err(err) => return cx.push(err),
148 };
David Tolnay7db73692019-10-20 14:51:12 -0400149
Joel Galensone1e969d2020-04-21 12:50:20 -0700150 let mut items = Vec::new();
151 for foreign in &foreign_mod.items {
152 match foreign {
David Tolnay3e628882020-05-10 15:30:14 -0700153 ForeignItem::Type(foreign) => match parse_extern_type(cx, foreign, lang) {
David Tolnay295ef6b2020-05-07 16:10:22 -0700154 Ok(ety) => items.push(ety),
David Tolnay52759782020-05-03 23:59:40 -0700155 Err(err) => cx.push(err),
156 },
David Tolnay3e628882020-05-10 15:30:14 -0700157 ForeignItem::Fn(foreign) => match parse_extern_fn(cx, foreign, lang) {
David Tolnay295ef6b2020-05-07 16:10:22 -0700158 Ok(efn) => items.push(efn),
David Tolnay52759782020-05-03 23:59:40 -0700159 Err(err) => cx.push(err),
160 },
David Tolnay7db73692019-10-20 14:51:12 -0400161 ForeignItem::Macro(foreign) if foreign.mac.path.is_ident("include") => {
David Tolnay52759782020-05-03 23:59:40 -0700162 match foreign.mac.parse_body() {
163 Ok(include) => items.push(Api::Include(include)),
164 Err(err) => cx.push(err),
165 }
David Tolnay7db73692019-10-20 14:51:12 -0400166 }
David Tolnay3e628882020-05-10 15:30:14 -0700167 ForeignItem::Verbatim(tokens) => match parse_extern_verbatim(cx, tokens, lang) {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700168 Ok(api) => items.push(api),
169 Err(err) => cx.push(err),
170 },
David Tolnay52759782020-05-03 23:59:40 -0700171 _ => cx.error(foreign, "unsupported foreign item"),
David Tolnay7db73692019-10-20 14:51:12 -0400172 }
173 }
David Tolnaya1f29c42020-04-22 18:01:38 -0700174
175 let mut types = items.iter().filter_map(|item| match item {
David Tolnaye5a015a2020-05-07 21:54:26 -0700176 Api::CxxType(ty) | Api::RustType(ty) => Some(&ty.ident),
177 Api::TypeAlias(alias) => Some(&alias.ident),
David Tolnaya1f29c42020-04-22 18:01:38 -0700178 _ => None,
179 });
180 if let (Some(single_type), None) = (types.next(), types.next()) {
David Tolnaye5a015a2020-05-07 21:54:26 -0700181 let single_type = single_type.clone();
David Tolnaya1f29c42020-04-22 18:01:38 -0700182 for item in &mut items {
183 if let Api::CxxFunction(efn) | Api::RustFunction(efn) = item {
184 if let Some(receiver) = &mut efn.receiver {
185 if receiver.ty == "Self" {
186 receiver.ty = single_type.clone();
187 }
188 }
189 }
190 }
191 }
192
David Tolnay52759782020-05-03 23:59:40 -0700193 out.extend(items);
David Tolnay7db73692019-10-20 14:51:12 -0400194}
195
196fn parse_lang(abi: Abi) -> Result<Lang> {
197 let name = match &abi.name {
198 Some(name) => name,
199 None => {
200 return Err(Error::new_spanned(
201 abi,
202 "ABI name is required, extern \"C\" or extern \"Rust\"",
203 ));
204 }
205 };
206 match name.value().as_str() {
David Tolnay0b76aea2020-03-18 12:54:24 -0700207 "C" | "C++" => Ok(Lang::Cxx),
David Tolnay7db73692019-10-20 14:51:12 -0400208 "Rust" => Ok(Lang::Rust),
209 _ => Err(Error::new_spanned(abi, "unrecognized ABI")),
210 }
211}
212
David Tolnay3e628882020-05-10 15:30:14 -0700213fn parse_extern_type(cx: &mut Errors, foreign_type: &ForeignItemType, lang: Lang) -> Result<Api> {
214 let doc = attrs::parse_doc(cx, &foreign_type.attrs);
David Tolnay7db73692019-10-20 14:51:12 -0400215 let type_token = foreign_type.type_token;
216 let ident = foreign_type.ident.clone();
David Tolnay295ef6b2020-05-07 16:10:22 -0700217 let api_type = match lang {
218 Lang::Cxx => Api::CxxType,
219 Lang::Rust => Api::RustType,
220 };
221 Ok(api_type(ExternType {
David Tolnay7db73692019-10-20 14:51:12 -0400222 doc,
223 type_token,
224 ident,
David Tolnay295ef6b2020-05-07 16:10:22 -0700225 }))
David Tolnay7db73692019-10-20 14:51:12 -0400226}
227
David Tolnay3e628882020-05-10 15:30:14 -0700228fn parse_extern_fn(cx: &mut Errors, foreign_fn: &ForeignItemFn, lang: Lang) -> Result<Api> {
David Tolnay7db73692019-10-20 14:51:12 -0400229 let generics = &foreign_fn.sig.generics;
230 if !generics.params.is_empty() || generics.where_clause.is_some() {
231 return Err(Error::new_spanned(
232 foreign_fn,
233 "extern function with generic parameters is not supported yet",
234 ));
235 }
236 if let Some(variadic) = &foreign_fn.sig.variadic {
237 return Err(Error::new_spanned(
238 variadic,
239 "variadic function is not supported yet",
240 ));
241 }
242
243 let mut receiver = None;
David Tolnaye3a48152020-04-08 19:38:05 -0700244 let mut args = Punctuated::new();
245 for arg in foreign_fn.sig.inputs.pairs() {
246 let (arg, comma) = arg.into_tuple();
David Tolnay7db73692019-10-20 14:51:12 -0400247 match arg {
David Tolnay1dd11a12020-04-22 12:31:48 -0700248 FnArg::Receiver(arg) => {
David Tolnaya1f29c42020-04-22 18:01:38 -0700249 if let Some((ampersand, lifetime)) = &arg.reference {
250 receiver = Some(Receiver {
251 ampersand: *ampersand,
252 lifetime: lifetime.clone(),
253 mutability: arg.mutability,
254 var: arg.self_token,
255 ty: Token![Self](arg.self_token.span).into(),
256 shorthand: true,
257 });
258 continue;
Joel Galensone1e969d2020-04-21 12:50:20 -0700259 }
David Tolnay1dd11a12020-04-22 12:31:48 -0700260 return Err(Error::new_spanned(arg, "unsupported signature"));
David Tolnay7db73692019-10-20 14:51:12 -0400261 }
262 FnArg::Typed(arg) => {
263 let ident = match arg.pat.as_ref() {
264 Pat::Ident(pat) => pat.ident.clone(),
Joel Galensonba676072020-04-27 15:55:45 -0700265 Pat::Wild(pat) => {
266 Ident::new(&format!("_{}", args.len()), pat.underscore_token.span)
267 }
David Tolnay7db73692019-10-20 14:51:12 -0400268 _ => return Err(Error::new_spanned(arg, "unsupported signature")),
269 };
270 let ty = parse_type(&arg.ty)?;
271 if ident != "self" {
David Tolnaye3a48152020-04-08 19:38:05 -0700272 args.push_value(Var { ident, ty });
273 if let Some(comma) = comma {
274 args.push_punct(*comma);
275 }
David Tolnay7db73692019-10-20 14:51:12 -0400276 continue;
277 }
278 if let Type::Ref(reference) = ty {
279 if let Type::Ident(ident) = reference.inner {
280 receiver = Some(Receiver {
David Tolnayfb6e3862020-04-20 01:33:23 -0700281 ampersand: reference.ampersand,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700282 lifetime: reference.lifetime,
David Tolnay7db73692019-10-20 14:51:12 -0400283 mutability: reference.mutability,
David Tolnay05e11cc2020-04-20 02:13:56 -0700284 var: Token![self](ident.span()),
285 ty: ident,
David Tolnay62d360c2020-04-22 16:26:21 -0700286 shorthand: false,
David Tolnay7db73692019-10-20 14:51:12 -0400287 });
288 continue;
289 }
290 }
291 return Err(Error::new_spanned(arg, "unsupported method receiver"));
292 }
293 }
294 }
David Tolnay59b7ede2020-03-16 00:30:23 -0700295
David Tolnaye3a48152020-04-08 19:38:05 -0700296 let mut throws_tokens = None;
297 let ret = parse_return_type(&foreign_fn.sig.output, &mut throws_tokens)?;
298 let throws = throws_tokens.is_some();
David Tolnay3e628882020-05-10 15:30:14 -0700299 let doc = attrs::parse_doc(cx, &foreign_fn.attrs);
David Tolnay7db73692019-10-20 14:51:12 -0400300 let fn_token = foreign_fn.sig.fn_token;
301 let ident = foreign_fn.sig.ident.clone();
David Tolnaye3a48152020-04-08 19:38:05 -0700302 let paren_token = foreign_fn.sig.paren_token;
David Tolnay7db73692019-10-20 14:51:12 -0400303 let semi_token = foreign_fn.semi_token;
David Tolnay295ef6b2020-05-07 16:10:22 -0700304 let api_function = match lang {
305 Lang::Cxx => Api::CxxFunction,
306 Lang::Rust => Api::RustFunction,
307 };
David Tolnayd95b1192020-03-18 20:07:46 -0700308
David Tolnay295ef6b2020-05-07 16:10:22 -0700309 Ok(api_function(ExternFn {
David Tolnay6cde49f2020-03-16 12:25:45 -0700310 lang,
David Tolnay7db73692019-10-20 14:51:12 -0400311 doc,
David Tolnay7db73692019-10-20 14:51:12 -0400312 ident,
David Tolnay16448732020-03-18 12:39:36 -0700313 sig: Signature {
314 fn_token,
315 receiver,
316 args,
317 ret,
318 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700319 paren_token,
320 throws_tokens,
David Tolnay16448732020-03-18 12:39:36 -0700321 },
David Tolnay7db73692019-10-20 14:51:12 -0400322 semi_token,
David Tolnay295ef6b2020-05-07 16:10:22 -0700323 }))
David Tolnay7db73692019-10-20 14:51:12 -0400324}
325
David Tolnay3e628882020-05-10 15:30:14 -0700326fn parse_extern_verbatim(cx: &mut Errors, tokens: &TokenStream, lang: Lang) -> Result<Api> {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700327 // type Alias = crate::path::to::Type;
David Tolnay3e628882020-05-10 15:30:14 -0700328 let parse = |input: ParseStream| -> Result<TypeAlias> {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700329 let attrs = input.call(Attribute::parse_outer)?;
330 let type_token: Token![type] = match input.parse()? {
331 Some(type_token) => type_token,
332 None => {
333 let span = input.cursor().token_stream();
334 return Err(Error::new_spanned(span, "unsupported foreign item"));
335 }
336 };
337 let ident: Ident = input.parse()?;
338 let eq_token: Token![=] = input.parse()?;
339 let ty: RustType = input.parse()?;
340 let semi_token: Token![;] = input.parse()?;
David Tolnay3e628882020-05-10 15:30:14 -0700341 attrs::parse_doc(cx, &attrs);
David Tolnaye2f9ec42020-05-07 16:19:33 -0700342
343 Ok(TypeAlias {
344 type_token,
345 ident,
346 eq_token,
347 ty,
348 semi_token,
349 })
David Tolnay3e628882020-05-10 15:30:14 -0700350 };
David Tolnaye2f9ec42020-05-07 16:19:33 -0700351
352 let type_alias = parse.parse2(tokens.clone())?;
353 match lang {
354 Lang::Cxx => Ok(Api::TypeAlias(type_alias)),
355 Lang::Rust => {
356 let (type_token, semi_token) = (type_alias.type_token, type_alias.semi_token);
357 let span = quote!(#type_token #semi_token);
358 let msg = "type alias in extern \"Rust\" block is not supported";
359 Err(Error::new_spanned(span, msg))
360 }
361 }
362}
363
David Tolnay7db73692019-10-20 14:51:12 -0400364fn parse_type(ty: &RustType) -> Result<Type> {
David Tolnay59b7ede2020-03-16 00:30:23 -0700365 match ty {
David Tolnayb40b9db2020-03-18 13:50:31 -0700366 RustType::Reference(ty) => parse_type_reference(ty),
367 RustType::Path(ty) => parse_type_path(ty),
David Tolnayeebe9b72020-04-14 16:32:18 -0700368 RustType::Slice(ty) => parse_type_slice(ty),
David Tolnayc071b892020-03-18 16:59:53 -0700369 RustType::BareFn(ty) => parse_type_fn(ty),
David Tolnayb40b9db2020-03-18 13:50:31 -0700370 RustType::Tuple(ty) if ty.elems.is_empty() => Ok(Type::Void(ty.paren_token.span)),
371 _ => Err(Error::new_spanned(ty, "unsupported type")),
372 }
373}
374
375fn parse_type_reference(ty: &TypeReference) -> Result<Type> {
376 let inner = parse_type(&ty.elem)?;
377 let which = match &inner {
378 Type::Ident(ident) if ident == "str" => {
379 if ty.mutability.is_some() {
380 return Err(Error::new_spanned(ty, "unsupported type"));
381 } else {
382 Type::Str
David Tolnay7db73692019-10-20 14:51:12 -0400383 }
384 }
David Tolnayeebe9b72020-04-14 16:32:18 -0700385 Type::Slice(slice) => match &slice.inner {
386 Type::Ident(ident) if ident == U8 && ty.mutability.is_none() => Type::SliceRefU8,
387 _ => Type::Ref,
David Tolnayeb952ba2020-04-14 15:02:24 -0700388 },
David Tolnayb40b9db2020-03-18 13:50:31 -0700389 _ => Type::Ref,
390 };
391 Ok(which(Box::new(Ref {
392 ampersand: ty.and_token,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700393 lifetime: ty.lifetime.clone(),
David Tolnayb40b9db2020-03-18 13:50:31 -0700394 mutability: ty.mutability,
395 inner,
396 })))
397}
398
399fn parse_type_path(ty: &TypePath) -> Result<Type> {
400 let path = &ty.path;
401 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
402 let segment = &path.segments[0];
403 let ident = segment.ident.clone();
404 match &segment.arguments {
405 PathArguments::None => return Ok(Type::Ident(ident)),
406 PathArguments::AngleBracketed(generic) => {
407 if ident == "UniquePtr" && generic.args.len() == 1 {
408 if let GenericArgument::Type(arg) = &generic.args[0] {
409 let inner = parse_type(arg)?;
410 return Ok(Type::UniquePtr(Box::new(Ty1 {
411 name: ident,
412 langle: generic.lt_token,
413 inner,
414 rangle: generic.gt_token,
415 })));
416 }
David Tolnaye1dcdf72020-04-24 17:40:55 -0700417 } else if ident == "CxxVector" && generic.args.len() == 1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700418 if let GenericArgument::Type(arg) = &generic.args[0] {
419 let inner = parse_type(arg)?;
David Tolnay4377a9e2020-04-24 15:20:26 -0700420 return Ok(Type::CxxVector(Box::new(Ty1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700421 name: ident,
422 langle: generic.lt_token,
423 inner,
424 rangle: generic.gt_token,
425 })));
426 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700427 } else if ident == "Box" && generic.args.len() == 1 {
428 if let GenericArgument::Type(arg) = &generic.args[0] {
429 let inner = parse_type(arg)?;
430 return Ok(Type::RustBox(Box::new(Ty1 {
431 name: ident,
432 langle: generic.lt_token,
433 inner,
434 rangle: generic.gt_token,
435 })));
436 }
Myron Ahneba35cf2020-02-05 19:41:51 +0700437 } else if ident == "Vec" && generic.args.len() == 1 {
438 if let GenericArgument::Type(arg) = &generic.args[0] {
439 let inner = parse_type(arg)?;
440 return Ok(Type::RustVec(Box::new(Ty1 {
441 name: ident,
442 langle: generic.lt_token,
443 inner,
444 rangle: generic.gt_token,
445 })));
446 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700447 }
448 }
449 PathArguments::Parenthesized(_) => {}
David Tolnayfb134ed2020-03-15 23:17:48 -0700450 }
David Tolnay7db73692019-10-20 14:51:12 -0400451 }
452 Err(Error::new_spanned(ty, "unsupported type"))
453}
454
David Tolnayeebe9b72020-04-14 16:32:18 -0700455fn parse_type_slice(ty: &TypeSlice) -> Result<Type> {
456 let inner = parse_type(&ty.elem)?;
457 Ok(Type::Slice(Box::new(Slice {
458 bracket: ty.bracket_token,
459 inner,
460 })))
461}
462
David Tolnayc071b892020-03-18 16:59:53 -0700463fn parse_type_fn(ty: &TypeBareFn) -> Result<Type> {
464 if ty.lifetimes.is_some() {
465 return Err(Error::new_spanned(
466 ty,
467 "function pointer with lifetime parameters is not supported yet",
468 ));
469 }
470 if ty.variadic.is_some() {
471 return Err(Error::new_spanned(
472 ty,
473 "variadic function pointer is not supported yet",
474 ));
475 }
476 let args = ty
477 .inputs
478 .iter()
479 .enumerate()
480 .map(|(i, arg)| {
481 let ty = parse_type(&arg.ty)?;
482 let ident = match &arg.name {
483 Some(ident) => ident.0.clone(),
484 None => format_ident!("_{}", i),
485 };
486 Ok(Var { ident, ty })
487 })
488 .collect::<Result<_>>()?;
David Tolnaye3a48152020-04-08 19:38:05 -0700489 let mut throws_tokens = None;
490 let ret = parse_return_type(&ty.output, &mut throws_tokens)?;
491 let throws = throws_tokens.is_some();
David Tolnayc071b892020-03-18 16:59:53 -0700492 Ok(Type::Fn(Box::new(Signature {
493 fn_token: ty.fn_token,
494 receiver: None,
495 args,
496 ret,
497 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700498 paren_token: ty.paren_token,
499 throws_tokens,
David Tolnayc071b892020-03-18 16:59:53 -0700500 })))
501}
502
David Tolnaye3a48152020-04-08 19:38:05 -0700503fn parse_return_type(
504 ty: &ReturnType,
505 throws_tokens: &mut Option<(kw::Result, Token![<], Token![>])>,
506) -> Result<Option<Type>> {
David Tolnayc071b892020-03-18 16:59:53 -0700507 let mut ret = match ty {
508 ReturnType::Default => return Ok(None),
509 ReturnType::Type(_, ret) => ret.as_ref(),
510 };
511 if let RustType::Path(ty) = ret {
512 let path = &ty.path;
513 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
514 let segment = &path.segments[0];
515 let ident = segment.ident.clone();
516 if let PathArguments::AngleBracketed(generic) = &segment.arguments {
517 if ident == "Result" && generic.args.len() == 1 {
518 if let GenericArgument::Type(arg) = &generic.args[0] {
519 ret = arg;
David Tolnaye3a48152020-04-08 19:38:05 -0700520 *throws_tokens =
521 Some((kw::Result(ident.span()), generic.lt_token, generic.gt_token));
David Tolnayc071b892020-03-18 16:59:53 -0700522 }
523 }
524 }
525 }
526 }
527 match parse_type(ret)? {
528 Type::Void(_) => Ok(None),
529 ty => Ok(Some(ty)),
530 }
531}