cxx_qt_macro/lib.rs
1// SPDX-FileCopyrightText: 2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
2// SPDX-FileContributor: Andrew Hayzen <andrew.hayzen@kdab.com>
3// SPDX-FileContributor: Gerhard de Clercq <gerhard.declercq@kdab.com>
4//
5// SPDX-License-Identifier: MIT OR Apache-2.0
6
7// We explicitly allow missing docs for the macros in this crate, as they should be documented in
8// cxx-qt itself.
9#![allow(missing_docs)]
10//! The cxx-qt-macro crate provides the procedural attribute macros which are used with cxx-qt.
11//!
12//! See the [cxx-qt crate docs](https://docs.rs/cxx-qt/latest/) for documentation of the macros
13//! inside this crate.
14
15use proc_macro::TokenStream;
16use syn::{parse_macro_input, ItemMod};
17
18use cxx_qt_gen::{write_rust, GeneratedRustBlocks, Parser};
19
20#[proc_macro_attribute]
21pub fn bridge(args: TokenStream, input: TokenStream) -> TokenStream {
22 // Parse the TokenStream of a macro
23 // this triggers a compile failure if the tokens fail to parse.
24 let mut module = parse_macro_input!(input as ItemMod);
25
26 // Macros do not typically need to do anything with their own attribute name,
27 // so rustc does not include that in the `args` or `input` TokenStreams.
28 //
29 // However, other code paths that use the parser do not enter from a macro invocation,
30 // so they rely on parsing the `cxx_qt::bridge` attribute to identify where to start parsing.
31 //
32 // To keep the inputs to the parser consistent for all code paths,
33 // add the attribute to the module before giving it to the parser.
34 let args_input = format!("#[cxx_qt::bridge({args})] mod dummy;");
35 let attrs = syn::parse_str::<ItemMod>(&args_input).unwrap().attrs;
36 module.attrs = attrs.into_iter().chain(module.attrs).collect();
37
38 // Extract and generate the rust code
39 extract_and_generate(module)
40}
41
42#[proc_macro_attribute]
43pub fn qobject(_args: TokenStream, _input: TokenStream) -> TokenStream {
44 unreachable!("qobject should not be used as a macro by itself. Instead it should be used within a cxx_qt::bridge definition")
45}
46
47// Take the module and C++ namespace and generate the rust code
48fn extract_and_generate(module: ItemMod) -> TokenStream {
49 Parser::from(module)
50 .and_then(|parser| GeneratedRustBlocks::from(&parser))
51 .map(|generated_rust| write_rust(&generated_rust, None))
52 .unwrap_or_else(|err| err.to_compile_error())
53 .into()
54}