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}