blob: be4653339b8f24afc6de5a41325a15267dcf383d [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
David Tolnay52509842020-04-25 19:38:59 -07009use self::error::{format_err, Error, Result};
David Tolnay08419302020-04-19 20:38:20 -070010use crate::syntax::namespace::Namespace;
David Tolnayb6cf3142020-04-19 20:56:09 -070011use crate::syntax::{self, check, Types};
David Tolnay7db73692019-10-20 14:51:12 -040012use quote::quote;
13use std::fs;
David Tolnay7db73692019-10-20 14:51:12 -040014use std::path::Path;
David Tolnayb6cf3142020-04-19 20:56:09 -070015use syn::{Attribute, File, Item};
David Tolnay7db73692019-10-20 14:51:12 -040016
17struct Input {
David Tolnay754e21c2020-03-29 20:58:46 -070018 namespace: Namespace,
David Tolnay7db73692019-10-20 14:51:12 -040019 module: Vec<Item>,
20}
21
David Tolnay33d30292020-03-18 18:02:02 -070022#[derive(Default)]
23pub(super) struct Opt {
24 /// Any additional headers to #include
25 pub include: Vec<String>,
26}
27
David Tolnay7ece56f2020-03-29 21:21:38 -070028pub(super) fn do_generate_bridge(path: &Path, opt: Opt) -> Vec<u8> {
David Tolnay7db73692019-10-20 14:51:12 -040029 let header = false;
David Tolnay33d30292020-03-18 18:02:02 -070030 generate(path, opt, header)
David Tolnay7db73692019-10-20 14:51:12 -040031}
32
David Tolnay7ece56f2020-03-29 21:21:38 -070033pub(super) fn do_generate_header(path: &Path, opt: Opt) -> Vec<u8> {
David Tolnay7db73692019-10-20 14:51:12 -040034 let header = true;
David Tolnay33d30292020-03-18 18:02:02 -070035 generate(path, opt, header)
David Tolnay7db73692019-10-20 14:51:12 -040036}
37
David Tolnay7ece56f2020-03-29 21:21:38 -070038fn generate(path: &Path, opt: Opt, header: bool) -> Vec<u8> {
David Tolnay7db73692019-10-20 14:51:12 -040039 let source = match fs::read_to_string(path) {
40 Ok(source) => source,
41 Err(err) => format_err(path, "", Error::Io(err)),
42 };
43 match (|| -> Result<_> {
44 let syntax = syn::parse_file(&source)?;
45 let bridge = find_bridge_mod(syntax)?;
David Tolnay9dcb8332020-04-30 20:37:33 -070046 let namespace = bridge.namespace;
David Tolnay7db73692019-10-20 14:51:12 -040047 let apis = syntax::parse_items(bridge.module)?;
48 let types = Types::collect(&apis)?;
David Tolnay9dcb8332020-04-30 20:37:33 -070049 check::typecheck(&namespace, &apis, &types)?;
50 let out = write::gen(namespace, &apis, &types, opt, header);
David Tolnay7db73692019-10-20 14:51:12 -040051 Ok(out)
52 })() {
David Tolnay7ece56f2020-03-29 21:21:38 -070053 Ok(out) => out.content(),
David Tolnay7db73692019-10-20 14:51:12 -040054 Err(err) => format_err(path, &source, err),
55 }
56}
57
58fn find_bridge_mod(syntax: File) -> Result<Input> {
59 for item in syntax.items {
60 if let Item::Mod(item) = item {
61 for attr in &item.attrs {
62 let path = &attr.path;
63 if quote!(#path).to_string() == "cxx :: bridge" {
64 let module = match item.content {
65 Some(module) => module.1,
66 None => {
67 return Err(Error::Syn(syn::Error::new_spanned(
68 item,
69 Error::OutOfLineMod,
70 )));
71 }
72 };
David Tolnayb6cf3142020-04-19 20:56:09 -070073 let namespace = parse_args(attr)?;
David Tolnay754e21c2020-03-29 20:58:46 -070074 return Ok(Input { namespace, module });
David Tolnay7db73692019-10-20 14:51:12 -040075 }
76 }
77 }
78 }
79 Err(Error::NoBridgeMod)
80}
81
David Tolnayb6cf3142020-04-19 20:56:09 -070082fn parse_args(attr: &Attribute) -> syn::Result<Namespace> {
David Tolnay7db73692019-10-20 14:51:12 -040083 if attr.tokens.is_empty() {
David Tolnayb6cf3142020-04-19 20:56:09 -070084 Ok(Namespace::none())
85 } else {
86 attr.parse_args()
David Tolnay7db73692019-10-20 14:51:12 -040087 }
David Tolnay7db73692019-10-20 14:51:12 -040088}