Skip to main content

qtbridge_gen/
lib.rs

1// Copyright (C) 2026 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only
3
4mod function_with_attributes;
5mod meta_call_check;
6mod qt_derive;
7mod qt_gen_impl;
8mod qt_resource;
9mod utils;
10
11use proc_macro::TokenStream;
12use crate::qt_gen_impl::qobject_module_builder;
13use qobject_module_builder::{LinkmeSupport, QObjectModuleBuilder};
14
15
16#[proc_macro_attribute]
17pub fn qobject(args: TokenStream, input: TokenStream) -> TokenStream {
18    // Automatic registration is enabled by the `linkme` cargo feature of qtbridge.
19    // The re-exported linkme crate is used so that user crates do not need their
20    // own dependency on it. This relies on the #[linkme(crate = ...)] attribute,
21    // which is not documented but covered by linkme's own test suite
22    // (tests/custom_linkme_path.rs). Kept separate from [`generate_qml_register`]
23    // for feature-independent testing with insta.
24    let linkme_support = match cfg!(feature = "linkme") {
25        true => LinkmeSupport::Enabled,
26        false => LinkmeSupport::Disabled,
27    };
28    let mut builder = QObjectModuleBuilder::new(linkme_support);
29    builder.build_token_stream(input.into(), args.into())
30        .unwrap_or_else(|err| err.to_compile_error())
31        .into()
32}
33
34#[proc_macro_attribute]
35pub fn qsignal(_: TokenStream, _: TokenStream) -> TokenStream {
36    // This macro does nothing but offer an entry point for Rust doc
37    panic!("#[qsignal] proc macro called outside #[qobject].")
38}
39
40#[proc_macro_attribute]
41pub fn qslot(_: TokenStream, _: TokenStream) -> TokenStream {
42    // This macro does nothing but offer an entry point for Rust doc
43    panic!("#[qslot] proc macro called outside #[qobject].")
44}
45
46#[proc_macro]
47pub fn qproperty(_: TokenStream) -> TokenStream {
48    // This macro does nothing but offer an entry point for Rust doc
49    panic!("qproperty! macro called outside #[qobject].");
50}
51
52/// Derive macro that generates a `QModelItem` implementation.
53///
54/// Applying this macro to a struct allows it to be used inside `QVec<T>`
55/// and exposed to QML, where it can be visualized with various views. The
56/// delegates within the view are able to read and write to the struct
57/// through the roles.
58///
59/// ## Roles
60/// - **Named Field Struct:** The generated roles will match the names of the
61///   fileds (e.g., `name`, `age`, …). Fields named `display`, `decoration`,
62///   `edit`, `toolTip`, `statusTip`, or `whatsThis` are recognized as default
63///   roles as used in Qt's default delegates.
64/// - **Tuple Structs:** The generated roles are `"_0"`, `"_1"`, `"_2"`, ...
65///
66/// ## Type requirements
67/// All fields must be convertible to and from `QVariant`.
68///
69/// ## Example
70/// ```rust,ignore
71/// #[derive(QModelItem)]
72/// struct Person {
73///     name: String,   // role "name"
74///     age: u32,       // role "age"
75/// }
76///
77/// #[derive(QModelItem)]
78/// struct Pair(i32, String); // roles "_0", "_1"
79/// ```
80#[proc_macro_derive(QModelItem)]
81pub fn derive_qmodelitem(input: TokenStream) -> TokenStream {
82        match qt_derive::try_derive_qmodelitem(input) {
83        Ok(ts) => ts,
84        Err(e) => e.to_compile_error().into(),
85    }
86}
87
88/// Includes a file or a directory and makes it accessible under the Qt resource system.
89///
90/// The path is resolved relative to the source file in which the macro is invoked,
91/// similarly to Rust's [include_bytes!] macro.
92///
93/// If the path refers to a directory, all files in that directory and its
94/// subdirectories are included recursively while preserving their relative paths.
95///
96/// An optional prefix can be added as a second macro parameter.
97///
98/// # Examples
99///
100/// Including a single file:
101///
102/// ```ignore
103/// fn main() {
104///     include_bytes_qml!("images/icon.png", "resources");
105/// }
106/// ```
107///
108/// Including a directory:
109///
110/// ```ignore
111/// fn main() {
112///     include_bytes_qml!("images", "resources");
113/// }
114/// ```
115///
116/// This makes the file `images/icon.png`, relative to the source file containing
117/// the macro invocation, accessible in QML as `qrc:/resources/images/icon.png`
118/// or `:/resources/images/icon.png`.
119///
120/// ```qml
121/// Image {
122///     source: "qrc:/resources/images/icon.png"
123/// }
124/// ```
125#[proc_macro]
126pub fn include_bytes_qml(input: TokenStream) -> TokenStream {
127    qt_resource::include_bytes_qml(input.into()).into()
128}