blob: 3ca63ab0ebad29e822bbac5340081f3bdaf0105f [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 };
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
137 Ok(Api::Enum(Enum {
138 doc,
139 enum_token: item.enum_token,
140 ident: item.ident,
141 brace_token: item.brace_token,
David Tolnay7ae018f2020-05-05 10:11:30 -0700142 variants,
Joel Galensonc03402a2020-04-23 17:31:09 -0700143 }))
144}
145
David Tolnay52759782020-05-03 23:59:40 -0700146fn parse_foreign_mod(cx: &mut Errors, foreign_mod: ItemForeignMod, out: &mut Vec<Api>) {
147 let lang = match parse_lang(foreign_mod.abi) {
148 Ok(lang) => lang,
149 Err(err) => return cx.push(err),
150 };
David Tolnay7db73692019-10-20 14:51:12 -0400151
Joel Galensone1e969d2020-04-21 12:50:20 -0700152 let mut items = Vec::new();
153 for foreign in &foreign_mod.items {
154 match foreign {
David Tolnay3e628882020-05-10 15:30:14 -0700155 ForeignItem::Type(foreign) => match parse_extern_type(cx, foreign, lang) {
David Tolnay295ef6b2020-05-07 16:10:22 -0700156 Ok(ety) => items.push(ety),
David Tolnay52759782020-05-03 23:59:40 -0700157 Err(err) => cx.push(err),
158 },
David Tolnay3e628882020-05-10 15:30:14 -0700159 ForeignItem::Fn(foreign) => match parse_extern_fn(cx, foreign, lang) {
David Tolnay295ef6b2020-05-07 16:10:22 -0700160 Ok(efn) => items.push(efn),
David Tolnay52759782020-05-03 23:59:40 -0700161 Err(err) => cx.push(err),
162 },
David Tolnay7db73692019-10-20 14:51:12 -0400163 ForeignItem::Macro(foreign) if foreign.mac.path.is_ident("include") => {
David Tolnay52759782020-05-03 23:59:40 -0700164 match foreign.mac.parse_body() {
165 Ok(include) => items.push(Api::Include(include)),
166 Err(err) => cx.push(err),
167 }
David Tolnay7db73692019-10-20 14:51:12 -0400168 }
David Tolnay3e628882020-05-10 15:30:14 -0700169 ForeignItem::Verbatim(tokens) => match parse_extern_verbatim(cx, tokens, lang) {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700170 Ok(api) => items.push(api),
171 Err(err) => cx.push(err),
172 },
David Tolnay52759782020-05-03 23:59:40 -0700173 _ => cx.error(foreign, "unsupported foreign item"),
David Tolnay7db73692019-10-20 14:51:12 -0400174 }
175 }
David Tolnaya1f29c42020-04-22 18:01:38 -0700176
177 let mut types = items.iter().filter_map(|item| match item {
David Tolnaye5a015a2020-05-07 21:54:26 -0700178 Api::CxxType(ty) | Api::RustType(ty) => Some(&ty.ident),
179 Api::TypeAlias(alias) => Some(&alias.ident),
David Tolnaya1f29c42020-04-22 18:01:38 -0700180 _ => None,
181 });
182 if let (Some(single_type), None) = (types.next(), types.next()) {
David Tolnaye5a015a2020-05-07 21:54:26 -0700183 let single_type = single_type.clone();
David Tolnaya1f29c42020-04-22 18:01:38 -0700184 for item in &mut items {
185 if let Api::CxxFunction(efn) | Api::RustFunction(efn) = item {
186 if let Some(receiver) = &mut efn.receiver {
187 if receiver.ty == "Self" {
188 receiver.ty = single_type.clone();
189 }
190 }
191 }
192 }
193 }
194
David Tolnay52759782020-05-03 23:59:40 -0700195 out.extend(items);
David Tolnay7db73692019-10-20 14:51:12 -0400196}
197
198fn parse_lang(abi: Abi) -> Result<Lang> {
199 let name = match &abi.name {
200 Some(name) => name,
201 None => {
202 return Err(Error::new_spanned(
203 abi,
204 "ABI name is required, extern \"C\" or extern \"Rust\"",
205 ));
206 }
207 };
208 match name.value().as_str() {
David Tolnay0b76aea2020-03-18 12:54:24 -0700209 "C" | "C++" => Ok(Lang::Cxx),
David Tolnay7db73692019-10-20 14:51:12 -0400210 "Rust" => Ok(Lang::Rust),
211 _ => Err(Error::new_spanned(abi, "unrecognized ABI")),
212 }
213}
214
David Tolnay3e628882020-05-10 15:30:14 -0700215fn parse_extern_type(cx: &mut Errors, foreign_type: &ForeignItemType, lang: Lang) -> Result<Api> {
216 let doc = attrs::parse_doc(cx, &foreign_type.attrs);
David Tolnay7db73692019-10-20 14:51:12 -0400217 let type_token = foreign_type.type_token;
218 let ident = foreign_type.ident.clone();
David Tolnay295ef6b2020-05-07 16:10:22 -0700219 let api_type = match lang {
220 Lang::Cxx => Api::CxxType,
221 Lang::Rust => Api::RustType,
222 };
223 Ok(api_type(ExternType {
David Tolnay7db73692019-10-20 14:51:12 -0400224 doc,
225 type_token,
226 ident,
David Tolnay295ef6b2020-05-07 16:10:22 -0700227 }))
David Tolnay7db73692019-10-20 14:51:12 -0400228}
229
David Tolnay3e628882020-05-10 15:30:14 -0700230fn parse_extern_fn(cx: &mut Errors, foreign_fn: &ForeignItemFn, lang: Lang) -> Result<Api> {
David Tolnay7db73692019-10-20 14:51:12 -0400231 let generics = &foreign_fn.sig.generics;
232 if !generics.params.is_empty() || generics.where_clause.is_some() {
233 return Err(Error::new_spanned(
234 foreign_fn,
235 "extern function with generic parameters is not supported yet",
236 ));
237 }
238 if let Some(variadic) = &foreign_fn.sig.variadic {
239 return Err(Error::new_spanned(
240 variadic,
241 "variadic function is not supported yet",
242 ));
243 }
244
245 let mut receiver = None;
David Tolnaye3a48152020-04-08 19:38:05 -0700246 let mut args = Punctuated::new();
247 for arg in foreign_fn.sig.inputs.pairs() {
248 let (arg, comma) = arg.into_tuple();
David Tolnay7db73692019-10-20 14:51:12 -0400249 match arg {
David Tolnay1dd11a12020-04-22 12:31:48 -0700250 FnArg::Receiver(arg) => {
David Tolnaya1f29c42020-04-22 18:01:38 -0700251 if let Some((ampersand, lifetime)) = &arg.reference {
252 receiver = Some(Receiver {
253 ampersand: *ampersand,
254 lifetime: lifetime.clone(),
255 mutability: arg.mutability,
256 var: arg.self_token,
257 ty: Token![Self](arg.self_token.span).into(),
258 shorthand: true,
259 });
260 continue;
Joel Galensone1e969d2020-04-21 12:50:20 -0700261 }
David Tolnay1dd11a12020-04-22 12:31:48 -0700262 return Err(Error::new_spanned(arg, "unsupported signature"));
David Tolnay7db73692019-10-20 14:51:12 -0400263 }
264 FnArg::Typed(arg) => {
265 let ident = match arg.pat.as_ref() {
266 Pat::Ident(pat) => pat.ident.clone(),
Joel Galensonba676072020-04-27 15:55:45 -0700267 Pat::Wild(pat) => {
268 Ident::new(&format!("_{}", args.len()), pat.underscore_token.span)
269 }
David Tolnay7db73692019-10-20 14:51:12 -0400270 _ => return Err(Error::new_spanned(arg, "unsupported signature")),
271 };
272 let ty = parse_type(&arg.ty)?;
273 if ident != "self" {
David Tolnaye3a48152020-04-08 19:38:05 -0700274 args.push_value(Var { ident, ty });
275 if let Some(comma) = comma {
276 args.push_punct(*comma);
277 }
David Tolnay7db73692019-10-20 14:51:12 -0400278 continue;
279 }
280 if let Type::Ref(reference) = ty {
281 if let Type::Ident(ident) = reference.inner {
282 receiver = Some(Receiver {
David Tolnayfb6e3862020-04-20 01:33:23 -0700283 ampersand: reference.ampersand,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700284 lifetime: reference.lifetime,
David Tolnay7db73692019-10-20 14:51:12 -0400285 mutability: reference.mutability,
David Tolnay05e11cc2020-04-20 02:13:56 -0700286 var: Token![self](ident.span()),
287 ty: ident,
David Tolnay62d360c2020-04-22 16:26:21 -0700288 shorthand: false,
David Tolnay7db73692019-10-20 14:51:12 -0400289 });
290 continue;
291 }
292 }
293 return Err(Error::new_spanned(arg, "unsupported method receiver"));
294 }
295 }
296 }
David Tolnay59b7ede2020-03-16 00:30:23 -0700297
David Tolnaye3a48152020-04-08 19:38:05 -0700298 let mut throws_tokens = None;
299 let ret = parse_return_type(&foreign_fn.sig.output, &mut throws_tokens)?;
300 let throws = throws_tokens.is_some();
David Tolnay3e628882020-05-10 15:30:14 -0700301 let doc = attrs::parse_doc(cx, &foreign_fn.attrs);
David Tolnay7db73692019-10-20 14:51:12 -0400302 let fn_token = foreign_fn.sig.fn_token;
303 let ident = foreign_fn.sig.ident.clone();
David Tolnaye3a48152020-04-08 19:38:05 -0700304 let paren_token = foreign_fn.sig.paren_token;
David Tolnay7db73692019-10-20 14:51:12 -0400305 let semi_token = foreign_fn.semi_token;
David Tolnay295ef6b2020-05-07 16:10:22 -0700306 let api_function = match lang {
307 Lang::Cxx => Api::CxxFunction,
308 Lang::Rust => Api::RustFunction,
309 };
David Tolnayd95b1192020-03-18 20:07:46 -0700310
David Tolnay295ef6b2020-05-07 16:10:22 -0700311 Ok(api_function(ExternFn {
David Tolnay6cde49f2020-03-16 12:25:45 -0700312 lang,
David Tolnay7db73692019-10-20 14:51:12 -0400313 doc,
David Tolnay7db73692019-10-20 14:51:12 -0400314 ident,
David Tolnay16448732020-03-18 12:39:36 -0700315 sig: Signature {
316 fn_token,
317 receiver,
318 args,
319 ret,
320 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700321 paren_token,
322 throws_tokens,
David Tolnay16448732020-03-18 12:39:36 -0700323 },
David Tolnay7db73692019-10-20 14:51:12 -0400324 semi_token,
David Tolnay295ef6b2020-05-07 16:10:22 -0700325 }))
David Tolnay7db73692019-10-20 14:51:12 -0400326}
327
David Tolnay3e628882020-05-10 15:30:14 -0700328fn parse_extern_verbatim(cx: &mut Errors, tokens: &TokenStream, lang: Lang) -> Result<Api> {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700329 // type Alias = crate::path::to::Type;
David Tolnay3e628882020-05-10 15:30:14 -0700330 let parse = |input: ParseStream| -> Result<TypeAlias> {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700331 let attrs = input.call(Attribute::parse_outer)?;
332 let type_token: Token![type] = match input.parse()? {
333 Some(type_token) => type_token,
334 None => {
335 let span = input.cursor().token_stream();
336 return Err(Error::new_spanned(span, "unsupported foreign item"));
337 }
338 };
339 let ident: Ident = input.parse()?;
340 let eq_token: Token![=] = input.parse()?;
341 let ty: RustType = input.parse()?;
342 let semi_token: Token![;] = input.parse()?;
David Tolnay3e628882020-05-10 15:30:14 -0700343 attrs::parse_doc(cx, &attrs);
David Tolnaye2f9ec42020-05-07 16:19:33 -0700344
345 Ok(TypeAlias {
346 type_token,
347 ident,
348 eq_token,
349 ty,
350 semi_token,
351 })
David Tolnay3e628882020-05-10 15:30:14 -0700352 };
David Tolnaye2f9ec42020-05-07 16:19:33 -0700353
354 let type_alias = parse.parse2(tokens.clone())?;
355 match lang {
356 Lang::Cxx => Ok(Api::TypeAlias(type_alias)),
357 Lang::Rust => {
358 let (type_token, semi_token) = (type_alias.type_token, type_alias.semi_token);
359 let span = quote!(#type_token #semi_token);
360 let msg = "type alias in extern \"Rust\" block is not supported";
361 Err(Error::new_spanned(span, msg))
362 }
363 }
364}
365
David Tolnay7db73692019-10-20 14:51:12 -0400366fn parse_type(ty: &RustType) -> Result<Type> {
David Tolnay59b7ede2020-03-16 00:30:23 -0700367 match ty {
David Tolnayb40b9db2020-03-18 13:50:31 -0700368 RustType::Reference(ty) => parse_type_reference(ty),
369 RustType::Path(ty) => parse_type_path(ty),
David Tolnayeebe9b72020-04-14 16:32:18 -0700370 RustType::Slice(ty) => parse_type_slice(ty),
David Tolnayc071b892020-03-18 16:59:53 -0700371 RustType::BareFn(ty) => parse_type_fn(ty),
David Tolnayb40b9db2020-03-18 13:50:31 -0700372 RustType::Tuple(ty) if ty.elems.is_empty() => Ok(Type::Void(ty.paren_token.span)),
373 _ => Err(Error::new_spanned(ty, "unsupported type")),
374 }
375}
376
377fn parse_type_reference(ty: &TypeReference) -> Result<Type> {
378 let inner = parse_type(&ty.elem)?;
379 let which = match &inner {
380 Type::Ident(ident) if ident == "str" => {
381 if ty.mutability.is_some() {
382 return Err(Error::new_spanned(ty, "unsupported type"));
383 } else {
384 Type::Str
David Tolnay7db73692019-10-20 14:51:12 -0400385 }
386 }
David Tolnayeebe9b72020-04-14 16:32:18 -0700387 Type::Slice(slice) => match &slice.inner {
388 Type::Ident(ident) if ident == U8 && ty.mutability.is_none() => Type::SliceRefU8,
389 _ => Type::Ref,
David Tolnayeb952ba2020-04-14 15:02:24 -0700390 },
David Tolnayb40b9db2020-03-18 13:50:31 -0700391 _ => Type::Ref,
392 };
393 Ok(which(Box::new(Ref {
394 ampersand: ty.and_token,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700395 lifetime: ty.lifetime.clone(),
David Tolnayb40b9db2020-03-18 13:50:31 -0700396 mutability: ty.mutability,
397 inner,
398 })))
399}
400
401fn parse_type_path(ty: &TypePath) -> Result<Type> {
402 let path = &ty.path;
403 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
404 let segment = &path.segments[0];
405 let ident = segment.ident.clone();
406 match &segment.arguments {
407 PathArguments::None => return Ok(Type::Ident(ident)),
408 PathArguments::AngleBracketed(generic) => {
409 if ident == "UniquePtr" && generic.args.len() == 1 {
410 if let GenericArgument::Type(arg) = &generic.args[0] {
411 let inner = parse_type(arg)?;
412 return Ok(Type::UniquePtr(Box::new(Ty1 {
413 name: ident,
414 langle: generic.lt_token,
415 inner,
416 rangle: generic.gt_token,
417 })));
418 }
David Tolnaye1dcdf72020-04-24 17:40:55 -0700419 } else if ident == "CxxVector" && generic.args.len() == 1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700420 if let GenericArgument::Type(arg) = &generic.args[0] {
421 let inner = parse_type(arg)?;
David Tolnay4377a9e2020-04-24 15:20:26 -0700422 return Ok(Type::CxxVector(Box::new(Ty1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700423 name: ident,
424 langle: generic.lt_token,
425 inner,
426 rangle: generic.gt_token,
427 })));
428 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700429 } else if ident == "Box" && generic.args.len() == 1 {
430 if let GenericArgument::Type(arg) = &generic.args[0] {
431 let inner = parse_type(arg)?;
432 return Ok(Type::RustBox(Box::new(Ty1 {
433 name: ident,
434 langle: generic.lt_token,
435 inner,
436 rangle: generic.gt_token,
437 })));
438 }
Myron Ahneba35cf2020-02-05 19:41:51 +0700439 } else if ident == "Vec" && generic.args.len() == 1 {
440 if let GenericArgument::Type(arg) = &generic.args[0] {
441 let inner = parse_type(arg)?;
442 return Ok(Type::RustVec(Box::new(Ty1 {
443 name: ident,
444 langle: generic.lt_token,
445 inner,
446 rangle: generic.gt_token,
447 })));
448 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700449 }
450 }
451 PathArguments::Parenthesized(_) => {}
David Tolnayfb134ed2020-03-15 23:17:48 -0700452 }
David Tolnay7db73692019-10-20 14:51:12 -0400453 }
454 Err(Error::new_spanned(ty, "unsupported type"))
455}
456
David Tolnayeebe9b72020-04-14 16:32:18 -0700457fn parse_type_slice(ty: &TypeSlice) -> Result<Type> {
458 let inner = parse_type(&ty.elem)?;
459 Ok(Type::Slice(Box::new(Slice {
460 bracket: ty.bracket_token,
461 inner,
462 })))
463}
464
David Tolnayc071b892020-03-18 16:59:53 -0700465fn parse_type_fn(ty: &TypeBareFn) -> Result<Type> {
466 if ty.lifetimes.is_some() {
467 return Err(Error::new_spanned(
468 ty,
469 "function pointer with lifetime parameters is not supported yet",
470 ));
471 }
472 if ty.variadic.is_some() {
473 return Err(Error::new_spanned(
474 ty,
475 "variadic function pointer is not supported yet",
476 ));
477 }
478 let args = ty
479 .inputs
480 .iter()
481 .enumerate()
482 .map(|(i, arg)| {
483 let ty = parse_type(&arg.ty)?;
484 let ident = match &arg.name {
485 Some(ident) => ident.0.clone(),
486 None => format_ident!("_{}", i),
487 };
488 Ok(Var { ident, ty })
489 })
490 .collect::<Result<_>>()?;
David Tolnaye3a48152020-04-08 19:38:05 -0700491 let mut throws_tokens = None;
492 let ret = parse_return_type(&ty.output, &mut throws_tokens)?;
493 let throws = throws_tokens.is_some();
David Tolnayc071b892020-03-18 16:59:53 -0700494 Ok(Type::Fn(Box::new(Signature {
495 fn_token: ty.fn_token,
496 receiver: None,
497 args,
498 ret,
499 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700500 paren_token: ty.paren_token,
501 throws_tokens,
David Tolnayc071b892020-03-18 16:59:53 -0700502 })))
503}
504
David Tolnaye3a48152020-04-08 19:38:05 -0700505fn parse_return_type(
506 ty: &ReturnType,
507 throws_tokens: &mut Option<(kw::Result, Token![<], Token![>])>,
508) -> Result<Option<Type>> {
David Tolnayc071b892020-03-18 16:59:53 -0700509 let mut ret = match ty {
510 ReturnType::Default => return Ok(None),
511 ReturnType::Type(_, ret) => ret.as_ref(),
512 };
513 if let RustType::Path(ty) = ret {
514 let path = &ty.path;
515 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
516 let segment = &path.segments[0];
517 let ident = segment.ident.clone();
518 if let PathArguments::AngleBracketed(generic) = &segment.arguments {
519 if ident == "Result" && generic.args.len() == 1 {
520 if let GenericArgument::Type(arg) = &generic.args[0] {
521 ret = arg;
David Tolnaye3a48152020-04-08 19:38:05 -0700522 *throws_tokens =
523 Some((kw::Result(ident.span()), generic.lt_token, generic.gt_token));
David Tolnayc071b892020-03-18 16:59:53 -0700524 }
525 }
526 }
527 }
528 }
529 match parse_type(ret)? {
530 Type::Void(_) => Ok(None),
531 ty => Ok(Some(ty)),
532 }
533}