cxxbridge_macro/
lib.rs

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