blob: 998cd14825d1fd1610a3c281b2f63ea3838dc661 [file] [log] [blame]
David Tolnay7db73692019-10-20 14:51:12 -04001// Functionality that is shared between the cxx::generate_bridge entry point and
2// the cmd.
3
4mod error;
5pub(super) mod include;
6pub(super) mod out;
7mod write;
8
9use self::error::format_err;
David Tolnay08419302020-04-19 20:38:20 -070010use crate::syntax::namespace::Namespace;
David Tolnay7db73692019-10-20 14:51:12 -040011use crate::syntax::{self, check, ident, Types};
12use quote::quote;
13use std::fs;
14use std::io;
15use std::path::Path;
16use syn::parse::ParseStream;
17use syn::{Attribute, File, Item, Token};
18use thiserror::Error;
19
20pub(super) type Result<T, E = Error> = std::result::Result<T, E>;
21
22#[derive(Error, Debug)]
23pub(super) enum Error {
24 #[error("no #[cxx::bridge] module found")]
25 NoBridgeMod,
26 #[error("#[cxx::bridge] module must have inline contents")]
27 OutOfLineMod,
28 #[error(transparent)]
29 Io(#[from] io::Error),
30 #[error(transparent)]
31 Syn(#[from] syn::Error),
32}
33
34struct Input {
David Tolnay754e21c2020-03-29 20:58:46 -070035 namespace: Namespace,
David Tolnay7db73692019-10-20 14:51:12 -040036 module: Vec<Item>,
37}
38
David Tolnay33d30292020-03-18 18:02:02 -070039#[derive(Default)]
40pub(super) struct Opt {
41 /// Any additional headers to #include
42 pub include: Vec<String>,
43}
44
David Tolnay7ece56f2020-03-29 21:21:38 -070045pub(super) fn do_generate_bridge(path: &Path, opt: Opt) -> Vec<u8> {
David Tolnay7db73692019-10-20 14:51:12 -040046 let header = false;
David Tolnay33d30292020-03-18 18:02:02 -070047 generate(path, opt, header)
David Tolnay7db73692019-10-20 14:51:12 -040048}
49
David Tolnay7ece56f2020-03-29 21:21:38 -070050pub(super) fn do_generate_header(path: &Path, opt: Opt) -> Vec<u8> {
David Tolnay7db73692019-10-20 14:51:12 -040051 let header = true;
David Tolnay33d30292020-03-18 18:02:02 -070052 generate(path, opt, header)
David Tolnay7db73692019-10-20 14:51:12 -040053}
54
David Tolnay7ece56f2020-03-29 21:21:38 -070055fn generate(path: &Path, opt: Opt, header: bool) -> Vec<u8> {
David Tolnay7db73692019-10-20 14:51:12 -040056 let source = match fs::read_to_string(path) {
57 Ok(source) => source,
58 Err(err) => format_err(path, "", Error::Io(err)),
59 };
60 match (|| -> Result<_> {
61 let syntax = syn::parse_file(&source)?;
62 let bridge = find_bridge_mod(syntax)?;
63 let apis = syntax::parse_items(bridge.module)?;
64 let types = Types::collect(&apis)?;
65 check::typecheck(&apis, &types)?;
David Tolnay33d30292020-03-18 18:02:02 -070066 let out = write::gen(bridge.namespace, &apis, &types, opt, header);
David Tolnay7db73692019-10-20 14:51:12 -040067 Ok(out)
68 })() {
David Tolnay7ece56f2020-03-29 21:21:38 -070069 Ok(out) => out.content(),
David Tolnay7db73692019-10-20 14:51:12 -040070 Err(err) => format_err(path, &source, err),
71 }
72}
73
74fn find_bridge_mod(syntax: File) -> Result<Input> {
75 for item in syntax.items {
76 if let Item::Mod(item) = item {
77 for attr in &item.attrs {
78 let path = &attr.path;
79 if quote!(#path).to_string() == "cxx :: bridge" {
80 let module = match item.content {
81 Some(module) => module.1,
82 None => {
83 return Err(Error::Syn(syn::Error::new_spanned(
84 item,
85 Error::OutOfLineMod,
86 )));
87 }
88 };
David Tolnay754e21c2020-03-29 20:58:46 -070089 let namespace_segments = parse_args(attr)?;
90 let namespace = Namespace::new(namespace_segments);
91 return Ok(Input { namespace, module });
David Tolnay7db73692019-10-20 14:51:12 -040092 }
93 }
94 }
95 }
96 Err(Error::NoBridgeMod)
97}
98
99fn parse_args(attr: &Attribute) -> syn::Result<Vec<String>> {
100 if attr.tokens.is_empty() {
101 return Ok(Vec::new());
102 }
103 attr.parse_args_with(|input: ParseStream| {
104 mod kw {
105 syn::custom_keyword!(namespace);
106 }
107 input.parse::<kw::namespace>()?;
108 input.parse::<Token![=]>()?;
109 let path = syn::Path::parse_mod_style(input)?;
110 input.parse::<Option<Token![,]>>()?;
111 path.segments
112 .into_iter()
113 .map(|seg| {
114 ident::check(&seg.ident)?;
115 Ok(seg.ident.to_string())
116 })
117 .collect()
118 })
119}