blob: b5070c79d9953fe6f6917d3eef6c67bfd081a21c [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();
David Tolnayb129ea72020-05-10 14:29:30 -070059 attrs::parse(
60 &item.attrs,
61 attrs::Parser {
62 doc: Some(&mut doc),
63 derives: Some(&mut derives),
64 },
65 )?;
David Tolnay09462ac2020-03-20 14:58:41 -070066
67 let fields = match item.fields {
68 Fields::Named(fields) => fields,
69 Fields::Unit => return Err(Error::new_spanned(item, "unit structs are not supported")),
70 Fields::Unnamed(_) => {
71 return Err(Error::new_spanned(item, "tuple structs are not supported"))
72 }
73 };
74
75 Ok(Api::Struct(Struct {
76 doc,
77 derives,
78 struct_token: item.struct_token,
79 ident: item.ident,
80 brace_token: fields.brace_token,
81 fields: fields
82 .named
83 .into_iter()
84 .map(|field| {
85 Ok(Var {
86 ident: field.ident.unwrap(),
87 ty: parse_type(&field.ty)?,
David Tolnay7db73692019-10-20 14:51:12 -040088 })
David Tolnay09462ac2020-03-20 14:58:41 -070089 })
90 .collect::<Result<_>>()?,
91 }))
David Tolnay7db73692019-10-20 14:51:12 -040092}
93
Joel Galensonc03402a2020-04-23 17:31:09 -070094fn parse_enum(item: ItemEnum) -> Result<Api> {
95 let generics = &item.generics;
96 if !generics.params.is_empty() || generics.where_clause.is_some() {
97 let enum_token = item.enum_token;
98 let ident = &item.ident;
99 let where_clause = &generics.where_clause;
100 let span = quote!(#enum_token #ident #generics #where_clause);
101 return Err(Error::new_spanned(
102 span,
103 "enums with generic parameters are not allowed",
104 ));
105 }
106
David Tolnayd7984c22020-04-30 20:09:31 -0700107 let doc = attrs::parse_doc(&item.attrs)?;
Joel Galensonc03402a2020-04-23 17:31:09 -0700108
Joel Galenson88547732020-05-05 08:23:42 -0700109 let mut variants = Vec::new();
110 let mut discriminants = HashSet::new();
111 let mut prev_discriminant = None;
112 for variant in item.variants {
113 match variant.fields {
Joel Galensonc03402a2020-04-23 17:31:09 -0700114 Fields::Unit => {}
115 _ => {
116 return Err(Error::new_spanned(
117 variant,
David Tolnayd7984c22020-04-30 20:09:31 -0700118 "enums with data are not supported yet",
Joel Galenson88547732020-05-05 08:23:42 -0700119 ));
Joel Galensonc03402a2020-04-23 17:31:09 -0700120 }
121 }
David Tolnay4301f3c2020-05-05 10:29:52 -0700122 if variant.discriminant.is_none() && prev_discriminant == Some(u32::MAX) {
David Tolnaya3f64072020-05-05 10:24:24 -0700123 let msg = format!("discriminant overflow on value after {}", u32::MAX);
124 return Err(Error::new_spanned(variant, msg));
Joel Galenson88547732020-05-05 08:23:42 -0700125 }
126 let discriminant =
127 parse_discriminant(&variant)?.unwrap_or_else(|| prev_discriminant.map_or(0, |n| n + 1));
128 if !discriminants.insert(discriminant) {
129 let msg = format!("discriminant value `{}` already exists", discriminant);
130 return Err(Error::new_spanned(variant, msg));
131 }
132 variants.push(Variant {
133 ident: variant.ident,
David Tolnay7ae018f2020-05-05 10:11:30 -0700134 discriminant,
Joel Galenson88547732020-05-05 08:23:42 -0700135 });
136 prev_discriminant = Some(discriminant);
Joel Galensonc03402a2020-04-23 17:31:09 -0700137 }
138
139 Ok(Api::Enum(Enum {
140 doc,
141 enum_token: item.enum_token,
142 ident: item.ident,
143 brace_token: item.brace_token,
David Tolnay7ae018f2020-05-05 10:11:30 -0700144 variants,
Joel Galensonc03402a2020-04-23 17:31:09 -0700145 }))
146}
147
Joel Galenson88547732020-05-05 08:23:42 -0700148fn parse_discriminant(variant: &RustVariant) -> Result<Option<u32>> {
Joel Galensonc03402a2020-04-23 17:31:09 -0700149 match &variant.discriminant {
Joel Galenson88547732020-05-05 08:23:42 -0700150 None => Ok(None),
Joel Galensonc03402a2020-04-23 17:31:09 -0700151 Some((
152 _,
153 Expr::Lit(ExprLit {
154 lit: Lit::Int(n), ..
155 }),
David Tolnayd7984c22020-04-30 20:09:31 -0700156 )) => match n.base10_parse() {
Joel Galenson88547732020-05-05 08:23:42 -0700157 Ok(val) => Ok(Some(val)),
Joel Galensonc03402a2020-04-23 17:31:09 -0700158 Err(_) => Err(Error::new_spanned(
159 variant,
160 "cannot parse enum discriminant as an integer",
161 )),
162 },
163 _ => Err(Error::new_spanned(
164 variant,
David Tolnayd7984c22020-04-30 20:09:31 -0700165 "enums with non-integer literal discriminants are not supported yet",
Joel Galensonc03402a2020-04-23 17:31:09 -0700166 )),
167 }
168}
169
David Tolnay52759782020-05-03 23:59:40 -0700170fn parse_foreign_mod(cx: &mut Errors, foreign_mod: ItemForeignMod, out: &mut Vec<Api>) {
171 let lang = match parse_lang(foreign_mod.abi) {
172 Ok(lang) => lang,
173 Err(err) => return cx.push(err),
174 };
David Tolnay7db73692019-10-20 14:51:12 -0400175
Joel Galensone1e969d2020-04-21 12:50:20 -0700176 let mut items = Vec::new();
177 for foreign in &foreign_mod.items {
178 match foreign {
David Tolnay295ef6b2020-05-07 16:10:22 -0700179 ForeignItem::Type(foreign) => match parse_extern_type(foreign, lang) {
180 Ok(ety) => items.push(ety),
David Tolnay52759782020-05-03 23:59:40 -0700181 Err(err) => cx.push(err),
182 },
183 ForeignItem::Fn(foreign) => match parse_extern_fn(foreign, lang) {
David Tolnay295ef6b2020-05-07 16:10:22 -0700184 Ok(efn) => items.push(efn),
David Tolnay52759782020-05-03 23:59:40 -0700185 Err(err) => cx.push(err),
186 },
David Tolnay7db73692019-10-20 14:51:12 -0400187 ForeignItem::Macro(foreign) if foreign.mac.path.is_ident("include") => {
David Tolnay52759782020-05-03 23:59:40 -0700188 match foreign.mac.parse_body() {
189 Ok(include) => items.push(Api::Include(include)),
190 Err(err) => cx.push(err),
191 }
David Tolnay7db73692019-10-20 14:51:12 -0400192 }
David Tolnaye2f9ec42020-05-07 16:19:33 -0700193 ForeignItem::Verbatim(tokens) => match parse_extern_verbatim(tokens, lang) {
194 Ok(api) => items.push(api),
195 Err(err) => cx.push(err),
196 },
David Tolnay52759782020-05-03 23:59:40 -0700197 _ => cx.error(foreign, "unsupported foreign item"),
David Tolnay7db73692019-10-20 14:51:12 -0400198 }
199 }
David Tolnaya1f29c42020-04-22 18:01:38 -0700200
201 let mut types = items.iter().filter_map(|item| match item {
David Tolnaye5a015a2020-05-07 21:54:26 -0700202 Api::CxxType(ty) | Api::RustType(ty) => Some(&ty.ident),
203 Api::TypeAlias(alias) => Some(&alias.ident),
David Tolnaya1f29c42020-04-22 18:01:38 -0700204 _ => None,
205 });
206 if let (Some(single_type), None) = (types.next(), types.next()) {
David Tolnaye5a015a2020-05-07 21:54:26 -0700207 let single_type = single_type.clone();
David Tolnaya1f29c42020-04-22 18:01:38 -0700208 for item in &mut items {
209 if let Api::CxxFunction(efn) | Api::RustFunction(efn) = item {
210 if let Some(receiver) = &mut efn.receiver {
211 if receiver.ty == "Self" {
212 receiver.ty = single_type.clone();
213 }
214 }
215 }
216 }
217 }
218
David Tolnay52759782020-05-03 23:59:40 -0700219 out.extend(items);
David Tolnay7db73692019-10-20 14:51:12 -0400220}
221
222fn parse_lang(abi: Abi) -> Result<Lang> {
223 let name = match &abi.name {
224 Some(name) => name,
225 None => {
226 return Err(Error::new_spanned(
227 abi,
228 "ABI name is required, extern \"C\" or extern \"Rust\"",
229 ));
230 }
231 };
232 match name.value().as_str() {
David Tolnay0b76aea2020-03-18 12:54:24 -0700233 "C" | "C++" => Ok(Lang::Cxx),
David Tolnay7db73692019-10-20 14:51:12 -0400234 "Rust" => Ok(Lang::Rust),
235 _ => Err(Error::new_spanned(abi, "unrecognized ABI")),
236 }
237}
238
David Tolnay295ef6b2020-05-07 16:10:22 -0700239fn parse_extern_type(foreign_type: &ForeignItemType, lang: Lang) -> Result<Api> {
David Tolnay7db73692019-10-20 14:51:12 -0400240 let doc = attrs::parse_doc(&foreign_type.attrs)?;
241 let type_token = foreign_type.type_token;
242 let ident = foreign_type.ident.clone();
David Tolnay295ef6b2020-05-07 16:10:22 -0700243 let api_type = match lang {
244 Lang::Cxx => Api::CxxType,
245 Lang::Rust => Api::RustType,
246 };
247 Ok(api_type(ExternType {
David Tolnay7db73692019-10-20 14:51:12 -0400248 doc,
249 type_token,
250 ident,
David Tolnay295ef6b2020-05-07 16:10:22 -0700251 }))
David Tolnay7db73692019-10-20 14:51:12 -0400252}
253
David Tolnay295ef6b2020-05-07 16:10:22 -0700254fn parse_extern_fn(foreign_fn: &ForeignItemFn, lang: Lang) -> Result<Api> {
David Tolnay7db73692019-10-20 14:51:12 -0400255 let generics = &foreign_fn.sig.generics;
256 if !generics.params.is_empty() || generics.where_clause.is_some() {
257 return Err(Error::new_spanned(
258 foreign_fn,
259 "extern function with generic parameters is not supported yet",
260 ));
261 }
262 if let Some(variadic) = &foreign_fn.sig.variadic {
263 return Err(Error::new_spanned(
264 variadic,
265 "variadic function is not supported yet",
266 ));
267 }
268
269 let mut receiver = None;
David Tolnaye3a48152020-04-08 19:38:05 -0700270 let mut args = Punctuated::new();
271 for arg in foreign_fn.sig.inputs.pairs() {
272 let (arg, comma) = arg.into_tuple();
David Tolnay7db73692019-10-20 14:51:12 -0400273 match arg {
David Tolnay1dd11a12020-04-22 12:31:48 -0700274 FnArg::Receiver(arg) => {
David Tolnaya1f29c42020-04-22 18:01:38 -0700275 if let Some((ampersand, lifetime)) = &arg.reference {
276 receiver = Some(Receiver {
277 ampersand: *ampersand,
278 lifetime: lifetime.clone(),
279 mutability: arg.mutability,
280 var: arg.self_token,
281 ty: Token![Self](arg.self_token.span).into(),
282 shorthand: true,
283 });
284 continue;
Joel Galensone1e969d2020-04-21 12:50:20 -0700285 }
David Tolnay1dd11a12020-04-22 12:31:48 -0700286 return Err(Error::new_spanned(arg, "unsupported signature"));
David Tolnay7db73692019-10-20 14:51:12 -0400287 }
288 FnArg::Typed(arg) => {
289 let ident = match arg.pat.as_ref() {
290 Pat::Ident(pat) => pat.ident.clone(),
Joel Galensonba676072020-04-27 15:55:45 -0700291 Pat::Wild(pat) => {
292 Ident::new(&format!("_{}", args.len()), pat.underscore_token.span)
293 }
David Tolnay7db73692019-10-20 14:51:12 -0400294 _ => return Err(Error::new_spanned(arg, "unsupported signature")),
295 };
296 let ty = parse_type(&arg.ty)?;
297 if ident != "self" {
David Tolnaye3a48152020-04-08 19:38:05 -0700298 args.push_value(Var { ident, ty });
299 if let Some(comma) = comma {
300 args.push_punct(*comma);
301 }
David Tolnay7db73692019-10-20 14:51:12 -0400302 continue;
303 }
304 if let Type::Ref(reference) = ty {
305 if let Type::Ident(ident) = reference.inner {
306 receiver = Some(Receiver {
David Tolnayfb6e3862020-04-20 01:33:23 -0700307 ampersand: reference.ampersand,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700308 lifetime: reference.lifetime,
David Tolnay7db73692019-10-20 14:51:12 -0400309 mutability: reference.mutability,
David Tolnay05e11cc2020-04-20 02:13:56 -0700310 var: Token![self](ident.span()),
311 ty: ident,
David Tolnay62d360c2020-04-22 16:26:21 -0700312 shorthand: false,
David Tolnay7db73692019-10-20 14:51:12 -0400313 });
314 continue;
315 }
316 }
317 return Err(Error::new_spanned(arg, "unsupported method receiver"));
318 }
319 }
320 }
David Tolnay59b7ede2020-03-16 00:30:23 -0700321
David Tolnaye3a48152020-04-08 19:38:05 -0700322 let mut throws_tokens = None;
323 let ret = parse_return_type(&foreign_fn.sig.output, &mut throws_tokens)?;
324 let throws = throws_tokens.is_some();
David Tolnay7db73692019-10-20 14:51:12 -0400325 let doc = attrs::parse_doc(&foreign_fn.attrs)?;
326 let fn_token = foreign_fn.sig.fn_token;
327 let ident = foreign_fn.sig.ident.clone();
David Tolnaye3a48152020-04-08 19:38:05 -0700328 let paren_token = foreign_fn.sig.paren_token;
David Tolnay7db73692019-10-20 14:51:12 -0400329 let semi_token = foreign_fn.semi_token;
David Tolnay295ef6b2020-05-07 16:10:22 -0700330 let api_function = match lang {
331 Lang::Cxx => Api::CxxFunction,
332 Lang::Rust => Api::RustFunction,
333 };
David Tolnayd95b1192020-03-18 20:07:46 -0700334
David Tolnay295ef6b2020-05-07 16:10:22 -0700335 Ok(api_function(ExternFn {
David Tolnay6cde49f2020-03-16 12:25:45 -0700336 lang,
David Tolnay7db73692019-10-20 14:51:12 -0400337 doc,
David Tolnay7db73692019-10-20 14:51:12 -0400338 ident,
David Tolnay16448732020-03-18 12:39:36 -0700339 sig: Signature {
340 fn_token,
341 receiver,
342 args,
343 ret,
344 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700345 paren_token,
346 throws_tokens,
David Tolnay16448732020-03-18 12:39:36 -0700347 },
David Tolnay7db73692019-10-20 14:51:12 -0400348 semi_token,
David Tolnay295ef6b2020-05-07 16:10:22 -0700349 }))
David Tolnay7db73692019-10-20 14:51:12 -0400350}
351
David Tolnaye2f9ec42020-05-07 16:19:33 -0700352fn parse_extern_verbatim(tokens: &TokenStream, lang: Lang) -> Result<Api> {
353 // type Alias = crate::path::to::Type;
354 fn parse(input: ParseStream) -> Result<TypeAlias> {
355 let attrs = input.call(Attribute::parse_outer)?;
356 let type_token: Token![type] = match input.parse()? {
357 Some(type_token) => type_token,
358 None => {
359 let span = input.cursor().token_stream();
360 return Err(Error::new_spanned(span, "unsupported foreign item"));
361 }
362 };
363 let ident: Ident = input.parse()?;
364 let eq_token: Token![=] = input.parse()?;
365 let ty: RustType = input.parse()?;
366 let semi_token: Token![;] = input.parse()?;
367 attrs::parse_doc(&attrs)?;
368
369 Ok(TypeAlias {
370 type_token,
371 ident,
372 eq_token,
373 ty,
374 semi_token,
375 })
376 }
377
378 let type_alias = parse.parse2(tokens.clone())?;
379 match lang {
380 Lang::Cxx => Ok(Api::TypeAlias(type_alias)),
381 Lang::Rust => {
382 let (type_token, semi_token) = (type_alias.type_token, type_alias.semi_token);
383 let span = quote!(#type_token #semi_token);
384 let msg = "type alias in extern \"Rust\" block is not supported";
385 Err(Error::new_spanned(span, msg))
386 }
387 }
388}
389
David Tolnay7db73692019-10-20 14:51:12 -0400390fn parse_type(ty: &RustType) -> Result<Type> {
David Tolnay59b7ede2020-03-16 00:30:23 -0700391 match ty {
David Tolnayb40b9db2020-03-18 13:50:31 -0700392 RustType::Reference(ty) => parse_type_reference(ty),
393 RustType::Path(ty) => parse_type_path(ty),
David Tolnayeebe9b72020-04-14 16:32:18 -0700394 RustType::Slice(ty) => parse_type_slice(ty),
David Tolnayc071b892020-03-18 16:59:53 -0700395 RustType::BareFn(ty) => parse_type_fn(ty),
David Tolnayb40b9db2020-03-18 13:50:31 -0700396 RustType::Tuple(ty) if ty.elems.is_empty() => Ok(Type::Void(ty.paren_token.span)),
397 _ => Err(Error::new_spanned(ty, "unsupported type")),
398 }
399}
400
401fn parse_type_reference(ty: &TypeReference) -> Result<Type> {
402 let inner = parse_type(&ty.elem)?;
403 let which = match &inner {
404 Type::Ident(ident) if ident == "str" => {
405 if ty.mutability.is_some() {
406 return Err(Error::new_spanned(ty, "unsupported type"));
407 } else {
408 Type::Str
David Tolnay7db73692019-10-20 14:51:12 -0400409 }
410 }
David Tolnayeebe9b72020-04-14 16:32:18 -0700411 Type::Slice(slice) => match &slice.inner {
412 Type::Ident(ident) if ident == U8 && ty.mutability.is_none() => Type::SliceRefU8,
413 _ => Type::Ref,
David Tolnayeb952ba2020-04-14 15:02:24 -0700414 },
David Tolnayb40b9db2020-03-18 13:50:31 -0700415 _ => Type::Ref,
416 };
417 Ok(which(Box::new(Ref {
418 ampersand: ty.and_token,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700419 lifetime: ty.lifetime.clone(),
David Tolnayb40b9db2020-03-18 13:50:31 -0700420 mutability: ty.mutability,
421 inner,
422 })))
423}
424
425fn parse_type_path(ty: &TypePath) -> Result<Type> {
426 let path = &ty.path;
427 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
428 let segment = &path.segments[0];
429 let ident = segment.ident.clone();
430 match &segment.arguments {
431 PathArguments::None => return Ok(Type::Ident(ident)),
432 PathArguments::AngleBracketed(generic) => {
433 if ident == "UniquePtr" && generic.args.len() == 1 {
434 if let GenericArgument::Type(arg) = &generic.args[0] {
435 let inner = parse_type(arg)?;
436 return Ok(Type::UniquePtr(Box::new(Ty1 {
437 name: ident,
438 langle: generic.lt_token,
439 inner,
440 rangle: generic.gt_token,
441 })));
442 }
David Tolnaye1dcdf72020-04-24 17:40:55 -0700443 } else if ident == "CxxVector" && generic.args.len() == 1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700444 if let GenericArgument::Type(arg) = &generic.args[0] {
445 let inner = parse_type(arg)?;
David Tolnay4377a9e2020-04-24 15:20:26 -0700446 return Ok(Type::CxxVector(Box::new(Ty1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700447 name: ident,
448 langle: generic.lt_token,
449 inner,
450 rangle: generic.gt_token,
451 })));
452 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700453 } else if ident == "Box" && generic.args.len() == 1 {
454 if let GenericArgument::Type(arg) = &generic.args[0] {
455 let inner = parse_type(arg)?;
456 return Ok(Type::RustBox(Box::new(Ty1 {
457 name: ident,
458 langle: generic.lt_token,
459 inner,
460 rangle: generic.gt_token,
461 })));
462 }
Myron Ahneba35cf2020-02-05 19:41:51 +0700463 } else if ident == "Vec" && generic.args.len() == 1 {
464 if let GenericArgument::Type(arg) = &generic.args[0] {
465 let inner = parse_type(arg)?;
466 return Ok(Type::RustVec(Box::new(Ty1 {
467 name: ident,
468 langle: generic.lt_token,
469 inner,
470 rangle: generic.gt_token,
471 })));
472 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700473 }
474 }
475 PathArguments::Parenthesized(_) => {}
David Tolnayfb134ed2020-03-15 23:17:48 -0700476 }
David Tolnay7db73692019-10-20 14:51:12 -0400477 }
478 Err(Error::new_spanned(ty, "unsupported type"))
479}
480
David Tolnayeebe9b72020-04-14 16:32:18 -0700481fn parse_type_slice(ty: &TypeSlice) -> Result<Type> {
482 let inner = parse_type(&ty.elem)?;
483 Ok(Type::Slice(Box::new(Slice {
484 bracket: ty.bracket_token,
485 inner,
486 })))
487}
488
David Tolnayc071b892020-03-18 16:59:53 -0700489fn parse_type_fn(ty: &TypeBareFn) -> Result<Type> {
490 if ty.lifetimes.is_some() {
491 return Err(Error::new_spanned(
492 ty,
493 "function pointer with lifetime parameters is not supported yet",
494 ));
495 }
496 if ty.variadic.is_some() {
497 return Err(Error::new_spanned(
498 ty,
499 "variadic function pointer is not supported yet",
500 ));
501 }
502 let args = ty
503 .inputs
504 .iter()
505 .enumerate()
506 .map(|(i, arg)| {
507 let ty = parse_type(&arg.ty)?;
508 let ident = match &arg.name {
509 Some(ident) => ident.0.clone(),
510 None => format_ident!("_{}", i),
511 };
512 Ok(Var { ident, ty })
513 })
514 .collect::<Result<_>>()?;
David Tolnaye3a48152020-04-08 19:38:05 -0700515 let mut throws_tokens = None;
516 let ret = parse_return_type(&ty.output, &mut throws_tokens)?;
517 let throws = throws_tokens.is_some();
David Tolnayc071b892020-03-18 16:59:53 -0700518 Ok(Type::Fn(Box::new(Signature {
519 fn_token: ty.fn_token,
520 receiver: None,
521 args,
522 ret,
523 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700524 paren_token: ty.paren_token,
525 throws_tokens,
David Tolnayc071b892020-03-18 16:59:53 -0700526 })))
527}
528
David Tolnaye3a48152020-04-08 19:38:05 -0700529fn parse_return_type(
530 ty: &ReturnType,
531 throws_tokens: &mut Option<(kw::Result, Token![<], Token![>])>,
532) -> Result<Option<Type>> {
David Tolnayc071b892020-03-18 16:59:53 -0700533 let mut ret = match ty {
534 ReturnType::Default => return Ok(None),
535 ReturnType::Type(_, ret) => ret.as_ref(),
536 };
537 if let RustType::Path(ty) = ret {
538 let path = &ty.path;
539 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
540 let segment = &path.segments[0];
541 let ident = segment.ident.clone();
542 if let PathArguments::AngleBracketed(generic) = &segment.arguments {
543 if ident == "Result" && generic.args.len() == 1 {
544 if let GenericArgument::Type(arg) = &generic.args[0] {
545 ret = arg;
David Tolnaye3a48152020-04-08 19:38:05 -0700546 *throws_tokens =
547 Some((kw::Result(ident.span()), generic.lt_token, generic.gt_token));
David Tolnayc071b892020-03-18 16:59:53 -0700548 }
549 }
550 }
551 }
552 }
553 match parse_type(ret)? {
554 Type::Void(_) => Ok(None),
555 ty => Ok(Some(ty)),
556 }
557}