blob: a11a5c8817d67a23c8596e6bb16ab20950296b48 [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 Tolnaye2e303f2020-05-10 20:52:00 -07009use quote::{format_ident, quote, quote_spanned};
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),
David Tolnayddf69e22020-05-10 22:08:20 -070063 ..Default::default()
David Tolnayb129ea72020-05-10 14:29:30 -070064 },
David Tolnay3e628882020-05-10 15:30:14 -070065 );
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
David Tolnay3e628882020-05-10 15:30:14 -070094fn parse_enum(cx: &mut Errors, item: ItemEnum) -> Result<Api> {
Joel Galensonc03402a2020-04-23 17:31:09 -070095 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 Tolnayddf69e22020-05-10 22:08:20 -0700107 let mut doc = Doc::new();
108 let mut repr = None;
109 attrs::parse(
110 cx,
111 &item.attrs,
112 attrs::Parser {
113 doc: Some(&mut doc),
114 repr: Some(&mut repr),
115 ..Default::default()
116 },
117 );
Joel Galensonc03402a2020-04-23 17:31:09 -0700118
Joel Galenson88547732020-05-05 08:23:42 -0700119 let mut variants = Vec::new();
David Tolnayddf69e22020-05-10 22:08:20 -0700120 let mut discriminants = DiscriminantSet::new(repr);
Joel Galenson88547732020-05-05 08:23:42 -0700121 for variant in item.variants {
122 match variant.fields {
Joel Galensonc03402a2020-04-23 17:31:09 -0700123 Fields::Unit => {}
124 _ => {
David Tolnay0435a812020-05-10 21:58:15 -0700125 cx.error(variant, "enums with data are not supported yet");
126 break;
Joel Galensonc03402a2020-04-23 17:31:09 -0700127 }
128 }
David Tolnay17e137f2020-05-08 15:55:28 -0700129 let expr = variant.discriminant.as_ref().map(|(_, expr)| expr);
130 let try_discriminant = match &expr {
131 Some(lit) => discriminants.insert(lit),
132 None => discriminants.insert_next(),
133 };
134 let discriminant = match try_discriminant {
135 Ok(discriminant) => discriminant,
David Tolnay0435a812020-05-10 21:58:15 -0700136 Err(err) => {
137 cx.error(variant, err);
138 break;
139 }
David Tolnay17e137f2020-05-08 15:55:28 -0700140 };
David Tolnay2b8bf6d2020-05-10 17:37:16 -0700141 let expr = variant.discriminant.map(|(_, expr)| expr);
Joel Galenson88547732020-05-05 08:23:42 -0700142 variants.push(Variant {
143 ident: variant.ident,
David Tolnay7ae018f2020-05-05 10:11:30 -0700144 discriminant,
David Tolnay2b8bf6d2020-05-10 17:37:16 -0700145 expr,
Joel Galenson88547732020-05-05 08:23:42 -0700146 });
Joel Galensonc03402a2020-04-23 17:31:09 -0700147 }
148
David Tolnaye2e303f2020-05-10 20:52:00 -0700149 let enum_token = item.enum_token;
150 let brace_token = item.brace_token;
151
David Tolnay0435a812020-05-10 21:58:15 -0700152 let mut repr = U8;
153 match discriminants.inferred_repr() {
154 Ok(inferred) => repr = inferred,
David Tolnaye2e303f2020-05-10 20:52:00 -0700155 Err(err) => {
156 let span = quote_spanned!(brace_token.span=> #enum_token {});
David Tolnay0435a812020-05-10 21:58:15 -0700157 cx.error(span, err);
158 variants.clear();
David Tolnaye2e303f2020-05-10 20:52:00 -0700159 }
David Tolnay0435a812020-05-10 21:58:15 -0700160 }
David Tolnaye2e303f2020-05-10 20:52:00 -0700161
Joel Galensonc03402a2020-04-23 17:31:09 -0700162 Ok(Api::Enum(Enum {
163 doc,
David Tolnaye2e303f2020-05-10 20:52:00 -0700164 enum_token,
Joel Galensonc03402a2020-04-23 17:31:09 -0700165 ident: item.ident,
David Tolnaye2e303f2020-05-10 20:52:00 -0700166 brace_token,
David Tolnay7ae018f2020-05-05 10:11:30 -0700167 variants,
David Tolnaye2e303f2020-05-10 20:52:00 -0700168 repr,
Joel Galensonc03402a2020-04-23 17:31:09 -0700169 }))
170}
171
David Tolnay52759782020-05-03 23:59:40 -0700172fn parse_foreign_mod(cx: &mut Errors, foreign_mod: ItemForeignMod, out: &mut Vec<Api>) {
173 let lang = match parse_lang(foreign_mod.abi) {
174 Ok(lang) => lang,
175 Err(err) => return cx.push(err),
176 };
David Tolnay7db73692019-10-20 14:51:12 -0400177
Joel Galensone1e969d2020-04-21 12:50:20 -0700178 let mut items = Vec::new();
179 for foreign in &foreign_mod.items {
180 match foreign {
David Tolnay3e628882020-05-10 15:30:14 -0700181 ForeignItem::Type(foreign) => match parse_extern_type(cx, foreign, lang) {
David Tolnay295ef6b2020-05-07 16:10:22 -0700182 Ok(ety) => items.push(ety),
David Tolnay52759782020-05-03 23:59:40 -0700183 Err(err) => cx.push(err),
184 },
David Tolnay3e628882020-05-10 15:30:14 -0700185 ForeignItem::Fn(foreign) => match parse_extern_fn(cx, foreign, lang) {
David Tolnay295ef6b2020-05-07 16:10:22 -0700186 Ok(efn) => items.push(efn),
David Tolnay52759782020-05-03 23:59:40 -0700187 Err(err) => cx.push(err),
188 },
David Tolnay7db73692019-10-20 14:51:12 -0400189 ForeignItem::Macro(foreign) if foreign.mac.path.is_ident("include") => {
David Tolnay52759782020-05-03 23:59:40 -0700190 match foreign.mac.parse_body() {
191 Ok(include) => items.push(Api::Include(include)),
192 Err(err) => cx.push(err),
193 }
David Tolnay7db73692019-10-20 14:51:12 -0400194 }
David Tolnay3e628882020-05-10 15:30:14 -0700195 ForeignItem::Verbatim(tokens) => match parse_extern_verbatim(cx, tokens, lang) {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700196 Ok(api) => items.push(api),
197 Err(err) => cx.push(err),
198 },
David Tolnay52759782020-05-03 23:59:40 -0700199 _ => cx.error(foreign, "unsupported foreign item"),
David Tolnay7db73692019-10-20 14:51:12 -0400200 }
201 }
David Tolnaya1f29c42020-04-22 18:01:38 -0700202
203 let mut types = items.iter().filter_map(|item| match item {
David Tolnaye5a015a2020-05-07 21:54:26 -0700204 Api::CxxType(ty) | Api::RustType(ty) => Some(&ty.ident),
205 Api::TypeAlias(alias) => Some(&alias.ident),
David Tolnaya1f29c42020-04-22 18:01:38 -0700206 _ => None,
207 });
208 if let (Some(single_type), None) = (types.next(), types.next()) {
David Tolnaye5a015a2020-05-07 21:54:26 -0700209 let single_type = single_type.clone();
David Tolnaya1f29c42020-04-22 18:01:38 -0700210 for item in &mut items {
211 if let Api::CxxFunction(efn) | Api::RustFunction(efn) = item {
212 if let Some(receiver) = &mut efn.receiver {
213 if receiver.ty == "Self" {
214 receiver.ty = single_type.clone();
215 }
216 }
217 }
218 }
219 }
220
David Tolnay52759782020-05-03 23:59:40 -0700221 out.extend(items);
David Tolnay7db73692019-10-20 14:51:12 -0400222}
223
224fn parse_lang(abi: Abi) -> Result<Lang> {
225 let name = match &abi.name {
226 Some(name) => name,
227 None => {
228 return Err(Error::new_spanned(
229 abi,
230 "ABI name is required, extern \"C\" or extern \"Rust\"",
231 ));
232 }
233 };
234 match name.value().as_str() {
David Tolnay0b76aea2020-03-18 12:54:24 -0700235 "C" | "C++" => Ok(Lang::Cxx),
David Tolnay7db73692019-10-20 14:51:12 -0400236 "Rust" => Ok(Lang::Rust),
237 _ => Err(Error::new_spanned(abi, "unrecognized ABI")),
238 }
239}
240
David Tolnay3e628882020-05-10 15:30:14 -0700241fn parse_extern_type(cx: &mut Errors, foreign_type: &ForeignItemType, lang: Lang) -> Result<Api> {
242 let doc = attrs::parse_doc(cx, &foreign_type.attrs);
David Tolnay7db73692019-10-20 14:51:12 -0400243 let type_token = foreign_type.type_token;
244 let ident = foreign_type.ident.clone();
David Tolnay295ef6b2020-05-07 16:10:22 -0700245 let api_type = match lang {
246 Lang::Cxx => Api::CxxType,
247 Lang::Rust => Api::RustType,
248 };
249 Ok(api_type(ExternType {
David Tolnay7db73692019-10-20 14:51:12 -0400250 doc,
251 type_token,
252 ident,
David Tolnay295ef6b2020-05-07 16:10:22 -0700253 }))
David Tolnay7db73692019-10-20 14:51:12 -0400254}
255
David Tolnay3e628882020-05-10 15:30:14 -0700256fn parse_extern_fn(cx: &mut Errors, foreign_fn: &ForeignItemFn, lang: Lang) -> Result<Api> {
David Tolnay7db73692019-10-20 14:51:12 -0400257 let generics = &foreign_fn.sig.generics;
258 if !generics.params.is_empty() || generics.where_clause.is_some() {
259 return Err(Error::new_spanned(
260 foreign_fn,
261 "extern function with generic parameters is not supported yet",
262 ));
263 }
264 if let Some(variadic) = &foreign_fn.sig.variadic {
265 return Err(Error::new_spanned(
266 variadic,
267 "variadic function is not supported yet",
268 ));
269 }
270
271 let mut receiver = None;
David Tolnaye3a48152020-04-08 19:38:05 -0700272 let mut args = Punctuated::new();
273 for arg in foreign_fn.sig.inputs.pairs() {
274 let (arg, comma) = arg.into_tuple();
David Tolnay7db73692019-10-20 14:51:12 -0400275 match arg {
David Tolnay1dd11a12020-04-22 12:31:48 -0700276 FnArg::Receiver(arg) => {
David Tolnaya1f29c42020-04-22 18:01:38 -0700277 if let Some((ampersand, lifetime)) = &arg.reference {
278 receiver = Some(Receiver {
279 ampersand: *ampersand,
280 lifetime: lifetime.clone(),
281 mutability: arg.mutability,
282 var: arg.self_token,
283 ty: Token![Self](arg.self_token.span).into(),
284 shorthand: true,
285 });
286 continue;
Joel Galensone1e969d2020-04-21 12:50:20 -0700287 }
David Tolnay1dd11a12020-04-22 12:31:48 -0700288 return Err(Error::new_spanned(arg, "unsupported signature"));
David Tolnay7db73692019-10-20 14:51:12 -0400289 }
290 FnArg::Typed(arg) => {
291 let ident = match arg.pat.as_ref() {
292 Pat::Ident(pat) => pat.ident.clone(),
Joel Galensonba676072020-04-27 15:55:45 -0700293 Pat::Wild(pat) => {
294 Ident::new(&format!("_{}", args.len()), pat.underscore_token.span)
295 }
David Tolnay7db73692019-10-20 14:51:12 -0400296 _ => return Err(Error::new_spanned(arg, "unsupported signature")),
297 };
298 let ty = parse_type(&arg.ty)?;
299 if ident != "self" {
David Tolnaye3a48152020-04-08 19:38:05 -0700300 args.push_value(Var { ident, ty });
301 if let Some(comma) = comma {
302 args.push_punct(*comma);
303 }
David Tolnay7db73692019-10-20 14:51:12 -0400304 continue;
305 }
306 if let Type::Ref(reference) = ty {
307 if let Type::Ident(ident) = reference.inner {
308 receiver = Some(Receiver {
David Tolnayfb6e3862020-04-20 01:33:23 -0700309 ampersand: reference.ampersand,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700310 lifetime: reference.lifetime,
David Tolnay7db73692019-10-20 14:51:12 -0400311 mutability: reference.mutability,
David Tolnay05e11cc2020-04-20 02:13:56 -0700312 var: Token![self](ident.span()),
313 ty: ident,
David Tolnay62d360c2020-04-22 16:26:21 -0700314 shorthand: false,
David Tolnay7db73692019-10-20 14:51:12 -0400315 });
316 continue;
317 }
318 }
319 return Err(Error::new_spanned(arg, "unsupported method receiver"));
320 }
321 }
322 }
David Tolnay59b7ede2020-03-16 00:30:23 -0700323
David Tolnaye3a48152020-04-08 19:38:05 -0700324 let mut throws_tokens = None;
325 let ret = parse_return_type(&foreign_fn.sig.output, &mut throws_tokens)?;
326 let throws = throws_tokens.is_some();
David Tolnay3e628882020-05-10 15:30:14 -0700327 let doc = attrs::parse_doc(cx, &foreign_fn.attrs);
David Tolnay7db73692019-10-20 14:51:12 -0400328 let fn_token = foreign_fn.sig.fn_token;
329 let ident = foreign_fn.sig.ident.clone();
David Tolnaye3a48152020-04-08 19:38:05 -0700330 let paren_token = foreign_fn.sig.paren_token;
David Tolnay7db73692019-10-20 14:51:12 -0400331 let semi_token = foreign_fn.semi_token;
David Tolnay295ef6b2020-05-07 16:10:22 -0700332 let api_function = match lang {
333 Lang::Cxx => Api::CxxFunction,
334 Lang::Rust => Api::RustFunction,
335 };
David Tolnayd95b1192020-03-18 20:07:46 -0700336
David Tolnay295ef6b2020-05-07 16:10:22 -0700337 Ok(api_function(ExternFn {
David Tolnay6cde49f2020-03-16 12:25:45 -0700338 lang,
David Tolnay7db73692019-10-20 14:51:12 -0400339 doc,
David Tolnay7db73692019-10-20 14:51:12 -0400340 ident,
David Tolnay16448732020-03-18 12:39:36 -0700341 sig: Signature {
342 fn_token,
343 receiver,
344 args,
345 ret,
346 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700347 paren_token,
348 throws_tokens,
David Tolnay16448732020-03-18 12:39:36 -0700349 },
David Tolnay7db73692019-10-20 14:51:12 -0400350 semi_token,
David Tolnay295ef6b2020-05-07 16:10:22 -0700351 }))
David Tolnay7db73692019-10-20 14:51:12 -0400352}
353
David Tolnay3e628882020-05-10 15:30:14 -0700354fn parse_extern_verbatim(cx: &mut Errors, tokens: &TokenStream, lang: Lang) -> Result<Api> {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700355 // type Alias = crate::path::to::Type;
David Tolnay3e628882020-05-10 15:30:14 -0700356 let parse = |input: ParseStream| -> Result<TypeAlias> {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700357 let attrs = input.call(Attribute::parse_outer)?;
358 let type_token: Token![type] = match input.parse()? {
359 Some(type_token) => type_token,
360 None => {
361 let span = input.cursor().token_stream();
362 return Err(Error::new_spanned(span, "unsupported foreign item"));
363 }
364 };
365 let ident: Ident = input.parse()?;
366 let eq_token: Token![=] = input.parse()?;
367 let ty: RustType = input.parse()?;
368 let semi_token: Token![;] = input.parse()?;
David Tolnay3e628882020-05-10 15:30:14 -0700369 attrs::parse_doc(cx, &attrs);
David Tolnaye2f9ec42020-05-07 16:19:33 -0700370
371 Ok(TypeAlias {
372 type_token,
373 ident,
374 eq_token,
375 ty,
376 semi_token,
377 })
David Tolnay3e628882020-05-10 15:30:14 -0700378 };
David Tolnaye2f9ec42020-05-07 16:19:33 -0700379
380 let type_alias = parse.parse2(tokens.clone())?;
381 match lang {
382 Lang::Cxx => Ok(Api::TypeAlias(type_alias)),
383 Lang::Rust => {
384 let (type_token, semi_token) = (type_alias.type_token, type_alias.semi_token);
385 let span = quote!(#type_token #semi_token);
386 let msg = "type alias in extern \"Rust\" block is not supported";
387 Err(Error::new_spanned(span, msg))
388 }
389 }
390}
391
David Tolnay7db73692019-10-20 14:51:12 -0400392fn parse_type(ty: &RustType) -> Result<Type> {
David Tolnay59b7ede2020-03-16 00:30:23 -0700393 match ty {
David Tolnayb40b9db2020-03-18 13:50:31 -0700394 RustType::Reference(ty) => parse_type_reference(ty),
395 RustType::Path(ty) => parse_type_path(ty),
David Tolnayeebe9b72020-04-14 16:32:18 -0700396 RustType::Slice(ty) => parse_type_slice(ty),
David Tolnayc071b892020-03-18 16:59:53 -0700397 RustType::BareFn(ty) => parse_type_fn(ty),
David Tolnayb40b9db2020-03-18 13:50:31 -0700398 RustType::Tuple(ty) if ty.elems.is_empty() => Ok(Type::Void(ty.paren_token.span)),
399 _ => Err(Error::new_spanned(ty, "unsupported type")),
400 }
401}
402
403fn parse_type_reference(ty: &TypeReference) -> Result<Type> {
404 let inner = parse_type(&ty.elem)?;
405 let which = match &inner {
406 Type::Ident(ident) if ident == "str" => {
407 if ty.mutability.is_some() {
408 return Err(Error::new_spanned(ty, "unsupported type"));
409 } else {
410 Type::Str
David Tolnay7db73692019-10-20 14:51:12 -0400411 }
412 }
David Tolnayeebe9b72020-04-14 16:32:18 -0700413 Type::Slice(slice) => match &slice.inner {
414 Type::Ident(ident) if ident == U8 && ty.mutability.is_none() => Type::SliceRefU8,
415 _ => Type::Ref,
David Tolnayeb952ba2020-04-14 15:02:24 -0700416 },
David Tolnayb40b9db2020-03-18 13:50:31 -0700417 _ => Type::Ref,
418 };
419 Ok(which(Box::new(Ref {
420 ampersand: ty.and_token,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700421 lifetime: ty.lifetime.clone(),
David Tolnayb40b9db2020-03-18 13:50:31 -0700422 mutability: ty.mutability,
423 inner,
424 })))
425}
426
427fn parse_type_path(ty: &TypePath) -> Result<Type> {
428 let path = &ty.path;
429 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
430 let segment = &path.segments[0];
431 let ident = segment.ident.clone();
432 match &segment.arguments {
433 PathArguments::None => return Ok(Type::Ident(ident)),
434 PathArguments::AngleBracketed(generic) => {
435 if ident == "UniquePtr" && generic.args.len() == 1 {
436 if let GenericArgument::Type(arg) = &generic.args[0] {
437 let inner = parse_type(arg)?;
438 return Ok(Type::UniquePtr(Box::new(Ty1 {
439 name: ident,
440 langle: generic.lt_token,
441 inner,
442 rangle: generic.gt_token,
443 })));
444 }
David Tolnaye1dcdf72020-04-24 17:40:55 -0700445 } else if ident == "CxxVector" && generic.args.len() == 1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700446 if let GenericArgument::Type(arg) = &generic.args[0] {
447 let inner = parse_type(arg)?;
David Tolnay4377a9e2020-04-24 15:20:26 -0700448 return Ok(Type::CxxVector(Box::new(Ty1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700449 name: ident,
450 langle: generic.lt_token,
451 inner,
452 rangle: generic.gt_token,
453 })));
454 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700455 } else if ident == "Box" && generic.args.len() == 1 {
456 if let GenericArgument::Type(arg) = &generic.args[0] {
457 let inner = parse_type(arg)?;
458 return Ok(Type::RustBox(Box::new(Ty1 {
459 name: ident,
460 langle: generic.lt_token,
461 inner,
462 rangle: generic.gt_token,
463 })));
464 }
Myron Ahneba35cf2020-02-05 19:41:51 +0700465 } else if ident == "Vec" && generic.args.len() == 1 {
466 if let GenericArgument::Type(arg) = &generic.args[0] {
467 let inner = parse_type(arg)?;
468 return Ok(Type::RustVec(Box::new(Ty1 {
469 name: ident,
470 langle: generic.lt_token,
471 inner,
472 rangle: generic.gt_token,
473 })));
474 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700475 }
476 }
477 PathArguments::Parenthesized(_) => {}
David Tolnayfb134ed2020-03-15 23:17:48 -0700478 }
David Tolnay7db73692019-10-20 14:51:12 -0400479 }
480 Err(Error::new_spanned(ty, "unsupported type"))
481}
482
David Tolnayeebe9b72020-04-14 16:32:18 -0700483fn parse_type_slice(ty: &TypeSlice) -> Result<Type> {
484 let inner = parse_type(&ty.elem)?;
485 Ok(Type::Slice(Box::new(Slice {
486 bracket: ty.bracket_token,
487 inner,
488 })))
489}
490
David Tolnayc071b892020-03-18 16:59:53 -0700491fn parse_type_fn(ty: &TypeBareFn) -> Result<Type> {
492 if ty.lifetimes.is_some() {
493 return Err(Error::new_spanned(
494 ty,
495 "function pointer with lifetime parameters is not supported yet",
496 ));
497 }
498 if ty.variadic.is_some() {
499 return Err(Error::new_spanned(
500 ty,
501 "variadic function pointer is not supported yet",
502 ));
503 }
504 let args = ty
505 .inputs
506 .iter()
507 .enumerate()
508 .map(|(i, arg)| {
509 let ty = parse_type(&arg.ty)?;
510 let ident = match &arg.name {
511 Some(ident) => ident.0.clone(),
512 None => format_ident!("_{}", i),
513 };
514 Ok(Var { ident, ty })
515 })
516 .collect::<Result<_>>()?;
David Tolnaye3a48152020-04-08 19:38:05 -0700517 let mut throws_tokens = None;
518 let ret = parse_return_type(&ty.output, &mut throws_tokens)?;
519 let throws = throws_tokens.is_some();
David Tolnayc071b892020-03-18 16:59:53 -0700520 Ok(Type::Fn(Box::new(Signature {
521 fn_token: ty.fn_token,
522 receiver: None,
523 args,
524 ret,
525 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700526 paren_token: ty.paren_token,
527 throws_tokens,
David Tolnayc071b892020-03-18 16:59:53 -0700528 })))
529}
530
David Tolnaye3a48152020-04-08 19:38:05 -0700531fn parse_return_type(
532 ty: &ReturnType,
533 throws_tokens: &mut Option<(kw::Result, Token![<], Token![>])>,
534) -> Result<Option<Type>> {
David Tolnayc071b892020-03-18 16:59:53 -0700535 let mut ret = match ty {
536 ReturnType::Default => return Ok(None),
537 ReturnType::Type(_, ret) => ret.as_ref(),
538 };
539 if let RustType::Path(ty) = ret {
540 let path = &ty.path;
541 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
542 let segment = &path.segments[0];
543 let ident = segment.ident.clone();
544 if let PathArguments::AngleBracketed(generic) = &segment.arguments {
545 if ident == "Result" && generic.args.len() == 1 {
546 if let GenericArgument::Type(arg) = &generic.args[0] {
547 ret = arg;
David Tolnaye3a48152020-04-08 19:38:05 -0700548 *throws_tokens =
549 Some((kw::Result(ident.span()), generic.lt_token, generic.gt_token));
David Tolnayc071b892020-03-18 16:59:53 -0700550 }
551 }
552 }
553 }
554 }
555 match parse_type(ret)? {
556 Type::Void(_) => Ok(None),
557 ty => Ok(Some(ty)),
558 }
559}