qtbridge/
lib.rs

1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only
3
4#![doc = include_str!("../README.md")]
5
6pub mod type_support {
7    //! This module lists the types supported in qtbridge.
8    //!
9    //! ## Supported Types
10    //!
11    //! The following types are supported in [`qsignal`](crate::qsignal), [`qslot`](crate::qslot) or [`qproperty`](crate::qproperty):
12    //! - **Scalar types**: [`i8`], [`u8`], [`i16`], [`u16`], [`i32`], [`u32`], [`i64`], [`u64`], [`isize`], [`usize`], [`f32`], [`f64`].
13    //! - **String types**: [`String`] and [`&str`].
14    //! - **Collections**: [`Vec<T>`], where `T` is one of the supported scalar types or [`String`].
15}
16
17#[doc(hidden)]
18pub use qtbridge_runtime;
19pub use qtbridge_runtime::QModelItem;
20#[doc(hidden)]
21pub use qtbridge_gen;
22#[doc(hidden)]
23pub use qtbridge_interfaces;
24#[doc(hidden)]
25pub use qtbridge_type_lib;
26#[doc(hidden)]
27pub use qtbridge_build_common;
28
29/// Annotate an `impl` block to make its struct accessible from QML.
30///
31/// The macro implements a range of traits that are enable bridging from Rust
32/// to QML. The mechanism is based on the implementation of various traits with
33/// some code generated at macro expandsion time. You should not implement these
34/// traits yourself. As a user, you should only interact with:
35///
36/// * [`QObjectHolder`]
37/// * [`QmlRegister`] (only non-generic types)
38///
39/// This macro makes it possible to declare the following items within the
40/// `impl` block:
41///
42/// * signals with the [`qsignal`] attribute macro
43/// * invokable functions with the [`qslot`] attribute macro
44/// * struct properties with the [`qproperty`] macro
45///
46/// Further, it allows the struct to implement traits to fulfill specific QML purposes.
47/// These are called `Base` traits. The available base traits are:
48///
49/// * [`QListModel`] to make a `struct` accessible by QML ListView, QML Repeater, or similar.
50/// * [`QTableModel`] to make a `struct` accessible by QML TableView.
51///
52/// Only one of those traits can be implemented at the same time.
53///
54/// # Usage
55///
56/// The [`qobject_impl`] macro must be applied to a `impl` block of the
57/// target `struct`. Only a single `impl` block can be annotated with this macro and
58/// all applications of [`qsignal`], [`qslot`] and [`qproperty`] have to be limited to
59/// this block.
60///
61/// In order to communicate with QML, the macro creates briding objects that are attached
62/// to the respective structs. Therefore, objects created with [`qobject_impl`] should be
63/// created with [`default_with_attached_qobject`](QObjectHolder::default_with_attached_qobject)
64/// or expanded with [`attach_qobject`](QObjectHolder::attach_qobject). This is not necessary if
65/// the struct is instantiated in QML.
66///
67/// The macro creates, when [`register`](QmlRegister::register) is called a QML module with name
68/// matching your Cargo package name. So for a Cargo.toml with
69/// ```toml
70/// [package]
71///  name = "hello_world"
72///
73/// [dependencies]
74/// qtbridge
75/// ```
76/// the QML file has to contain
77///
78/// ```toml
79/// import hello_world
80/// ```
81///
82/// ## Requirements
83///
84/// A `struct` annotated with [`qobject_impl`] must implement the [`Default`] trait.
85/// The static function [`register`](QmlRegister::register) has to be called at the start of the
86/// main function to make this `struct` instantiable from QML.
87/// The macro implements [`Drop`] to call [`detach_qobject`](QObjectHolder::detach_qobject),
88/// cleaning up the QML parts of the object. You can implement [`Drop`] yourself when using the
89/// `NoDrop` option (see below). In that case, [`detach_qobject`](QObjectHolder::detach_qobject)
90/// has to be called manually.
91///
92/// ## Parameters
93///
94/// Parameters to adjust the macro behaviour are passed as comma-separated keywords or keyword-value pairs.
95///
96/// **Base = BaseTrait**
97///
98/// Set the 'base' trait. Requires that the specified trait is implemented for the corresponding `struct`.
99///
100/// **NoQmlElement**
101///
102/// Do not implement [`QmlRegister`]. [`QmlRegister`] registers the `struct` in the QML type system,
103/// allowing you to instantiate this type in QML. The `NoQmlElement` option can be useful to turn off
104/// instantiatability within QML or to provide a manual implementation of this trait with better control
105/// over naming and versioning.
106///
107/// **Singleton**
108///
109/// Implement [`QmlRegister`] as a [singleton](https://doc.qt.io/qt-6/qml-singleton.html). A singleton
110/// is accessed from QML as a single shared instance of the type, using the type name as identifier.
111/// This is useful for application-wide data, global settings, or service objects.
112///
113/// **NoDrop**
114///
115/// Do not implement [`Drop`] in the macro. This option has to be set when a custom [`Drop`]
116/// implementation is required. The function [`attach_qobject`](QObjectHolder::attach_qobject)
117/// has to be called manually to avoid memory leaks.
118///
119/// **LinkMe**
120///
121/// This option calls [`register`](QmlRegister::register) at application without any additional code.
122/// The crate [`Linkme`](https://crates.io/crates/linkme) is used for this purpose and needs to be
123/// added to Cargo.toml.
124///
125/// ## Example
126///
127/// ```
128/// use qtbridge::{QApp, qobject_impl};
129///
130/// #[derive(Default)]
131/// pub struct Counter {
132///    value: i32,
133/// }
134///
135/// #[qobject_impl(Singleton)]
136/// impl Counter {
137///     qproperty!("value", Member = value, Notify = "valueChanged");
138///
139///     #[qsignal]
140///     fn value_changed(&self);
141///
142///     #[qslot]
143///     fn change_value(&mut self, inc: bool) {
144///         self.value = match inc {
145///             true => self.value.saturating_add(1),
146///             false => self.value.saturating_sub(1),
147///         };
148///         self.value_changed();
149///     }
150/// }
151///
152/// const QML_CODE: &str =
153/// r#"
154///     import QtQuick
155///     import QtQuick.Controls
156///     import QtQuick.Layouts
157///     import qtbridge // must match your cargo package name
158///
159///     ApplicationWindow {
160///         visible: true
161///         title: qsTr("Counter QML app")
162/// #       Component.onCompleted: closeTimer.start()
163/// #       Timer {
164/// #           id: closeTimer
165/// #           interval: 1
166/// #           onTriggered: Qt.quit()
167/// #       }
168///         RowLayout {
169///             anchors.centerIn: parent
170///             Button {
171///                 text: "-"
172///                 onClicked: Counter.changeValue(false)
173///             }
174///             Button {
175///                 text: "+"
176///                 onClicked: Counter.changeValue(true)
177///             }
178///         }
179///     }
180/// "#;
181///
182/// fn main() {
183///     QApp::new()
184///         .register::<Counter>()
185///         .load_qml(QML_CODE.as_bytes())
186///         .run();
187/// }
188/// ```
189///
190#[doc(inline)]
191pub use qtbridge_gen::qobject_impl;
192
193/// Annotate a `mod` block to make its struct accessible from QML.
194///
195/// The mod block must contain a single `struct` and it's  `impl` blocks. The
196/// impl blocks are treated as if they had the [`qobject_impl`] annotation.
197///
198/// Similar to [`qobject_impl`], this macro implements the following traits:
199///
200/// * [`QObjectHolder`]
201/// * [`QmlRegister`] (only non-generic types)
202///
203/// and a QML module that fits the package name of your Cargo.toml.
204///
205/// This macro has the same parameters as [`qobject_impl`] and behaves the same way.
206/// In contrast to [`qobject_impl`], this macro tries to identify an existing
207/// [`Drop`] implementation and will inject [`detach_qobject`](QObjectHolder::detach_qobject)
208/// when found. If no [`Drop`] implementation is found, the macro will generate one.
209/// To surpess this injection, you can use the `NoDrop` option.
210///
211/// ## Example
212///
213/// ```
214/// use qtbridge::{QApp, qobject};
215///
216/// #[qobject(Singleton)]
217/// pub mod backend {
218///     #[derive(Default)]
219///     pub struct Counter {
220///        value: i32,
221///     }
222///
223///     impl Counter {
224///         qproperty!("value", Member = value, Notify = "valueChanged");
225///
226///         #[qsignal]
227///         fn value_changed(&self);
228///
229///         #[qslot]
230///         fn change_value(&mut self, inc: bool) {
231///             self.value = match inc {
232///                 true => self.value.saturating_add(1),
233///                 false => self.value.saturating_sub(1),
234///             };
235///             self.value_changed();
236///         }
237///     }
238/// }
239///
240/// const QML_CODE: &str =
241/// r#"
242///     import QtQuick
243///     import QtQuick.Controls
244///     import QtQuick.Layouts
245///     import qtbridge // must match your cargo package name
246///
247///     ApplicationWindow {
248///         visible: true
249///         title: qsTr("Counter QML app")
250/// #       Component.onCompleted: closeTimer.start()
251/// #       Timer {
252/// #           id: closeTimer
253/// #           interval: 1
254/// #           onTriggered: Qt.quit()
255/// #       }
256///         RowLayout {
257///             anchors.centerIn: parent
258///             Button {
259///                 text: "-"
260///                 onClicked: Counter.changeValue(false)
261///             }
262///             Button {
263///                 text: "+"
264///                 onClicked: Counter.changeValue(true)
265///             }
266///         }
267///     }
268/// "#;
269///
270/// fn main() {
271///     QApp::new()
272///         .register::<backend::Counter>()
273///         .load_qml(QML_CODE.as_bytes())
274///         .run();
275/// }
276/// ```
277#[doc(inline)]
278pub use qtbridge_gen::qobject;
279
280
281/// Annotates a function as a signal that can be handled in QML.
282///
283/// Signals can be called from Rust and the signal handler can be defined in QML. This is the
284/// recommended way to invoke QML code from Rust.
285///
286/// ### Requirements
287///
288/// - The signal must be defined within a `mod` or `impl` block, annotated with [`qobject`]
289/// or [`qobject_impl`], respectively.
290/// - The first argument of the annotated function must be `&self` or `&mut self`.
291/// - All other parameter types and the return type must be one of the
292/// [supported types][crate::type_support].
293/// - The function must not have a body (end with semicolon or have an empty curly braces).
294///
295/// ```
296/// # use qtbridge::qobject_impl;
297/// # #[derive(Default)]
298/// # pub struct Backend {
299/// # }
300/// #
301/// #[qobject_impl]
302/// impl Backend {
303///     #[qsignal]
304///     fn value_changed(&self, new_value: i32);
305///     #[qsignal]
306///     fn event_triggered(&self){}
307/// }
308/// ```
309///
310/// To receive a notification on the QML side, the object definition has to declare a signal handler named
311/// `on<Signal>`, where `<Signal>` is the name of the signal, with the first letter capitalized.
312///
313/// ```qml,ignore
314/// Backend {
315///     onValue_changed: console.log("Value changed");
316/// }
317/// ```
318/// Alternatively you can instantiate a `Connection` object with the respective signal handler.
319/// ```qml,ignore
320/// Connection {
321///     target: backend
322///     function onValue_changed() {
323///         console.log("Value changed");
324///     }
325/// }
326/// ```
327///
328/// For more details see <https://doc.qt.io/qt-6/qtqml-syntax-signals.html>
329///
330/// ### Parameters
331///
332/// ***qml_name***
333///
334/// The signal name as seen in QML. Defaults to the Rust function name.
335///
336#[doc(inline)]
337pub use qtbridge_gen::qsignal;
338
339/// Annotates a function as invokable from QML.
340///
341/// In addition to being invokable from QML, the function can also act as a slot for
342/// [signal-slot connections](#signals-and-slots) when used in Qt signal bindings.
343///
344/// ### Requirements
345///
346/// - Has to be defined within a `mod` or `impl` block, annotated with [`qobject`]
347/// or [`qobject_impl`], respectively.
348/// - The annotated function must have a body.
349/// - The first argument of the annotated function must be `&self` or `&mut self`.
350/// - All other types and the return type must be in the list of [supported types][crate::type_support].
351///
352/// ### Example
353/// ```
354/// # use qtbridge::qobject_impl;
355/// # #[derive(Default)]
356/// # pub struct Backend {
357/// #     value: i32,
358/// # }
359/// #
360/// # #[qobject_impl]
361/// # impl Backend {
362/// #[qslot]
363/// fn set_value(&mut self, new_value: i32) {
364///     self.value = new_value;
365/// }
366/// # }
367/// ```
368///
369/// ### Parameters
370///
371/// **qml_name**
372///
373/// The function name as seen from QML. Defaults to the Rust function name.
374#[doc(inline)]
375pub use qtbridge_gen::qslot;
376
377// TODO: Remove name mangling from doc snippets.
378/// Registers a property to be accessible from QML.
379///
380/// ### Requirements
381///
382/// - The property must be defined within a `mod` or `impl` block, annotated with [`qobject`]
383/// or [`qobject_impl`], respectively.
384/// - The first parameter is the property name. It must begin with a lower case letter and
385/// can only contain letters, numbers and underscores.
386/// - The property must be one of the [supported types][crate::type_support].
387/// - The return value of the getter (specified via `Read` parameter) must match the property type
388/// - The value parameter of the setter (specified via `Write` parameter) must match the property type
389/// - The member of the `struct` (specified via `Member` parameter) must match the property type
390/// - A signal indicating any property changes (specified via `Notify` parameter) needs to be
391/// emitted by the changing function
392/// - Getter and setter methods must be defined within the same `impl` block in which the property
393/// is declared.
394///
395/// A property may be **accessor-based** or **member-based** or mix of both (see the [syntax](#qproperty-syntax) section for details).
396///
397/// ### Accessor based property
398///
399/// A pure accessor-based property can be declared together with a range of functions:
400/// ```
401/// # use qtbridge::qobject_impl;
402/// # #[derive(Default)]
403/// # pub struct Backend {
404/// #     value: i32,
405/// # }
406/// #
407/// # #[qobject_impl]
408/// # impl Backend {
409/// qproperty!("myProperty", Read = get_value, Write = set_value, Notify = "myPropertyChanged");
410///
411/// pub fn get_value(&self) -> i32 { self.value }
412/// pub fn set_value(&mut self, value: i32) {
413///     self.value = value;
414///     self.my_property_changed();
415/// }
416/// #[qsignal]
417/// pub fn my_property_changed(&self);
418/// # }
419/// ```
420/// The getter method that returns the current value of the property, the setter (if provided) must
421/// take the input value of the property as its first argument (after `&mut self`).
422///
423/// ### Member based property
424///
425/// Member based properties do not require setter nor getter and Qml will directly read and write
426/// to the member. A `Notify` signal has to be provided and it has to be triggered whenever the
427/// member is changed.
428///
429/// A `struct` containing a member-based property may look like:
430/// ```
431/// # use qtbridge::qobject_impl;
432/// #[derive(Default)]
433/// struct Text {
434///     msg: String
435/// }
436///
437/// #[qobject_impl]
438/// impl Text {
439///     qproperty!("message", Member = msg, Notify = "messageChanged");
440///
441///     #[qsignal]
442///     fn message_changed(&self);
443/// }
444/// ```
445///
446/// More information about Qt properties: <https://doc.qt.io/qt-6/properties.html>.
447///
448/// ### Parameters of `qproperty!`
449///
450/// **Name**
451///
452/// The first argument is a string literal specifying the name of the Qt property.
453/// This is the name under which the property is exposed to QML and should follow the naming rules from [requirements](#requirements-2).
454///
455/// **Read**
456///
457/// Specifies the getter method for the property in the format `Read = getter_name`.
458///
459/// **Write**
460///
461/// Specifies the setter method for the property in the format `Write = setter_name`.
462///
463/// **Member**
464///
465/// Specifies the struct member variable that will be accessed if no getter or setter are provided.
466/// Expected format: `Member = var_name`.
467///
468/// **Notify**
469///
470/// Specifies the name of the signal that has to be emitted when the property changes.
471/// Expected format: `Notify = "signal_name"`.
472///
473/// **Constant**
474///
475/// A constant property is not allowed to have `Write` or `Notify` parameter.
476/// Expected as a single keyword without assignment expression.
477///
478/// **Default**
479///
480/// QML writes to the default property if a property is defined within a object but not assigned to any property.
481/// For more information see <https://doc.qt.io/qt-6/qtqml-syntax-objectattributes.html>
482///
483#[doc(inline)]
484pub use qtbridge_gen::qproperty;
485
486pub use qtbridge_runtime::{QApp, run_simple_app, qresource};
487
488/// Enable access to C++ and QML.
489///
490/// This trait is automatically implemented by  [`qobject`] and [`qobject_impl`]
491/// and should never be implemented manually.
492///
493#[doc(inline)]
494pub use qtbridge_runtime::QObjectHolder;
495
496/// QmlRegister enables QML to instantiate types of this trait.
497///
498/// The trait is usually implemented by [`qobject`] and [`qobject_impl`]. If you
499/// want to implement this trait manually, you have to add the `NoQmlElement`
500/// option.
501///
502/// [`QmlRegister`] defines the [`ELEMENT_NAME`](QmlRegister::ELEMENT_NAME)
503/// with which the `struct` can be instantiated in QML and the module name,
504/// [`URI`](QmlRegister::URI), which has to be used as import in QML to
505/// use this `struct`.
506///
507/// [`QmlRegister`] knows two ways of registering a type. The ordinary way
508/// is to register as an element that can be instantiated in QML:
509///
510/// ```
511/// # use qtbridge::qobject_impl;
512/// # #[derive(Default)]
513/// # pub struct Backend {
514/// # }
515/// #
516/// #[qobject_impl(NoQmlElement)]
517/// impl Backend {
518///     #[qslot]
519///     fn say_hello(&self) {
520///         println!("Hello World!")
521///     }
522/// }
523/// impl qtbridge::qtbridge_runtime::QmlRegister for Backend {
524///     const URI: &str = "rust_backend";
525///     const ELEMENT_NAME: &str = "Backend";
526///     const MINOR_VERSION: u8 = 0u8;
527///     const MAJOR_VERSION: u8 = 1u8;
528///     const IS_SINGLETON: bool = false;
529/// }
530/// ```
531///
532/// ```qml
533/// import rust_backend
534/// Backend {
535///     id: backend
536/// }
537/// Button {
538///     anchors.centerIn: parent
539///     text: "Hello World!"
540///     onClicked: backend.sayHello()
541/// }
542/// ```
543///
544/// Alternatively, by setting [`IS_SINGLETON`](QmlRegister::IS_SINGLETON)
545/// to true, the type is registered as a singleton. That means that only
546/// one instance can be created. It can be accessed with the
547/// [`ELEMENT_NAME`](QmlRegister::ELEMENT_NAME):
548///
549/// ```
550/// # use qtbridge::qobject_impl;
551/// # #[derive(Default)]
552/// # pub struct Backend {
553/// # }
554/// #
555/// #[qobject_impl(NoQmlElement)]
556/// impl Backend {
557///     #[qslot]
558///     fn say_hello(&self) {
559///         println!("Hello World!")
560///     }
561/// }
562/// impl qtbridge::qtbridge_runtime::QmlRegister for Backend {
563///     const URI: &str = "rust_backend";
564///     const ELEMENT_NAME: &str = "Backend";
565///     const MINOR_VERSION: u8 = 0u8;
566///     const MAJOR_VERSION: u8 = 1u8;
567///     const IS_SINGLETON: bool = true;
568/// }
569/// ```
570///
571/// ```qml
572/// import rust_backend
573/// Button {
574///     anchors.centerIn: parent
575///     text: "Hello World!"
576///     onClicked: Backend.sayHello()
577/// }
578/// ```
579///
580/// Further, [`MAJOR_VERSION`](QmlRegister::MAJOR_VERSION) and
581/// [`MINOR_VERSION`](QmlRegister::MINOR_VERSION) define the version of the
582/// QML module. These fields are mandatory but QML can load a module without
583/// specifying the version
584///
585#[doc(inline)]
586pub use qtbridge_runtime::QmlRegister;
587
588pub use qtbridge_gen::QModelItem;
589
590pub use qtbridge_gen::include_bytes_qml;
591
592pub use qtbridge_interfaces::{QListModel, QListModelBase};
593pub use qtbridge_interfaces::{QTableModel, QTableModelBase};
594
595#[doc(hidden)]
596pub use qtbridge_interfaces::{QAbstractItemModel, QAbstractItemModelBase};
597#[doc(hidden)]
598pub use qtbridge_interfaces::{QAbstractListModel, QAbstractListModelBase};