blob: e195081f46006a0cecca0c52f3bc45e7aeee0aeb [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 Tolnay91e87fa2020-05-11 19:10:23 -07008use proc_macro2::{TokenStream, TokenTree};
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,
David Tolnay91e87fa2020-05-11 19:10:23 -070014 GenericArgument, Ident, Item, ItemEnum, ItemForeignMod, ItemStruct, LitStr, Pat, PathArguments,
15 Result, 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 Tolnay91e87fa2020-05-11 19:10:23 -0700190 match foreign.mac.parse_body_with(parse_include) {
David Tolnay52759782020-05-03 23:59:40 -0700191 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 Tolnayc8361022020-08-25 21:57:53 -0700245 let semi_token = foreign_type.semi_token;
David Tolnay295ef6b2020-05-07 16:10:22 -0700246 let api_type = match lang {
247 Lang::Cxx => Api::CxxType,
248 Lang::Rust => Api::RustType,
249 };
250 Ok(api_type(ExternType {
David Tolnay7db73692019-10-20 14:51:12 -0400251 doc,
252 type_token,
253 ident,
David Tolnayc8361022020-08-25 21:57:53 -0700254 semi_token,
David Tolnay295ef6b2020-05-07 16:10:22 -0700255 }))
David Tolnay7db73692019-10-20 14:51:12 -0400256}
257
David Tolnay3e628882020-05-10 15:30:14 -0700258fn parse_extern_fn(cx: &mut Errors, foreign_fn: &ForeignItemFn, lang: Lang) -> Result<Api> {
David Tolnay7db73692019-10-20 14:51:12 -0400259 let generics = &foreign_fn.sig.generics;
260 if !generics.params.is_empty() || generics.where_clause.is_some() {
261 return Err(Error::new_spanned(
262 foreign_fn,
263 "extern function with generic parameters is not supported yet",
264 ));
265 }
266 if let Some(variadic) = &foreign_fn.sig.variadic {
267 return Err(Error::new_spanned(
268 variadic,
269 "variadic function is not supported yet",
270 ));
271 }
272
273 let mut receiver = None;
David Tolnaye3a48152020-04-08 19:38:05 -0700274 let mut args = Punctuated::new();
275 for arg in foreign_fn.sig.inputs.pairs() {
276 let (arg, comma) = arg.into_tuple();
David Tolnay7db73692019-10-20 14:51:12 -0400277 match arg {
David Tolnay1dd11a12020-04-22 12:31:48 -0700278 FnArg::Receiver(arg) => {
David Tolnaya1f29c42020-04-22 18:01:38 -0700279 if let Some((ampersand, lifetime)) = &arg.reference {
280 receiver = Some(Receiver {
281 ampersand: *ampersand,
282 lifetime: lifetime.clone(),
283 mutability: arg.mutability,
284 var: arg.self_token,
285 ty: Token![Self](arg.self_token.span).into(),
286 shorthand: true,
287 });
288 continue;
Joel Galensone1e969d2020-04-21 12:50:20 -0700289 }
David Tolnay1dd11a12020-04-22 12:31:48 -0700290 return Err(Error::new_spanned(arg, "unsupported signature"));
David Tolnay7db73692019-10-20 14:51:12 -0400291 }
292 FnArg::Typed(arg) => {
293 let ident = match arg.pat.as_ref() {
294 Pat::Ident(pat) => pat.ident.clone(),
Joel Galensonba676072020-04-27 15:55:45 -0700295 Pat::Wild(pat) => {
296 Ident::new(&format!("_{}", args.len()), pat.underscore_token.span)
297 }
David Tolnay7db73692019-10-20 14:51:12 -0400298 _ => return Err(Error::new_spanned(arg, "unsupported signature")),
299 };
300 let ty = parse_type(&arg.ty)?;
301 if ident != "self" {
David Tolnaye3a48152020-04-08 19:38:05 -0700302 args.push_value(Var { ident, ty });
303 if let Some(comma) = comma {
304 args.push_punct(*comma);
305 }
David Tolnay7db73692019-10-20 14:51:12 -0400306 continue;
307 }
308 if let Type::Ref(reference) = ty {
309 if let Type::Ident(ident) = reference.inner {
310 receiver = Some(Receiver {
David Tolnayfb6e3862020-04-20 01:33:23 -0700311 ampersand: reference.ampersand,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700312 lifetime: reference.lifetime,
David Tolnay7db73692019-10-20 14:51:12 -0400313 mutability: reference.mutability,
David Tolnay05e11cc2020-04-20 02:13:56 -0700314 var: Token![self](ident.span()),
315 ty: ident,
David Tolnay62d360c2020-04-22 16:26:21 -0700316 shorthand: false,
David Tolnay7db73692019-10-20 14:51:12 -0400317 });
318 continue;
319 }
320 }
321 return Err(Error::new_spanned(arg, "unsupported method receiver"));
322 }
323 }
324 }
David Tolnay59b7ede2020-03-16 00:30:23 -0700325
David Tolnaye3a48152020-04-08 19:38:05 -0700326 let mut throws_tokens = None;
327 let ret = parse_return_type(&foreign_fn.sig.output, &mut throws_tokens)?;
328 let throws = throws_tokens.is_some();
David Tolnay3e628882020-05-10 15:30:14 -0700329 let doc = attrs::parse_doc(cx, &foreign_fn.attrs);
David Tolnay7db73692019-10-20 14:51:12 -0400330 let fn_token = foreign_fn.sig.fn_token;
331 let ident = foreign_fn.sig.ident.clone();
David Tolnaye3a48152020-04-08 19:38:05 -0700332 let paren_token = foreign_fn.sig.paren_token;
David Tolnay7db73692019-10-20 14:51:12 -0400333 let semi_token = foreign_fn.semi_token;
David Tolnay295ef6b2020-05-07 16:10:22 -0700334 let api_function = match lang {
335 Lang::Cxx => Api::CxxFunction,
336 Lang::Rust => Api::RustFunction,
337 };
David Tolnayd95b1192020-03-18 20:07:46 -0700338
David Tolnay295ef6b2020-05-07 16:10:22 -0700339 Ok(api_function(ExternFn {
David Tolnay6cde49f2020-03-16 12:25:45 -0700340 lang,
David Tolnay7db73692019-10-20 14:51:12 -0400341 doc,
David Tolnay7db73692019-10-20 14:51:12 -0400342 ident,
David Tolnay16448732020-03-18 12:39:36 -0700343 sig: Signature {
344 fn_token,
345 receiver,
346 args,
347 ret,
348 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700349 paren_token,
350 throws_tokens,
David Tolnay16448732020-03-18 12:39:36 -0700351 },
David Tolnay7db73692019-10-20 14:51:12 -0400352 semi_token,
David Tolnay295ef6b2020-05-07 16:10:22 -0700353 }))
David Tolnay7db73692019-10-20 14:51:12 -0400354}
355
David Tolnay3e628882020-05-10 15:30:14 -0700356fn parse_extern_verbatim(cx: &mut Errors, tokens: &TokenStream, lang: Lang) -> Result<Api> {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700357 // type Alias = crate::path::to::Type;
David Tolnay3e628882020-05-10 15:30:14 -0700358 let parse = |input: ParseStream| -> Result<TypeAlias> {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700359 let attrs = input.call(Attribute::parse_outer)?;
360 let type_token: Token![type] = match input.parse()? {
361 Some(type_token) => type_token,
362 None => {
363 let span = input.cursor().token_stream();
364 return Err(Error::new_spanned(span, "unsupported foreign item"));
365 }
366 };
367 let ident: Ident = input.parse()?;
368 let eq_token: Token![=] = input.parse()?;
369 let ty: RustType = input.parse()?;
370 let semi_token: Token![;] = input.parse()?;
David Tolnay3e628882020-05-10 15:30:14 -0700371 attrs::parse_doc(cx, &attrs);
David Tolnaye2f9ec42020-05-07 16:19:33 -0700372
373 Ok(TypeAlias {
374 type_token,
375 ident,
376 eq_token,
377 ty,
378 semi_token,
379 })
David Tolnay3e628882020-05-10 15:30:14 -0700380 };
David Tolnaye2f9ec42020-05-07 16:19:33 -0700381
382 let type_alias = parse.parse2(tokens.clone())?;
383 match lang {
384 Lang::Cxx => Ok(Api::TypeAlias(type_alias)),
385 Lang::Rust => {
386 let (type_token, semi_token) = (type_alias.type_token, type_alias.semi_token);
387 let span = quote!(#type_token #semi_token);
388 let msg = "type alias in extern \"Rust\" block is not supported";
389 Err(Error::new_spanned(span, msg))
390 }
391 }
392}
393
David Tolnay91e87fa2020-05-11 19:10:23 -0700394fn parse_include(input: ParseStream) -> Result<String> {
395 if input.peek(LitStr) {
396 return Ok(input.parse::<LitStr>()?.value());
397 }
398
399 if input.peek(Token![<]) {
400 let mut path = String::new();
401 input.parse::<Token![<]>()?;
402 path.push('<');
403 while !input.is_empty() && !input.peek(Token![>]) {
404 let token: TokenTree = input.parse()?;
405 match token {
406 TokenTree::Ident(token) => path += &token.to_string(),
407 TokenTree::Literal(token)
408 if token
409 .to_string()
410 .starts_with(|ch: char| ch.is_ascii_digit()) =>
411 {
412 path += &token.to_string();
413 }
414 TokenTree::Punct(token) => path.push(token.as_char()),
415 _ => return Err(Error::new(token.span(), "unexpected token in include path")),
416 }
417 }
418 input.parse::<Token![>]>()?;
419 path.push('>');
420 return Ok(path);
421 }
422
423 Err(input.error("expected \"quoted/path/to\" or <bracketed/path/to>"))
424}
425
David Tolnay7db73692019-10-20 14:51:12 -0400426fn parse_type(ty: &RustType) -> Result<Type> {
David Tolnay59b7ede2020-03-16 00:30:23 -0700427 match ty {
David Tolnayb40b9db2020-03-18 13:50:31 -0700428 RustType::Reference(ty) => parse_type_reference(ty),
429 RustType::Path(ty) => parse_type_path(ty),
David Tolnayeebe9b72020-04-14 16:32:18 -0700430 RustType::Slice(ty) => parse_type_slice(ty),
David Tolnayc071b892020-03-18 16:59:53 -0700431 RustType::BareFn(ty) => parse_type_fn(ty),
David Tolnayb40b9db2020-03-18 13:50:31 -0700432 RustType::Tuple(ty) if ty.elems.is_empty() => Ok(Type::Void(ty.paren_token.span)),
433 _ => Err(Error::new_spanned(ty, "unsupported type")),
434 }
435}
436
437fn parse_type_reference(ty: &TypeReference) -> Result<Type> {
438 let inner = parse_type(&ty.elem)?;
439 let which = match &inner {
440 Type::Ident(ident) if ident == "str" => {
441 if ty.mutability.is_some() {
442 return Err(Error::new_spanned(ty, "unsupported type"));
443 } else {
444 Type::Str
David Tolnay7db73692019-10-20 14:51:12 -0400445 }
446 }
David Tolnayeebe9b72020-04-14 16:32:18 -0700447 Type::Slice(slice) => match &slice.inner {
448 Type::Ident(ident) if ident == U8 && ty.mutability.is_none() => Type::SliceRefU8,
449 _ => Type::Ref,
David Tolnayeb952ba2020-04-14 15:02:24 -0700450 },
David Tolnayb40b9db2020-03-18 13:50:31 -0700451 _ => Type::Ref,
452 };
453 Ok(which(Box::new(Ref {
454 ampersand: ty.and_token,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700455 lifetime: ty.lifetime.clone(),
David Tolnayb40b9db2020-03-18 13:50:31 -0700456 mutability: ty.mutability,
457 inner,
458 })))
459}
460
461fn parse_type_path(ty: &TypePath) -> Result<Type> {
462 let path = &ty.path;
463 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
464 let segment = &path.segments[0];
465 let ident = segment.ident.clone();
466 match &segment.arguments {
467 PathArguments::None => return Ok(Type::Ident(ident)),
468 PathArguments::AngleBracketed(generic) => {
469 if ident == "UniquePtr" && generic.args.len() == 1 {
470 if let GenericArgument::Type(arg) = &generic.args[0] {
471 let inner = parse_type(arg)?;
472 return Ok(Type::UniquePtr(Box::new(Ty1 {
473 name: ident,
474 langle: generic.lt_token,
475 inner,
476 rangle: generic.gt_token,
477 })));
478 }
David Tolnaye1dcdf72020-04-24 17:40:55 -0700479 } else if ident == "CxxVector" && generic.args.len() == 1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700480 if let GenericArgument::Type(arg) = &generic.args[0] {
481 let inner = parse_type(arg)?;
David Tolnay4377a9e2020-04-24 15:20:26 -0700482 return Ok(Type::CxxVector(Box::new(Ty1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700483 name: ident,
484 langle: generic.lt_token,
485 inner,
486 rangle: generic.gt_token,
487 })));
488 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700489 } else if ident == "Box" && generic.args.len() == 1 {
490 if let GenericArgument::Type(arg) = &generic.args[0] {
491 let inner = parse_type(arg)?;
492 return Ok(Type::RustBox(Box::new(Ty1 {
493 name: ident,
494 langle: generic.lt_token,
495 inner,
496 rangle: generic.gt_token,
497 })));
498 }
Myron Ahneba35cf2020-02-05 19:41:51 +0700499 } else if ident == "Vec" && generic.args.len() == 1 {
500 if let GenericArgument::Type(arg) = &generic.args[0] {
501 let inner = parse_type(arg)?;
502 return Ok(Type::RustVec(Box::new(Ty1 {
503 name: ident,
504 langle: generic.lt_token,
505 inner,
506 rangle: generic.gt_token,
507 })));
508 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700509 }
510 }
511 PathArguments::Parenthesized(_) => {}
David Tolnayfb134ed2020-03-15 23:17:48 -0700512 }
David Tolnay7db73692019-10-20 14:51:12 -0400513 }
514 Err(Error::new_spanned(ty, "unsupported type"))
515}
516
David Tolnayeebe9b72020-04-14 16:32:18 -0700517fn parse_type_slice(ty: &TypeSlice) -> Result<Type> {
518 let inner = parse_type(&ty.elem)?;
519 Ok(Type::Slice(Box::new(Slice {
520 bracket: ty.bracket_token,
521 inner,
522 })))
523}
524
David Tolnayc071b892020-03-18 16:59:53 -0700525fn parse_type_fn(ty: &TypeBareFn) -> Result<Type> {
526 if ty.lifetimes.is_some() {
527 return Err(Error::new_spanned(
528 ty,
529 "function pointer with lifetime parameters is not supported yet",
530 ));
531 }
532 if ty.variadic.is_some() {
533 return Err(Error::new_spanned(
534 ty,
535 "variadic function pointer is not supported yet",
536 ));
537 }
538 let args = ty
539 .inputs
540 .iter()
541 .enumerate()
542 .map(|(i, arg)| {
543 let ty = parse_type(&arg.ty)?;
544 let ident = match &arg.name {
545 Some(ident) => ident.0.clone(),
546 None => format_ident!("_{}", i),
547 };
548 Ok(Var { ident, ty })
549 })
550 .collect::<Result<_>>()?;
David Tolnaye3a48152020-04-08 19:38:05 -0700551 let mut throws_tokens = None;
552 let ret = parse_return_type(&ty.output, &mut throws_tokens)?;
553 let throws = throws_tokens.is_some();
David Tolnayc071b892020-03-18 16:59:53 -0700554 Ok(Type::Fn(Box::new(Signature {
555 fn_token: ty.fn_token,
556 receiver: None,
557 args,
558 ret,
559 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700560 paren_token: ty.paren_token,
561 throws_tokens,
David Tolnayc071b892020-03-18 16:59:53 -0700562 })))
563}
564
David Tolnaye3a48152020-04-08 19:38:05 -0700565fn parse_return_type(
566 ty: &ReturnType,
567 throws_tokens: &mut Option<(kw::Result, Token![<], Token![>])>,
568) -> Result<Option<Type>> {
David Tolnayc071b892020-03-18 16:59:53 -0700569 let mut ret = match ty {
570 ReturnType::Default => return Ok(None),
571 ReturnType::Type(_, ret) => ret.as_ref(),
572 };
573 if let RustType::Path(ty) = ret {
574 let path = &ty.path;
575 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
576 let segment = &path.segments[0];
577 let ident = segment.ident.clone();
578 if let PathArguments::AngleBracketed(generic) = &segment.arguments {
579 if ident == "Result" && generic.args.len() == 1 {
580 if let GenericArgument::Type(arg) = &generic.args[0] {
581 ret = arg;
David Tolnaye3a48152020-04-08 19:38:05 -0700582 *throws_tokens =
583 Some((kw::Result(ident.span()), generic.lt_token, generic.gt_token));
David Tolnayc071b892020-03-18 16:59:53 -0700584 }
585 }
586 }
587 }
588 }
589 match parse_type(ret)? {
590 Type::Void(_) => Ok(None),
591 ty => Ok(Some(ty)),
592 }
593}