Skip to main content

cxxbridge_macro/
lib.rs

1#![allow(
2    clippy::assert_is_empty,
3    clippy::cast_sign_loss,
4    clippy::doc_markdown,
5    clippy::elidable_lifetime_names,
6    clippy::enum_glob_use,
7    clippy::expl_impl_clone_on_copy, // https://github.com/rust-lang/rust-clippy/issues/15842
8    clippy::inherent_to_string,
9    clippy::items_after_statements,
10    clippy::match_bool,
11    clippy::match_like_matches_macro,
12    clippy::match_same_arms,
13    clippy::needless_late_init,
14    clippy::needless_lifetimes,
15    clippy::needless_pass_by_value,
16    clippy::nonminimal_bool,
17    clippy::precedence,
18    clippy::redundant_else,
19    clippy::ref_option,
20    clippy::similar_names,
21    clippy::single_match_else,
22    clippy::struct_field_names,
23    clippy::too_many_arguments,
24    clippy::too_many_lines,
25    clippy::toplevel_ref_arg,
26    clippy::uninlined_format_args,
27    clippy::wrong_self_convention
28)]
29#![cfg_attr(test, allow(dead_code, unfulfilled_lint_expectations))]
30#![allow(unknown_lints, mismatched_lifetime_syntaxes)]
31
32mod attrs;
33mod cfg;
34mod derive;
35mod expand;
36mod generics;
37mod syntax;
38#[cfg(test)]
39mod tests;
40mod tokens;
41mod type_id;
42
43use crate::syntax::file::Module;
44use crate::syntax::namespace::Namespace;
45use crate::syntax::qualified::QualifiedName;
46use crate::type_id::Crate;
47use proc_macro::TokenStream;
48use syn::parse::{Parse, ParseStream, Parser, Result};
49use syn::parse_macro_input;
50
51/// `#[cxx::bridge] mod ffi { ... }`
52///
53/// Refer to the crate-level documentation for the explanation of how this macro
54/// is intended to be used.
55///
56/// The only additional thing to note here is namespace support — if the
57/// types and functions on the `extern "C++"` side of our bridge are in a
58/// namespace, specify that namespace as an argument of the cxx::bridge
59/// attribute macro.
60///
61/// ```
62/// #[cxx::bridge(namespace = "mycompany::rust")]
63/// # mod ffi {}
64/// ```
65///
66/// The types and functions from the `extern "Rust"` side of the bridge will be
67/// placed into that same namespace in the generated C++ code.
68#[proc_macro_attribute]
69pub fn bridge(args: TokenStream, input: TokenStream) -> TokenStream {
70    let _ = syntax::error::ERRORS;
71
72    let namespace = match Namespace::parse_bridge_attr_namespace.parse(args) {
73        Ok(namespace) => namespace,
74        Err(err) => return err.to_compile_error().into(),
75    };
76    let mut ffi = parse_macro_input!(input as Module);
77    ffi.namespace = namespace;
78
79    expand::bridge(ffi)
80        .unwrap_or_else(|err| err.to_compile_error())
81        .into()
82}
83
84#[doc(hidden)]
85#[proc_macro]
86pub fn type_id(input: TokenStream) -> TokenStream {
87    struct TypeId {
88        krate: Crate,
89        path: QualifiedName,
90    }
91
92    impl Parse for TypeId {
93        fn parse(input: ParseStream) -> Result<Self> {
94            let krate = input.parse().map(Crate::DollarCrate)?;
95            let path = QualifiedName::parse_quoted_or_unquoted(input)?;
96            Ok(TypeId { krate, path })
97        }
98    }
99
100    let arg = parse_macro_input!(input as TypeId);
101    type_id::expand(arg.krate, arg.path).into()
102}