blob: ab5dcc140005273ad8775b02cf7139e7ca464747 [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),
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 _ => {
David Tolnay0435a812020-05-10 21:58:15 -0700114 cx.error(variant, "enums with data are not supported yet");
115 break;
Joel Galensonc03402a2020-04-23 17:31:09 -0700116 }
117 }
David Tolnay17e137f2020-05-08 15:55:28 -0700118 let expr = variant.discriminant.as_ref().map(|(_, expr)| expr);
119 let try_discriminant = match &expr {
120 Some(lit) => discriminants.insert(lit),
121 None => discriminants.insert_next(),
122 };
123 let discriminant = match try_discriminant {
124 Ok(discriminant) => discriminant,
David Tolnay0435a812020-05-10 21:58:15 -0700125 Err(err) => {
126 cx.error(variant, err);
127 break;
128 }
David Tolnay17e137f2020-05-08 15:55:28 -0700129 };
David Tolnay2b8bf6d2020-05-10 17:37:16 -0700130 let expr = variant.discriminant.map(|(_, expr)| expr);
Joel Galenson88547732020-05-05 08:23:42 -0700131 variants.push(Variant {
132 ident: variant.ident,
David Tolnay7ae018f2020-05-05 10:11:30 -0700133 discriminant,
David Tolnay2b8bf6d2020-05-10 17:37:16 -0700134 expr,
Joel Galenson88547732020-05-05 08:23:42 -0700135 });
Joel Galensonc03402a2020-04-23 17:31:09 -0700136 }
137
David Tolnaye2e303f2020-05-10 20:52:00 -0700138 let enum_token = item.enum_token;
139 let brace_token = item.brace_token;
140
David Tolnay0435a812020-05-10 21:58:15 -0700141 let mut repr = U8;
142 match discriminants.inferred_repr() {
143 Ok(inferred) => repr = inferred,
David Tolnaye2e303f2020-05-10 20:52:00 -0700144 Err(err) => {
145 let span = quote_spanned!(brace_token.span=> #enum_token {});
David Tolnay0435a812020-05-10 21:58:15 -0700146 cx.error(span, err);
147 variants.clear();
David Tolnaye2e303f2020-05-10 20:52:00 -0700148 }
David Tolnay0435a812020-05-10 21:58:15 -0700149 }
David Tolnaye2e303f2020-05-10 20:52:00 -0700150
Joel Galensonc03402a2020-04-23 17:31:09 -0700151 Ok(Api::Enum(Enum {
152 doc,
David Tolnaye2e303f2020-05-10 20:52:00 -0700153 enum_token,
Joel Galensonc03402a2020-04-23 17:31:09 -0700154 ident: item.ident,
David Tolnaye2e303f2020-05-10 20:52:00 -0700155 brace_token,
David Tolnay7ae018f2020-05-05 10:11:30 -0700156 variants,
David Tolnaye2e303f2020-05-10 20:52:00 -0700157 repr,
Joel Galensonc03402a2020-04-23 17:31:09 -0700158 }))
159}
160
David Tolnay52759782020-05-03 23:59:40 -0700161fn parse_foreign_mod(cx: &mut Errors, foreign_mod: ItemForeignMod, out: &mut Vec<Api>) {
162 let lang = match parse_lang(foreign_mod.abi) {
163 Ok(lang) => lang,
164 Err(err) => return cx.push(err),
165 };
David Tolnay7db73692019-10-20 14:51:12 -0400166
Joel Galensone1e969d2020-04-21 12:50:20 -0700167 let mut items = Vec::new();
168 for foreign in &foreign_mod.items {
169 match foreign {
David Tolnay3e628882020-05-10 15:30:14 -0700170 ForeignItem::Type(foreign) => match parse_extern_type(cx, foreign, lang) {
David Tolnay295ef6b2020-05-07 16:10:22 -0700171 Ok(ety) => items.push(ety),
David Tolnay52759782020-05-03 23:59:40 -0700172 Err(err) => cx.push(err),
173 },
David Tolnay3e628882020-05-10 15:30:14 -0700174 ForeignItem::Fn(foreign) => match parse_extern_fn(cx, foreign, lang) {
David Tolnay295ef6b2020-05-07 16:10:22 -0700175 Ok(efn) => items.push(efn),
David Tolnay52759782020-05-03 23:59:40 -0700176 Err(err) => cx.push(err),
177 },
David Tolnay7db73692019-10-20 14:51:12 -0400178 ForeignItem::Macro(foreign) if foreign.mac.path.is_ident("include") => {
David Tolnay52759782020-05-03 23:59:40 -0700179 match foreign.mac.parse_body() {
180 Ok(include) => items.push(Api::Include(include)),
181 Err(err) => cx.push(err),
182 }
David Tolnay7db73692019-10-20 14:51:12 -0400183 }
David Tolnay3e628882020-05-10 15:30:14 -0700184 ForeignItem::Verbatim(tokens) => match parse_extern_verbatim(cx, tokens, lang) {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700185 Ok(api) => items.push(api),
186 Err(err) => cx.push(err),
187 },
David Tolnay52759782020-05-03 23:59:40 -0700188 _ => cx.error(foreign, "unsupported foreign item"),
David Tolnay7db73692019-10-20 14:51:12 -0400189 }
190 }
David Tolnaya1f29c42020-04-22 18:01:38 -0700191
192 let mut types = items.iter().filter_map(|item| match item {
David Tolnaye5a015a2020-05-07 21:54:26 -0700193 Api::CxxType(ty) | Api::RustType(ty) => Some(&ty.ident),
194 Api::TypeAlias(alias) => Some(&alias.ident),
David Tolnaya1f29c42020-04-22 18:01:38 -0700195 _ => None,
196 });
197 if let (Some(single_type), None) = (types.next(), types.next()) {
David Tolnaye5a015a2020-05-07 21:54:26 -0700198 let single_type = single_type.clone();
David Tolnaya1f29c42020-04-22 18:01:38 -0700199 for item in &mut items {
200 if let Api::CxxFunction(efn) | Api::RustFunction(efn) = item {
201 if let Some(receiver) = &mut efn.receiver {
202 if receiver.ty == "Self" {
203 receiver.ty = single_type.clone();
204 }
205 }
206 }
207 }
208 }
209
David Tolnay52759782020-05-03 23:59:40 -0700210 out.extend(items);
David Tolnay7db73692019-10-20 14:51:12 -0400211}
212
213fn parse_lang(abi: Abi) -> Result<Lang> {
214 let name = match &abi.name {
215 Some(name) => name,
216 None => {
217 return Err(Error::new_spanned(
218 abi,
219 "ABI name is required, extern \"C\" or extern \"Rust\"",
220 ));
221 }
222 };
223 match name.value().as_str() {
David Tolnay0b76aea2020-03-18 12:54:24 -0700224 "C" | "C++" => Ok(Lang::Cxx),
David Tolnay7db73692019-10-20 14:51:12 -0400225 "Rust" => Ok(Lang::Rust),
226 _ => Err(Error::new_spanned(abi, "unrecognized ABI")),
227 }
228}
229
David Tolnay3e628882020-05-10 15:30:14 -0700230fn parse_extern_type(cx: &mut Errors, foreign_type: &ForeignItemType, lang: Lang) -> Result<Api> {
231 let doc = attrs::parse_doc(cx, &foreign_type.attrs);
David Tolnay7db73692019-10-20 14:51:12 -0400232 let type_token = foreign_type.type_token;
233 let ident = foreign_type.ident.clone();
David Tolnay295ef6b2020-05-07 16:10:22 -0700234 let api_type = match lang {
235 Lang::Cxx => Api::CxxType,
236 Lang::Rust => Api::RustType,
237 };
238 Ok(api_type(ExternType {
David Tolnay7db73692019-10-20 14:51:12 -0400239 doc,
240 type_token,
241 ident,
David Tolnay295ef6b2020-05-07 16:10:22 -0700242 }))
David Tolnay7db73692019-10-20 14:51:12 -0400243}
244
David Tolnay3e628882020-05-10 15:30:14 -0700245fn parse_extern_fn(cx: &mut Errors, foreign_fn: &ForeignItemFn, lang: Lang) -> Result<Api> {
David Tolnay7db73692019-10-20 14:51:12 -0400246 let generics = &foreign_fn.sig.generics;
247 if !generics.params.is_empty() || generics.where_clause.is_some() {
248 return Err(Error::new_spanned(
249 foreign_fn,
250 "extern function with generic parameters is not supported yet",
251 ));
252 }
253 if let Some(variadic) = &foreign_fn.sig.variadic {
254 return Err(Error::new_spanned(
255 variadic,
256 "variadic function is not supported yet",
257 ));
258 }
259
260 let mut receiver = None;
David Tolnaye3a48152020-04-08 19:38:05 -0700261 let mut args = Punctuated::new();
262 for arg in foreign_fn.sig.inputs.pairs() {
263 let (arg, comma) = arg.into_tuple();
David Tolnay7db73692019-10-20 14:51:12 -0400264 match arg {
David Tolnay1dd11a12020-04-22 12:31:48 -0700265 FnArg::Receiver(arg) => {
David Tolnaya1f29c42020-04-22 18:01:38 -0700266 if let Some((ampersand, lifetime)) = &arg.reference {
267 receiver = Some(Receiver {
268 ampersand: *ampersand,
269 lifetime: lifetime.clone(),
270 mutability: arg.mutability,
271 var: arg.self_token,
272 ty: Token![Self](arg.self_token.span).into(),
273 shorthand: true,
274 });
275 continue;
Joel Galensone1e969d2020-04-21 12:50:20 -0700276 }
David Tolnay1dd11a12020-04-22 12:31:48 -0700277 return Err(Error::new_spanned(arg, "unsupported signature"));
David Tolnay7db73692019-10-20 14:51:12 -0400278 }
279 FnArg::Typed(arg) => {
280 let ident = match arg.pat.as_ref() {
281 Pat::Ident(pat) => pat.ident.clone(),
Joel Galensonba676072020-04-27 15:55:45 -0700282 Pat::Wild(pat) => {
283 Ident::new(&format!("_{}", args.len()), pat.underscore_token.span)
284 }
David Tolnay7db73692019-10-20 14:51:12 -0400285 _ => return Err(Error::new_spanned(arg, "unsupported signature")),
286 };
287 let ty = parse_type(&arg.ty)?;
288 if ident != "self" {
David Tolnaye3a48152020-04-08 19:38:05 -0700289 args.push_value(Var { ident, ty });
290 if let Some(comma) = comma {
291 args.push_punct(*comma);
292 }
David Tolnay7db73692019-10-20 14:51:12 -0400293 continue;
294 }
295 if let Type::Ref(reference) = ty {
296 if let Type::Ident(ident) = reference.inner {
297 receiver = Some(Receiver {
David Tolnayfb6e3862020-04-20 01:33:23 -0700298 ampersand: reference.ampersand,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700299 lifetime: reference.lifetime,
David Tolnay7db73692019-10-20 14:51:12 -0400300 mutability: reference.mutability,
David Tolnay05e11cc2020-04-20 02:13:56 -0700301 var: Token![self](ident.span()),
302 ty: ident,
David Tolnay62d360c2020-04-22 16:26:21 -0700303 shorthand: false,
David Tolnay7db73692019-10-20 14:51:12 -0400304 });
305 continue;
306 }
307 }
308 return Err(Error::new_spanned(arg, "unsupported method receiver"));
309 }
310 }
311 }
David Tolnay59b7ede2020-03-16 00:30:23 -0700312
David Tolnaye3a48152020-04-08 19:38:05 -0700313 let mut throws_tokens = None;
314 let ret = parse_return_type(&foreign_fn.sig.output, &mut throws_tokens)?;
315 let throws = throws_tokens.is_some();
David Tolnay3e628882020-05-10 15:30:14 -0700316 let doc = attrs::parse_doc(cx, &foreign_fn.attrs);
David Tolnay7db73692019-10-20 14:51:12 -0400317 let fn_token = foreign_fn.sig.fn_token;
318 let ident = foreign_fn.sig.ident.clone();
David Tolnaye3a48152020-04-08 19:38:05 -0700319 let paren_token = foreign_fn.sig.paren_token;
David Tolnay7db73692019-10-20 14:51:12 -0400320 let semi_token = foreign_fn.semi_token;
David Tolnay295ef6b2020-05-07 16:10:22 -0700321 let api_function = match lang {
322 Lang::Cxx => Api::CxxFunction,
323 Lang::Rust => Api::RustFunction,
324 };
David Tolnayd95b1192020-03-18 20:07:46 -0700325
David Tolnay295ef6b2020-05-07 16:10:22 -0700326 Ok(api_function(ExternFn {
David Tolnay6cde49f2020-03-16 12:25:45 -0700327 lang,
David Tolnay7db73692019-10-20 14:51:12 -0400328 doc,
David Tolnay7db73692019-10-20 14:51:12 -0400329 ident,
David Tolnay16448732020-03-18 12:39:36 -0700330 sig: Signature {
331 fn_token,
332 receiver,
333 args,
334 ret,
335 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700336 paren_token,
337 throws_tokens,
David Tolnay16448732020-03-18 12:39:36 -0700338 },
David Tolnay7db73692019-10-20 14:51:12 -0400339 semi_token,
David Tolnay295ef6b2020-05-07 16:10:22 -0700340 }))
David Tolnay7db73692019-10-20 14:51:12 -0400341}
342
David Tolnay3e628882020-05-10 15:30:14 -0700343fn parse_extern_verbatim(cx: &mut Errors, tokens: &TokenStream, lang: Lang) -> Result<Api> {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700344 // type Alias = crate::path::to::Type;
David Tolnay3e628882020-05-10 15:30:14 -0700345 let parse = |input: ParseStream| -> Result<TypeAlias> {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700346 let attrs = input.call(Attribute::parse_outer)?;
347 let type_token: Token![type] = match input.parse()? {
348 Some(type_token) => type_token,
349 None => {
350 let span = input.cursor().token_stream();
351 return Err(Error::new_spanned(span, "unsupported foreign item"));
352 }
353 };
354 let ident: Ident = input.parse()?;
355 let eq_token: Token![=] = input.parse()?;
356 let ty: RustType = input.parse()?;
357 let semi_token: Token![;] = input.parse()?;
David Tolnay3e628882020-05-10 15:30:14 -0700358 attrs::parse_doc(cx, &attrs);
David Tolnaye2f9ec42020-05-07 16:19:33 -0700359
360 Ok(TypeAlias {
361 type_token,
362 ident,
363 eq_token,
364 ty,
365 semi_token,
366 })
David Tolnay3e628882020-05-10 15:30:14 -0700367 };
David Tolnaye2f9ec42020-05-07 16:19:33 -0700368
369 let type_alias = parse.parse2(tokens.clone())?;
370 match lang {
371 Lang::Cxx => Ok(Api::TypeAlias(type_alias)),
372 Lang::Rust => {
373 let (type_token, semi_token) = (type_alias.type_token, type_alias.semi_token);
374 let span = quote!(#type_token #semi_token);
375 let msg = "type alias in extern \"Rust\" block is not supported";
376 Err(Error::new_spanned(span, msg))
377 }
378 }
379}
380
David Tolnay7db73692019-10-20 14:51:12 -0400381fn parse_type(ty: &RustType) -> Result<Type> {
David Tolnay59b7ede2020-03-16 00:30:23 -0700382 match ty {
David Tolnayb40b9db2020-03-18 13:50:31 -0700383 RustType::Reference(ty) => parse_type_reference(ty),
384 RustType::Path(ty) => parse_type_path(ty),
David Tolnayeebe9b72020-04-14 16:32:18 -0700385 RustType::Slice(ty) => parse_type_slice(ty),
David Tolnayc071b892020-03-18 16:59:53 -0700386 RustType::BareFn(ty) => parse_type_fn(ty),
David Tolnayb40b9db2020-03-18 13:50:31 -0700387 RustType::Tuple(ty) if ty.elems.is_empty() => Ok(Type::Void(ty.paren_token.span)),
388 _ => Err(Error::new_spanned(ty, "unsupported type")),
389 }
390}
391
392fn parse_type_reference(ty: &TypeReference) -> Result<Type> {
393 let inner = parse_type(&ty.elem)?;
394 let which = match &inner {
395 Type::Ident(ident) if ident == "str" => {
396 if ty.mutability.is_some() {
397 return Err(Error::new_spanned(ty, "unsupported type"));
398 } else {
399 Type::Str
David Tolnay7db73692019-10-20 14:51:12 -0400400 }
401 }
David Tolnayeebe9b72020-04-14 16:32:18 -0700402 Type::Slice(slice) => match &slice.inner {
403 Type::Ident(ident) if ident == U8 && ty.mutability.is_none() => Type::SliceRefU8,
404 _ => Type::Ref,
David Tolnayeb952ba2020-04-14 15:02:24 -0700405 },
David Tolnayb40b9db2020-03-18 13:50:31 -0700406 _ => Type::Ref,
407 };
408 Ok(which(Box::new(Ref {
409 ampersand: ty.and_token,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700410 lifetime: ty.lifetime.clone(),
David Tolnayb40b9db2020-03-18 13:50:31 -0700411 mutability: ty.mutability,
412 inner,
413 })))
414}
415
416fn parse_type_path(ty: &TypePath) -> Result<Type> {
417 let path = &ty.path;
418 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
419 let segment = &path.segments[0];
420 let ident = segment.ident.clone();
421 match &segment.arguments {
422 PathArguments::None => return Ok(Type::Ident(ident)),
423 PathArguments::AngleBracketed(generic) => {
424 if ident == "UniquePtr" && generic.args.len() == 1 {
425 if let GenericArgument::Type(arg) = &generic.args[0] {
426 let inner = parse_type(arg)?;
427 return Ok(Type::UniquePtr(Box::new(Ty1 {
428 name: ident,
429 langle: generic.lt_token,
430 inner,
431 rangle: generic.gt_token,
432 })));
433 }
David Tolnaye1dcdf72020-04-24 17:40:55 -0700434 } else if ident == "CxxVector" && generic.args.len() == 1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700435 if let GenericArgument::Type(arg) = &generic.args[0] {
436 let inner = parse_type(arg)?;
David Tolnay4377a9e2020-04-24 15:20:26 -0700437 return Ok(Type::CxxVector(Box::new(Ty1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700438 name: ident,
439 langle: generic.lt_token,
440 inner,
441 rangle: generic.gt_token,
442 })));
443 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700444 } else if ident == "Box" && generic.args.len() == 1 {
445 if let GenericArgument::Type(arg) = &generic.args[0] {
446 let inner = parse_type(arg)?;
447 return Ok(Type::RustBox(Box::new(Ty1 {
448 name: ident,
449 langle: generic.lt_token,
450 inner,
451 rangle: generic.gt_token,
452 })));
453 }
Myron Ahneba35cf2020-02-05 19:41:51 +0700454 } else if ident == "Vec" && generic.args.len() == 1 {
455 if let GenericArgument::Type(arg) = &generic.args[0] {
456 let inner = parse_type(arg)?;
457 return Ok(Type::RustVec(Box::new(Ty1 {
458 name: ident,
459 langle: generic.lt_token,
460 inner,
461 rangle: generic.gt_token,
462 })));
463 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700464 }
465 }
466 PathArguments::Parenthesized(_) => {}
David Tolnayfb134ed2020-03-15 23:17:48 -0700467 }
David Tolnay7db73692019-10-20 14:51:12 -0400468 }
469 Err(Error::new_spanned(ty, "unsupported type"))
470}
471
David Tolnayeebe9b72020-04-14 16:32:18 -0700472fn parse_type_slice(ty: &TypeSlice) -> Result<Type> {
473 let inner = parse_type(&ty.elem)?;
474 Ok(Type::Slice(Box::new(Slice {
475 bracket: ty.bracket_token,
476 inner,
477 })))
478}
479
David Tolnayc071b892020-03-18 16:59:53 -0700480fn parse_type_fn(ty: &TypeBareFn) -> Result<Type> {
481 if ty.lifetimes.is_some() {
482 return Err(Error::new_spanned(
483 ty,
484 "function pointer with lifetime parameters is not supported yet",
485 ));
486 }
487 if ty.variadic.is_some() {
488 return Err(Error::new_spanned(
489 ty,
490 "variadic function pointer is not supported yet",
491 ));
492 }
493 let args = ty
494 .inputs
495 .iter()
496 .enumerate()
497 .map(|(i, arg)| {
498 let ty = parse_type(&arg.ty)?;
499 let ident = match &arg.name {
500 Some(ident) => ident.0.clone(),
501 None => format_ident!("_{}", i),
502 };
503 Ok(Var { ident, ty })
504 })
505 .collect::<Result<_>>()?;
David Tolnaye3a48152020-04-08 19:38:05 -0700506 let mut throws_tokens = None;
507 let ret = parse_return_type(&ty.output, &mut throws_tokens)?;
508 let throws = throws_tokens.is_some();
David Tolnayc071b892020-03-18 16:59:53 -0700509 Ok(Type::Fn(Box::new(Signature {
510 fn_token: ty.fn_token,
511 receiver: None,
512 args,
513 ret,
514 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700515 paren_token: ty.paren_token,
516 throws_tokens,
David Tolnayc071b892020-03-18 16:59:53 -0700517 })))
518}
519
David Tolnaye3a48152020-04-08 19:38:05 -0700520fn parse_return_type(
521 ty: &ReturnType,
522 throws_tokens: &mut Option<(kw::Result, Token![<], Token![>])>,
523) -> Result<Option<Type>> {
David Tolnayc071b892020-03-18 16:59:53 -0700524 let mut ret = match ty {
525 ReturnType::Default => return Ok(None),
526 ReturnType::Type(_, ret) => ret.as_ref(),
527 };
528 if let RustType::Path(ty) = ret {
529 let path = &ty.path;
530 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
531 let segment = &path.segments[0];
532 let ident = segment.ident.clone();
533 if let PathArguments::AngleBracketed(generic) = &segment.arguments {
534 if ident == "Result" && generic.args.len() == 1 {
535 if let GenericArgument::Type(arg) = &generic.args[0] {
536 ret = arg;
David Tolnaye3a48152020-04-08 19:38:05 -0700537 *throws_tokens =
538 Some((kw::Result(ident.span()), generic.lt_token, generic.gt_token));
David Tolnayc071b892020-03-18 16:59:53 -0700539 }
540 }
541 }
542 }
543 }
544 match parse_type(ret)? {
545 Type::Void(_) => Ok(None),
546 ty => Ok(Some(ty)),
547 }
548}