diff --git a/README.md b/README.md index c54ac32ba..175989904 100644 --- a/README.md +++ b/README.md @@ -52,11 +52,11 @@ impl From for DataSerde { } } -#[cxx_qt::bridge(namespace = "cxx_qt::my_object")] -mod my_object { - use super::DataSerde; +const DEFAULT_STR: &str = r#"{"number": 1, "string": "Hello World!"}"#; - const DEFAULT_STR: &str = r#"{"number": 1, "string": "Hello World!"}"#; +#[cxx_qt::bridge(namespace = "cxx_qt::my_object")] +mod ffi { + use super::{DataSerde, DEFAULT_STR}; #[namespace = ""] unsafe extern "C++" { @@ -85,10 +85,11 @@ mod my_object { } } + #[cxx_qt::qobject] #[derive(Default)] - pub struct RustObj; + pub struct MyObject; - impl cxx_qt::QObject { + impl cxx_qt::QObject { #[invokable] pub fn increment(&self, cpp: &mut CppObj) { cpp.set_number(cpp.number() + 1); diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index cb2428288..e6e4f6148 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -20,7 +20,7 @@ SPDX-License-Identifier: MIT OR Apache-2.0 - [QObject](./qobject/index.md) - [Macro](./qobject/macro.md) - [Data Struct](./qobject/data_struct.md) - - [RustObj Struct](./qobject/rustobj_struct.md) + - [QObject marked Struct](./qobject/qobject_struct.md) - [Cpp Object](./qobject/cpp_object.md) - [Signals enum](./qobject/signals_enum.md) - [Handlers](./qobject/handlers.md) diff --git a/book/src/concepts/bridge.md b/book/src/concepts/bridge.md index 5324b84b7..832ba515c 100644 --- a/book/src/concepts/bridge.md +++ b/book/src/concepts/bridge.md @@ -15,4 +15,4 @@ We provide [Qt types](./types.md) to help pass common data types across the brid When Rust items are exposed to C++ we automatically perform a conversion between Snake case and Camel case. So that items (such as properties and invokables) appear as Camel case to C++ but Snake case to Rust. -Note that the Rust [`RustObj`](../qobject/rustobj_struct.md) of a constructed Qt object is owned by the C++ side of the bridge representing it. So when the C++ object is destroyed the Rust object will be destroyed. In the future there will be [handlers](../qobject/handlers.md) for executing Rust code from the (de)constructor of the C++ object [https://github.com/KDAB/cxx-qt/issues/13](https://github.com/KDAB/cxx-qt/issues/13). +Note that the Rust [`QObject marked struct`](../qobject/qobject_struct.md) of a constructed Qt object is owned by the C++ side of the bridge representing it. So when the C++ object is destroyed the Rust object will be destroyed. In the future there will be [handlers](../qobject/handlers.md) for executing Rust code from the (de)constructor of the C++ object [https://github.com/KDAB/cxx-qt/issues/13](https://github.com/KDAB/cxx-qt/issues/13). diff --git a/book/src/concepts/qt.md b/book/src/concepts/qt.md index 57c68494c..3e18be64c 100644 --- a/book/src/concepts/qt.md +++ b/book/src/concepts/qt.md @@ -9,7 +9,7 @@ SPDX-License-Identifier: MIT OR Apache-2.0 ## Invokables -Invokables can be defined using the [RustObj Struct](../qobject/rustobj_struct.md), these will be exposed as methods on the C++ class with `Q_INVOKABLE` so that they are accessible for QML too. +Invokables can be defined using the [QObject Struct](../qobject/qobject_struct.md), these will be exposed as methods on the C++ class with `Q_INVOKABLE` so that they are accessible for QML too. ## Properties @@ -18,7 +18,3 @@ Properties can be defined using the [Data struct](../qobject/data_struct.md), th ## Signals Signals can be defined using the [Signals enum](../qobject/signals_enum.md), these will be exposed as `Q_SIGNALS` on the C++ class and therefore to QML as well. - -## Change events - -You can listen to property changes via the [handlers](../qobject/handlers.md) available in the RustObj Struct. These handlers are called from the Qt event loop thread to remain [thread safe](./threading.md). diff --git a/book/src/concepts/threading.md b/book/src/concepts/threading.md index 95e9c0d61..fde9abba6 100644 --- a/book/src/concepts/threading.md +++ b/book/src/concepts/threading.md @@ -25,7 +25,7 @@ We provide a solution to prevent entering deadlocks from signal connections, eg To achieve safe multi-threading on the Rust side we use an `UpdateRequester`. Where the Rust thread is started (eg an invokable) the `UpdateRequester` should be cloned into the thread. -Then when the background thread needs to update a value in the Qt object it requests an update, this is posted into the same queue as above. Once the event loop occurs this calls `UpdateRequestHandler` in the [RustObj Handlers](../qobject/handlers.md) so that you can safely call setters or emit signals from the Qt thread and synchronise your state to the foreground. +Then when the background thread needs to update a value in the Qt object it requests an update, this is posted into the same queue as above. Once the event loop occurs this calls `UpdateRequestHandler` in the [Handlers](../qobject/handlers.md) so that you can safely call setters or emit signals from the Qt thread and synchronise your state to the foreground. We recommend using a channel in the thread to send enums or values which are then processed in `UpdateRequestHandler`. diff --git a/book/src/getting-started/1-qobjects-in-rust.md b/book/src/getting-started/1-qobjects-in-rust.md index 43eb21914..cee9a13dd 100644 --- a/book/src/getting-started/1-qobjects-in-rust.md +++ b/book/src/getting-started/1-qobjects-in-rust.md @@ -33,19 +33,20 @@ Qt's design is inherently object-oriented, which is true both for C++ and QML as Therefore, in order to integrate well with Qt, Rust needs to be able to extend the Qt object system with its own QObject subclasses and instances. This is exactly what CXX-Qt allows you to do. -As Rust doesn't offer classes with inheritance and polymorphism, CXX-Qt uses a Rust module when defining new QObject subclasses. +As Rust doesn't offer classes with inheritance and polymorphism, CXX-Qt uses macros when defining new QObject subclasses. These CXX-Qt modules consist of multiple parts: - A `Data` struct - Defines which Properties will be in the QObject subclass. - Needs to implement the `Default` trait. - This data will live as properties in the C++ subclass that is generated by CXX-Qt. -- A `RustObj` struct +- A struct marked with a `#[cxx_qt::qobject]` macro + - Defines the C++ QObject subclass name - A normal Rust struct. - One struct instance is created per class instance. - Contains any Rust-only data. - Needs to implement the `Default` trait. -- The `impl` of the `RustObj` struct (optional): +- The `impl` of the `#[cxx_qt::qobject]` marked struct (optional): - Contains any Rust code. - Functions marked with `#[invokable]` will be callable from QML and C++. - The `Signal` enum @@ -54,7 +55,7 @@ These CXX-Qt modules consist of multiple parts: CXX-Qt will then expand this Rust module into two separate parts: - A C++ subclass of QObject with the same name as the module -- The Rust struct `RustObj` +- The `#[cxx_qt::qobject]` marked Rust struct
@@ -62,19 +63,19 @@ CXX-Qt will then expand this Rust module into two separate parts:
-CXX-Qt also generates the code needed for interaction of the C++ QObject subclass and the `RustObj` struct using the [CXX library](https://cxx.rs/). +CXX-Qt also generates the code needed for interaction of the C++ QObject subclass and the `#[cxx_qt::qobject]` marked struct using the [CXX library](https://cxx.rs/). For more details, see the [Concepts: Bridge](../concepts/bridge.md) page. Additionally, CXX-Qt wraps some Qt types for us, so they can be used easily by the Rust side. See the [Concepts: Qt Types](../concepts/types.md) page for the list of available types. The important take away here is the duality of any subclass generated by CXX-Qt. -These classes are made up of the actual QObject subclass instance that exists purely on the C++ side, as well as an instance of the `RustObj` struct. +These classes are made up of the actual QObject subclass instance that exists purely on the C++ side, as well as an instance of the `#[cxx_qt::qobject]` marked struct. The lifetime and GUI data is therefore managed by the QObject instance on the C++ side. Typically this will be instantiated by QML and the lifetime will be directly associated with the corresponding QML widget. Any properties declared in the `Data` struct will be stored as a member of the C++ QObject. -However, the generated QObject subclass will defer to the `RustObj` struct for any behavior, which is then defined in Rust. -The `RustObj` struct can expose additional functionality with functions marked as `#[invokable]`, which will generate a function on the C++ side that will directly call the appropriate Rust method. +However, the generated QObject subclass will defer to the `#[cxx_qt::qobject]` marked struct for any behavior, which is then defined in Rust. +The `#[cxx_qt::qobject]` marked struct can expose additional functionality with functions marked as `#[invokable]`, which will generate a function on the C++ side that will directly call the appropriate Rust method. These Rust methods can take a reference to the members of the C++ object via a wrapper called `CppObj`, so the Rust code can modify them. Now that we have taken a look the theory of it all, lets jump in and write [our first CXX-Qt module](./2-our-first-cxx-qt-module.md). diff --git a/book/src/getting-started/2-our-first-cxx-qt-module.md b/book/src/getting-started/2-our-first-cxx-qt-module.md index 4d0bffa3d..470647d0e 100644 --- a/book/src/getting-started/2-our-first-cxx-qt-module.md +++ b/book/src/getting-started/2-our-first-cxx-qt-module.md @@ -29,16 +29,15 @@ Starting with the module definition: {{#include ../../../examples/qml_minimal/src/lib.rs:book_bridge_macro}} ``` -Because we add the `#[cxx_qt::bridge(namespace = "cxx_qt::my_object")]` macro to the module definition, CXX-Qt will create a new QObject subclass from this module. -The new QObject subclass in our case will be named `MyObject`, as CXX-Qt automatically converts Rusts snake_case to the Qt default PascalCase. -CXX-Qt is all about idiomatic code in both Rust and C++, so it will do its best to keep styling consistent for C++ and Rust as well. +Because we add the `#[cxx_qt::bridge(namespace = "cxx_qt::my_object")]` macro to the module definition, +CXX-Qt will look inside the module for further macros which can define the QObject. For the `#[cxx_qt::bridge(namespace = "cxx_qt::my_object")]` macro to work, we first need to define the data that will live in the new C++ object. This is done with the `Data` struct: ```rust,ignore {{#include ../../../examples/qml_minimal/src/lib.rs:book_data_struct}} ``` -That means the newly created QObject subclass will have two properties as members: `number` and `string`. For names that contain multiple words, like `my_number`, CXX-Qt will again perform the snake_case to camelCase conversion to fit with C++/QML naming conventions. +That means the newly created QObject subclass will have two properties as members: `number` and `string`. For names that contain multiple words, like `my_number`, CXX-Qt will perform the snake_case to camelCase conversion to fit with C++/QML naming conventions. Note that the data types we use here are normal Rust data types. CXX-Qt will automatically convert these types to their C++/Qt equivalent. @@ -56,14 +55,14 @@ Now that we've defined the data that will live on the C++ side of things, let's ```rust,ignore {{#include ../../../examples/qml_minimal/src/lib.rs:book_rustobj_struct}} ``` -In our case, this is just an empty struct. -However, the `RustObj` could contain any data we want. +The name of this struct is used as the name of the C++ QObject subclass, in our case this is just an empty struct. +However, the `#[cxx_qt::qobject]` marked struct could contain any data we want. It is not converted into a C++ class, so it isn't limited to the Qt-compatible types that the `Data` struct is. -An important point to note here is that the `RustObj`, like the `Data` struct must implement the `Default` trait. -Every instance of the `MyObject` class will automatically create a corresponding `RustObj` instance by using the `Default` trait. +An important point to note here is that the `#[cxx_qt::qobject]` marked struct, like the `Data` struct must implement the `Default` trait. +Every instance of the `MyObject` class will automatically create a corresponding `#[cxx_qt::qobject]` marked struct instance by using the `Default` trait. -Just because the `RustObj` struct doesn't contain any data, that still doesn't mean its not an important part of our `MyObject` class. +Just because the `#[cxx_qt::qobject]` marked struct struct doesn't contain any data, that still doesn't mean its not an important part of our `MyObject` class. That is because it actually defines the behavior of our class through its `impl`: ```rust,ignore {{#include ../../../examples/qml_minimal/src/lib.rs:book_rustobj_impl}} @@ -80,7 +79,7 @@ In our case, we define two new functions: Both functions are marked with the `#[invokable]` macro, which means the functions will be added to the C++ code of `MyObject` and will be callable from QML as well. -Apart from functions marked with the `#[invokable]` macro, the `RustObj` impl is just a normal Rust struct impl and can contain normal Rust functions, which the invokable functions can call as usual. +Apart from functions marked with the `#[invokable]` macro, the `#[cxx_qt::qobject]` marked struct impl is just a normal Rust struct impl and can contain normal Rust functions, which the invokable functions can call as usual. And that's it. We've defined our first QObject subclass in Rust. That wasn't so hard, was it? diff --git a/book/src/qobject/cpp_object.md b/book/src/qobject/cpp_object.md index e8b209dbf..1b4c09e90 100644 --- a/book/src/qobject/cpp_object.md +++ b/book/src/qobject/cpp_object.md @@ -21,7 +21,7 @@ If the [`Data` struct](./data_struct.md) has a field called `number: i32`, then If there is a [`Signals` enum](./signals_enum.md) then you can call `emit_queued(&mut self, Signals)` or `unsafe emit_immediate(&mut self, Signals)` on the `CppObj` to emit a signal. -Note that `emit_immediate` is unsafe as it can cause deadlocks if the `Q_EMIT` is `Qt::DirectConnection` connected to a Rust invokable on the same QObject that has caused the `Q_EMIT`, as this would then try to lock the `RustObj` which is already locked. +Note that `emit_immediate` is unsafe as it can cause deadlocks if the `Q_EMIT` is `Qt::DirectConnection` connected to a Rust invokable on the same QObject that has caused the `Q_EMIT`, as this would then try to lock the internal Rust object which is already locked. ```rust,ignore,noplayground {{#include ../../../examples/qml_features/src/signals.rs:book_rust_obj_impl}} diff --git a/book/src/qobject/index.md b/book/src/qobject/index.md index 2798494ca..ee50c96e2 100644 --- a/book/src/qobject/index.md +++ b/book/src/qobject/index.md @@ -11,7 +11,7 @@ A QObject is constructed with the following parts * [A macro around the module](./macro.md) * [A Data struct defining properties](./data_struct.md) - * [A RustObj defining invokables](./rustobj_struct.md) + * [A QObject marked struct defining invokables](./qobject_struct.md) * [Cpp Object wrapper](./cpp_object.md) * [A Signals enum for defining signals](./signals_enum.md) - * [Handlers on RustObj for processing events on the Qt thread](./handlers.md) + * [Handlers for processing events on the Qt thread](./handlers.md) diff --git a/book/src/qobject/macro.md b/book/src/qobject/macro.md index b0a14b925..500694600 100644 --- a/book/src/qobject/macro.md +++ b/book/src/qobject/macro.md @@ -13,7 +13,7 @@ The namespace specified is used in C++ to allow segmenting generated code from y Note that currently each QObject needs to be in its own namespace otherwise there will be collisions from generated free functions. -The example below would export the contents of the module as `DataStructProperties` to Qt / QML. +The example below would export the struct marked with `#[cxx_qt::qobject]` as `DataStructProperties` to Qt / QML. Note that the object name needs to be unique to avoid clashes, in the future full module paths may be used to aid avoiding collisions [https://github.com/KDAB/cxx-qt/issues/19](https://github.com/KDAB/cxx-qt/issues/19) - but this doesn't prevent attempting to register two QML types with the same name. @@ -21,4 +21,4 @@ Note that the object name needs to be unique to avoid clashes, in the future ful {{#include ../../../examples/qml_features/src/data_struct_properties.rs:book_macro_code}} ``` -Note: this might change in the future to allow for defining the base class or options when exporting to QML and could become namespaced to `#[cxx_qt(QObject)]` ( [https://github.com/KDAB/cxx-qt/issues/22](https://github.com/KDAB/cxx-qt/issues/22) ). +Note: this might change in the future to allow for defining the base class or options when exporting to QML and could become namespaced to `#[cxx_qt::qobject(base = "QAbstractListModel")]` ( [https://github.com/KDAB/cxx-qt/issues/22](https://github.com/KDAB/cxx-qt/issues/22) ). diff --git a/book/src/qobject/rustobj_struct.md b/book/src/qobject/qobject_struct.md similarity index 57% rename from book/src/qobject/rustobj_struct.md rename to book/src/qobject/qobject_struct.md index a2d2c53c5..84e902c26 100644 --- a/book/src/qobject/rustobj_struct.md +++ b/book/src/qobject/qobject_struct.md @@ -5,12 +5,13 @@ SPDX-FileContributor: Andrew Hayzen SPDX-License-Identifier: MIT OR Apache-2.0 --> -# RustObj Struct +# QObject Marked Struct -The RustObj struct allows you to define the following items +The `#[cxx_qt::qobject]` marked struct allows you to define the following items + * The name of the C++ class for the QObject * Invokable methods that are exposed to Qt - * Private methods and fields for RustObj to use (eg this is useful for storing the channels for [threading](../concepts/threading.md)) + * Private methods and fields for struct to use (eg this is useful for storing the channels for [threading](../concepts/threading.md)) * Mutate C++ state with [`CppObj`](./cpp_object.md) * Implement [handlers](./handlers.md) for property or update requests @@ -20,7 +21,7 @@ The RustObj struct allows you to define the following items ## Invokables -A `impl cxx_qt::QObject` is used to define invokables, the `impl cxx_qt::QObject` defines that the methods are implemented onto the C++ QObject. +A `impl cxx_qt::QObject` is used to define invokables, the `impl cxx_qt::QObject` defines that the methods are implemented onto the C++ QObject `T`. Therefore they have access to both C++ and Rust methods. Also CXX-Qt adds wrapper code around your invokables to automatically perform any conversion between the [C++ and Rust types](../concepts/types.md). To mark a method as invokable simply add the `#[invokable]` attribute to the Rust method. This then causes `Q_INVOKABLE` to be set on the C++ definition of the method, allowing QML to call the invokable. @@ -29,8 +30,8 @@ Note to access properties on the C++ object use [Cpp Object](./cpp_object.md). ## Private Methods and Fields -Unlike the [Data Struct](./data_struct.md) fields which are defined on the `RustObj` struct are not exposed as properties to Qt. These can be considered as "private to Rust" fields, and are useful for storing channels for threading or internal information for the QObject. +Unlike the [Data Struct](./data_struct.md) fields which are defined on the `#[cxx_qt::qobject]` marked struct are not exposed as properties to Qt. These can be considered as "private to Rust" fields, and are useful for storing channels for threading or internal information for the QObject. -Methods implemented using `impl RustObj` (and not `impl cxx_qt::QObject`) are just normal Rust member methods. +Methods implemented using `impl T` (and not `impl cxx_qt::QObject`) are just normal Rust member methods. Therefore they do not have access to any C++ or QObject functionality (e.g. emitting Signals, changing properties, etc.) -You will usually only need to use `impl RustObj` if you want to also use your RustObj struct as a normal Rust struct, that is not wrapped in a QObject. +You will usually only need to use `impl T` if you want to also use your struct as a normal Rust struct, that is not wrapped in a QObject. diff --git a/book/src/qobject/signals_enum.md b/book/src/qobject/signals_enum.md index e3c9b4190..558b7d8a7 100644 --- a/book/src/qobject/signals_enum.md +++ b/book/src/qobject/signals_enum.md @@ -17,7 +17,7 @@ The `cxx_qt::signals(T)` attribute is used on an enum to define which signals sh To emit a signal from Rust use the [`CppObj`](./cpp_object.md) and call either the `emit_queued(Signal)` or `unsafe emit_immediate(Signal)` method. -Note that `emit_immediate` is unsafe as it can cause deadlocks if the `Q_EMIT` is `Qt::DirectConnection` connected to a Rust invokable on the same QObject that has caused the `Q_EMIT`, as this would then try to lock the `RustObj` which is already locked. +Note that `emit_immediate` is unsafe as it can cause deadlocks if the `Q_EMIT` is `Qt::DirectConnection` connected to a Rust invokable on the same QObject that has caused the `Q_EMIT`, as this would then try to lock the internal Rust object which is already locked. ```rust,ignore,noplayground {{#include ../../../examples/qml_features/src/signals.rs:book_rust_obj_impl}} diff --git a/cmake/CxxQt.cmake b/cmake/CxxQt.cmake index 833f95cc6..9d91cc99d 100644 --- a/cmake/CxxQt.cmake +++ b/cmake/CxxQt.cmake @@ -32,10 +32,10 @@ function(cxx_qt_generate_cpp GEN_SOURCES) endif() # TODO: figure out if RelWithDebInfo is a thing in Rust and fix accordingly if (CMAKE_BUILD_TYPE STREQUAL "Debug") - set(CARGO_CMD cargo build) + set(CARGO_CMD cargo +nightly build) set(TARGET_DIR "debug") else () - set(CARGO_CMD cargo build --release) + set(CARGO_CMD cargo +nightly build --release) set(TARGET_DIR "release") endif () @@ -89,7 +89,7 @@ function(cxx_qt_link_rustlib APP_NAME) endif () # TODO: figure out if RelWithDebInfo is a thing in Rust and fix accordingly if (CMAKE_BUILD_TYPE STREQUAL "Debug" OR NOT CMAKE_BUILD_TYPE) - set(CARGO_CMD cargo build) + set(CARGO_CMD cargo +nightly build) set(TARGET_DIR "debug") # Hack around Rust standard library linked with Release version of C runtime # Refer to https://github.com/robmikh/linkerissuerepro for explanation @@ -97,7 +97,7 @@ function(cxx_qt_link_rustlib APP_NAME) set_property(TARGET "${APP_NAME}" PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreadedDLL") endif() else () - set(CARGO_CMD cargo build --release) + set(CARGO_CMD cargo +nightly build --release) set(TARGET_DIR "release") endif () diff --git a/cxx-qt-build/Cargo.toml b/cxx-qt-build/Cargo.toml index 963e3f8d8..5dcc70372 100644 --- a/cxx-qt-build/Cargo.toml +++ b/cxx-qt-build/Cargo.toml @@ -21,4 +21,3 @@ proc-macro2 = "1.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" quote = "1.0" -convert_case = "0.4" diff --git a/cxx-qt-build/src/lib.rs b/cxx-qt-build/src/lib.rs index aa124bda9..0d2d07d2f 100644 --- a/cxx-qt-build/src/lib.rs +++ b/cxx-qt-build/src/lib.rs @@ -3,7 +3,6 @@ // SPDX-FileContributor: Gerhard de Clercq // // SPDX-License-Identifier: MIT OR Apache-2.0 -use convert_case::{Case, Casing}; use quote::ToTokens; use serde::{Deserialize, Serialize}; use std::env; @@ -50,7 +49,7 @@ fn manifest_dir() -> String { pub struct GeneratedCpp { cxx_qt: Option, cxx: cxx_gen::GeneratedCode, - module_ident: String, + file_ident: String, } impl GeneratedCpp { @@ -59,9 +58,16 @@ impl GeneratedCpp { let file = parse_qt_file(rust_file_path).unwrap(); let mut cxx_qt = None; - // TODO: later change how the resultant filename is chosen, can we match the input file like - // CXX does? - let mut module_ident: String = "".to_owned(); + // Use the Rust filename as the resultant CXX/CXX-Qt names + // + // TODO: we should consider sub directories so you can have a/b/c and a/d/c and not collide + let file_ident: String = rust_file_path + .as_ref() + .file_stem() + .unwrap() + .to_os_string() + .into_string() + .unwrap(); let mut tokens = proc_macro2::TokenStream::new(); // Add any attributes in the file into the tokenstream @@ -72,32 +78,19 @@ impl GeneratedCpp { // Loop through the items looking for any CXX or CXX-Qt blocks for item in &file.items { match item { - CxxQtItem::Cxx(m) => { - // TODO: later we will allow for multiple CXX or CXX-Qt blocks in one file - if !module_ident.is_empty() { - panic!( - "Unfortunately only files with either a single cxx or a single cxx_qt module are currently supported. - The file {} has more than one of these.", - rust_file_path.as_ref().display()); - } - - module_ident = m.ident.to_string().to_case(Case::Snake); - tokens.extend(m.into_token_stream()); - } + CxxQtItem::Cxx(m) => tokens.extend(m.into_token_stream()), CxxQtItem::CxxQt(m) => { - // TODO: later we will allow for multiple CXX or CXX-Qt blocks in one file - if !module_ident.is_empty() { + // TODO: later we will allow for multiple CXX-Qt blocks in one file + if cxx_qt.is_some() { panic!( - "Unfortunately only files with either a single cxx or a single cxx_qt module are currently supported. + "Unfortunately only files with either a single cxx_qt module are currently supported. The file {} has more than one of these.", rust_file_path.as_ref().display()); } - module_ident = m.ident.to_string().to_case(Case::Snake); - // TODO: later we will likely have cxx_qt_gen::generate_header_and_cpp // which will take a CxxQtItemMod and respond with a C++ header and source - let qobject = extract_qobject(m).unwrap(); + let qobject = extract_qobject(m, rust_file_path.as_ref().to_path_buf()).unwrap(); // TODO: we'll have to extend the C++ data here rather than overwriting // assuming we share the same file cxx_qt = Some(generate_qobject_cpp(&qobject).unwrap()); @@ -122,7 +115,7 @@ impl GeneratedCpp { GeneratedCpp { cxx_qt, cxx, - module_ident, + file_ident, } } @@ -150,7 +143,7 @@ impl GeneratedCpp { let header_path = PathBuf::from(format!( "{}/{}.cxxqt.h", include_directory_path.display(), - self.module_ident + self.file_ident )); let mut header = File::create(&header_path).expect("Could not create cxx-qt header file"); @@ -162,7 +155,7 @@ impl GeneratedCpp { let cpp_path = PathBuf::from(format!( "{}/{}.cxxqt.cpp", source_directory_path.display(), - &self.module_ident + self.file_ident )); let mut cpp = File::create(&cpp_path).expect("Could not create cxx-qt source file"); cpp.write_all(cxx_qt_generated.source.as_bytes()) @@ -173,7 +166,7 @@ impl GeneratedCpp { let header_path = PathBuf::from(format!( "{}/{}.cxx.h", include_directory_path.display(), - self.module_ident + self.file_ident )); let mut header = File::create(&header_path).expect("Could not create cxx header file"); header @@ -184,7 +177,7 @@ impl GeneratedCpp { let cpp_path = PathBuf::from(format!( "{}/{}.cxx.cpp", source_directory_path.display(), - self.module_ident + self.file_ident )); let mut cpp = File::create(&cpp_path).expect("Could not create cxx source file"); cpp.write_all(&self.cxx.implementation) diff --git a/cxx-qt-gen/src/extract.rs b/cxx-qt-gen/src/extract.rs index 43268f911..836fbd01f 100644 --- a/cxx-qt-gen/src/extract.rs +++ b/cxx-qt-gen/src/extract.rs @@ -7,7 +7,7 @@ use crate::parser::{signals::ParsedSignalsEnum, Parser}; use convert_case::{Case, Casing}; use derivative::*; use proc_macro2::{Span, TokenStream}; -use std::result::Result; +use std::{path::PathBuf, result::Result}; use syn::{spanned::Spanned, token::Brace, *}; /// Describes an ident which has a different name in C++ and Rust @@ -191,6 +191,8 @@ pub struct QObject { pub(crate) original_passthrough_decls: Vec, /// The Rust impl that has optionally been provided to handle updates pub(crate) handle_updates_impl: Option, + /// The source path that the QObject was defined in + pub(crate) source_path: PathBuf, } /// Describe the error type from extract_qt_type and extract_type_ident @@ -648,7 +650,7 @@ fn extract_signals( } /// Parses a module in order to extract a QObject description from it -pub fn extract_qobject(module: &ItemMod) -> Result { +pub fn extract_qobject(module: &ItemMod, source_path: PathBuf) -> Result { // Build a parser for the given ItemMod // // TODO: in the future steps from this extract.rs file will be moved into module parts @@ -664,7 +666,7 @@ pub fn extract_qobject(module: &ItemMod) -> Result { ) .to_compile_error()); } - let (_, qobject) = parser.cxx_qt_data.qobjects.drain().take(1).next().unwrap(); + let (qt_ident, qobject) = parser.cxx_qt_data.qobjects.drain().take(1).next().unwrap(); // Find the items from the module let original_mod = parser.passthrough_module.clone(); @@ -674,9 +676,7 @@ pub fn extract_qobject(module: &ItemMod) -> Result { // The original Data Item::Struct if one is found let original_data_struct = qobject.data_struct; // The original RustObj Item::Struct if one is found - let original_rust_struct = qobject.rust_struct; - // The name of the Qt object we are creating - let qt_ident = quote::format_ident!("{}", original_mod.ident.to_string().to_case(Case::Pascal)); + let original_rust_struct = qobject.qobject_struct; // A list of the invokables for the struct let object_invokables = qobject @@ -745,6 +745,7 @@ pub fn extract_qobject(module: &ItemMod) -> Result { .unwrap_or_else(|| syn::parse_str("pub struct RustObj;").unwrap()), original_passthrough_decls, handle_updates_impl, + source_path, }) } @@ -758,7 +759,7 @@ mod tests { fn parses_custom_default() { let source = include_str!("../test_inputs/custom_default.rs"); let module: ItemMod = syn::parse_str(source).unwrap(); - let qobject = extract_qobject(&module).unwrap(); + let qobject = extract_qobject(&module, PathBuf::from("my_object.rs")).unwrap(); // Check that it got the invokables and properties assert_eq!(qobject.invokables.len(), 0); @@ -782,7 +783,7 @@ mod tests { if let Item::Impl(trait_impl) = &qobject.original_passthrough_decls[1] { if let Type::Path(TypePath { path, .. }) = &*trait_impl.self_ty { assert_eq!(path.segments.len(), 1); - assert_eq!(path.segments[0].ident.to_string(), "RustObj"); + assert_eq!(path.segments[0].ident.to_string(), "MyObject"); } else { panic!("Trait impl was not a TypePath"); } @@ -795,12 +796,12 @@ mod tests { fn parses_invokables() { let source = include_str!("../test_inputs/invokables.rs"); let module: ItemMod = syn::parse_str(source).unwrap(); - let qobject = extract_qobject(&module).unwrap(); + let qobject = extract_qobject(&module, PathBuf::from("my_object.rs")).unwrap(); // Check that it got the names right assert_eq!(qobject.ident.to_string(), "MyObject"); - assert_eq!(qobject.original_mod.ident.to_string(), "my_object"); - assert_eq!(qobject.original_rust_struct.ident.to_string(), "RustObj"); + assert_eq!(qobject.original_mod.ident.to_string(), "ffi"); + assert_eq!(qobject.original_rust_struct.ident.to_string(), "MyObject"); // Check that it got the invokables assert_eq!(qobject.invokables.len(), 9); @@ -960,7 +961,7 @@ mod tests { fn parsing_naming() { let source = include_str!("../test_inputs/naming.rs"); let module: ItemMod = syn::parse_str(source).unwrap(); - let qobject = extract_qobject(&module).unwrap(); + let qobject = extract_qobject(&module, PathBuf::from("my_object.rs")).unwrap(); // Check that it got the properties and that the idents are correct assert_eq!(qobject.properties.len(), 1); @@ -1003,12 +1004,12 @@ mod tests { fn parses_passthrough() { let source = include_str!("../test_inputs/passthrough.rs"); let module: ItemMod = syn::parse_str(source).unwrap(); - let qobject = extract_qobject(&module).unwrap(); + let qobject = extract_qobject(&module, PathBuf::from("my_object.rs")).unwrap(); // Check that it got the names right assert_eq!(qobject.ident.to_string(), "MyObject"); - assert_eq!(qobject.original_mod.ident.to_string(), "my_object"); - assert_eq!(qobject.original_rust_struct.ident.to_string(), "RustObj"); + assert_eq!(qobject.original_mod.ident.to_string(), "ffi"); + assert_eq!(qobject.original_rust_struct.ident.to_string(), "MyObject"); // Check that it got the inovkables and properties assert_eq!(qobject.invokables.len(), 0); @@ -1026,7 +1027,7 @@ mod tests { fn parses_properties() { let source = include_str!("../test_inputs/properties.rs"); let module: ItemMod = syn::parse_str(source).unwrap(); - let qobject = extract_qobject(&module).unwrap(); + let qobject = extract_qobject(&module, PathBuf::from("my_object.rs")).unwrap(); // Check that it got the properties and that the idents are correct assert_eq!(qobject.properties.len(), 2); @@ -1081,7 +1082,7 @@ mod tests { fn parses_signals() { let source = include_str!("../test_inputs/signals.rs"); let module: ItemMod = syn::parse_str(source).unwrap(); - let qobject = extract_qobject(&module).unwrap(); + let qobject = extract_qobject(&module, PathBuf::from("my_object.rs")).unwrap(); assert_eq!(qobject.properties.len(), 0); assert_eq!(qobject.invokables.len(), 1); @@ -1133,7 +1134,7 @@ mod tests { fn parses_types_primitive_property() { let source = include_str!("../test_inputs/types_primitive_property.rs"); let module: ItemMod = syn::parse_str(source).unwrap(); - let qobject = extract_qobject(&module).unwrap(); + let qobject = extract_qobject(&module, PathBuf::from("my_object.rs")).unwrap(); // Check that it got the inovkables and properties assert_eq!(qobject.invokables.len(), 0); diff --git a/cxx-qt-gen/src/gen_cpp.rs b/cxx-qt-gen/src/gen_cpp.rs index 3bc9be644..6df42ab5f 100644 --- a/cxx-qt-gen/src/gen_cpp.rs +++ b/cxx-qt-gen/src/gen_cpp.rs @@ -1079,13 +1079,14 @@ mod tests { use crate::extract_qobject; use pretty_assertions::assert_str_eq; + use std::path::PathBuf; use syn::ItemMod; #[test] fn generates_handlers() { let source = include_str!("../test_inputs/handlers.rs"); let module: ItemMod = syn::parse_str(source).unwrap(); - let qobject = extract_qobject(&module).unwrap(); + let qobject = extract_qobject(&module, PathBuf::from("my_object.rs")).unwrap(); let expected_header = clang_format(include_str!("../test_outputs/handlers.h")).unwrap(); let expected_source = clang_format(include_str!("../test_outputs/handlers.cpp")).unwrap(); @@ -1098,7 +1099,7 @@ mod tests { fn generates_invokables() { let source = include_str!("../test_inputs/invokables.rs"); let module: ItemMod = syn::parse_str(source).unwrap(); - let qobject = extract_qobject(&module).unwrap(); + let qobject = extract_qobject(&module, PathBuf::from("my_object.rs")).unwrap(); let expected_header = clang_format(include_str!("../test_outputs/invokables.h")).unwrap(); let expected_source = clang_format(include_str!("../test_outputs/invokables.cpp")).unwrap(); @@ -1111,7 +1112,7 @@ mod tests { fn generates_naming() { let source = include_str!("../test_inputs/naming.rs"); let module: ItemMod = syn::parse_str(source).unwrap(); - let qobject = extract_qobject(&module).unwrap(); + let qobject = extract_qobject(&module, PathBuf::from("my_object.rs")).unwrap(); let expected_header = clang_format(include_str!("../test_outputs/naming.h")).unwrap(); let expected_source = clang_format(include_str!("../test_outputs/naming.cpp")).unwrap(); @@ -1124,7 +1125,7 @@ mod tests { fn generates_properties() { let source = include_str!("../test_inputs/properties.rs"); let module: ItemMod = syn::parse_str(source).unwrap(); - let qobject = extract_qobject(&module).unwrap(); + let qobject = extract_qobject(&module, PathBuf::from("my_object.rs")).unwrap(); let expected_header = clang_format(include_str!("../test_outputs/properties.h")).unwrap(); let expected_source = clang_format(include_str!("../test_outputs/properties.cpp")).unwrap(); @@ -1137,7 +1138,7 @@ mod tests { fn generates_signals() { let source = include_str!("../test_inputs/signals.rs"); let module: ItemMod = syn::parse_str(source).unwrap(); - let qobject = extract_qobject(&module).unwrap(); + let qobject = extract_qobject(&module, PathBuf::from("my_object.rs")).unwrap(); let expected_header = clang_format(include_str!("../test_outputs/signals.h")).unwrap(); let expected_source = clang_format(include_str!("../test_outputs/signals.cpp")).unwrap(); @@ -1150,7 +1151,7 @@ mod tests { fn generates_types_primitive_property() { let source = include_str!("../test_inputs/types_primitive_property.rs"); let module: ItemMod = syn::parse_str(source).unwrap(); - let qobject = extract_qobject(&module).unwrap(); + let qobject = extract_qobject(&module, PathBuf::from("my_object.rs")).unwrap(); let expected_header = clang_format(include_str!("../test_outputs/types_primitive_property.h")).unwrap(); @@ -1165,7 +1166,7 @@ mod tests { fn generates_types_qt_property() { let source = include_str!("../test_inputs/types_qt_property.rs"); let module: ItemMod = syn::parse_str(source).unwrap(); - let qobject = extract_qobject(&module).unwrap(); + let qobject = extract_qobject(&module, PathBuf::from("my_object.rs")).unwrap(); let expected_header = clang_format(include_str!("../test_outputs/types_qt_property.h")).unwrap(); @@ -1180,7 +1181,7 @@ mod tests { fn generates_types_qt_invokable() { let source = include_str!("../test_inputs/types_qt_invokable.rs"); let module: ItemMod = syn::parse_str(source).unwrap(); - let qobject = extract_qobject(&module).unwrap(); + let qobject = extract_qobject(&module, PathBuf::from("my_object.rs")).unwrap(); let expected_header = clang_format(include_str!("../test_outputs/types_qt_invokable.h")).unwrap(); diff --git a/cxx-qt-gen/src/gen_rs.rs b/cxx-qt-gen/src/gen_rs.rs index d932f54c5..91bf94508 100644 --- a/cxx-qt-gen/src/gen_rs.rs +++ b/cxx-qt-gen/src/gen_rs.rs @@ -114,12 +114,7 @@ pub fn generate_qobject_cxx(obj: &QObject) -> Result { let class_name = &obj.ident; let rust_class_name_cpp = format_ident!("{}Qt", class_name); let cxx_class_name_rust = format_ident!("{}Rust", class_name); - let rust_class_name = format_ident!("RustObj"); - - // Build a snake version of the class name, this is used for rust method names - // - // TODO: Abstract this calculation to make it common to gen_rs and gen_cpp - let ident_snake = class_name.to_string().to_case(Case::Snake); + let rust_class_name = &obj.original_rust_struct.ident; // Lists of functions we generate for the CXX bridge let mut cpp_functions = Vec::new(); @@ -356,7 +351,10 @@ pub fn generate_qobject_cxx(obj: &QObject) -> Result { }; // Build the import path for the C++ header - let import_path = format!("cxx-qt-gen/include/{}.cxxqt.h", ident_snake); + let import_path = format!( + "cxx-qt-gen/include/{}.cxxqt.h", + obj.source_path.file_stem().unwrap().to_str().unwrap() + ); let namespace = &obj.namespace; @@ -714,7 +712,7 @@ pub fn generate_qobject_rs(obj: &QObject) -> Result { let class_name = &obj.ident; // Cache the rust class name - let rust_class_name = format_ident!("RustObj"); + let rust_class_name = &obj.original_rust_struct.ident; let rust_wrapper_name = format_ident!("CppObj"); // Generate cxx block @@ -943,7 +941,7 @@ pub fn generate_qobject_rs(obj: &QObject) -> Result { #(#original_passthrough_decls)* - pub fn create_rs() -> std::boxed::Box { + pub fn create_rs() -> std::boxed::Box<#rust_class_name> { std::default::Default::default() } @@ -962,6 +960,7 @@ mod tests { use pretty_assertions::assert_str_eq; use std::{ io::Write, + path::PathBuf, process::{Command, Stdio}, }; use syn::ItemMod; @@ -994,7 +993,7 @@ mod tests { fn generates_custom_default() { let source = include_str!("../test_inputs/custom_default.rs"); let module: ItemMod = syn::parse_str(source).unwrap(); - let qobject = extract_qobject(&module).unwrap(); + let qobject = extract_qobject(&module, PathBuf::from("my_object.rs")).unwrap(); let expected_output = include_str!("../test_outputs/custom_default.rs"); let expected_output = format_rs_source(expected_output); @@ -1009,7 +1008,7 @@ mod tests { fn generates_handlers() { let source = include_str!("../test_inputs/handlers.rs"); let module: ItemMod = syn::parse_str(source).unwrap(); - let qobject = extract_qobject(&module).unwrap(); + let qobject = extract_qobject(&module, PathBuf::from("my_object.rs")).unwrap(); let expected_output = include_str!("../test_outputs/handlers.rs"); let expected_output = format_rs_source(expected_output); @@ -1024,7 +1023,7 @@ mod tests { fn generates_invokables() { let source = include_str!("../test_inputs/invokables.rs"); let module: ItemMod = syn::parse_str(source).unwrap(); - let qobject = extract_qobject(&module).unwrap(); + let qobject = extract_qobject(&module, PathBuf::from("my_object.rs")).unwrap(); let expected_output = include_str!("../test_outputs/invokables.rs"); let expected_output = format_rs_source(expected_output); @@ -1039,7 +1038,7 @@ mod tests { fn generates_naming() { let source = include_str!("../test_inputs/naming.rs"); let module: ItemMod = syn::parse_str(source).unwrap(); - let qobject = extract_qobject(&module).unwrap(); + let qobject = extract_qobject(&module, PathBuf::from("my_object.rs")).unwrap(); let expected_output = include_str!("../test_outputs/naming.rs"); let expected_output = format_rs_source(expected_output); @@ -1054,7 +1053,7 @@ mod tests { fn generates_passthrough() { let source = include_str!("../test_inputs/passthrough.rs"); let module: ItemMod = syn::parse_str(source).unwrap(); - let qobject = extract_qobject(&module).unwrap(); + let qobject = extract_qobject(&module, PathBuf::from("my_object.rs")).unwrap(); let expected_output = include_str!("../test_outputs/passthrough.rs"); let expected_output = format_rs_source(expected_output); @@ -1069,7 +1068,7 @@ mod tests { fn generates_properties() { let source = include_str!("../test_inputs/properties.rs"); let module: ItemMod = syn::parse_str(source).unwrap(); - let qobject = extract_qobject(&module).unwrap(); + let qobject = extract_qobject(&module, PathBuf::from("my_object.rs")).unwrap(); let expected_output = include_str!("../test_outputs/properties.rs"); let expected_output = format_rs_source(expected_output); @@ -1084,7 +1083,7 @@ mod tests { fn generates_signals() { let source = include_str!("../test_inputs/signals.rs"); let module: ItemMod = syn::parse_str(source).unwrap(); - let qobject = extract_qobject(&module).unwrap(); + let qobject = extract_qobject(&module, PathBuf::from("my_object.rs")).unwrap(); let expected_output = include_str!("../test_outputs/signals.rs"); let expected_output = format_rs_source(expected_output); @@ -1099,7 +1098,7 @@ mod tests { fn generates_types_primitive_property() { let source = include_str!("../test_inputs/types_primitive_property.rs"); let module: ItemMod = syn::parse_str(source).unwrap(); - let qobject = extract_qobject(&module).unwrap(); + let qobject = extract_qobject(&module, PathBuf::from("my_object.rs")).unwrap(); let expected_output = include_str!("../test_outputs/types_primitive_property.rs"); let expected_output = format_rs_source(expected_output); @@ -1114,7 +1113,7 @@ mod tests { fn generates_types_qt_property() { let source = include_str!("../test_inputs/types_qt_property.rs"); let module: ItemMod = syn::parse_str(source).unwrap(); - let qobject = extract_qobject(&module).unwrap(); + let qobject = extract_qobject(&module, PathBuf::from("my_object.rs")).unwrap(); let expected_output = include_str!("../test_outputs/types_qt_property.rs"); let expected_output = format_rs_source(expected_output); @@ -1129,7 +1128,7 @@ mod tests { fn generates_types_qt_invokable() { let source = include_str!("../test_inputs/types_qt_invokable.rs"); let module: ItemMod = syn::parse_str(source).unwrap(); - let qobject = extract_qobject(&module).unwrap(); + let qobject = extract_qobject(&module, PathBuf::from("my_object.rs")).unwrap(); let expected_output = include_str!("../test_outputs/types_qt_invokable.rs"); let expected_output = format_rs_source(expected_output); diff --git a/cxx-qt-gen/src/parser/cxxqtdata.rs b/cxx-qt-gen/src/parser/cxxqtdata.rs index 2df57b9ef..c0508ab37 100644 --- a/cxx-qt-gen/src/parser/cxxqtdata.rs +++ b/cxx-qt-gen/src/parser/cxxqtdata.rs @@ -8,7 +8,6 @@ use crate::syntax::{ attribute::{attribute_find_path, attribute_tokens_to_ident}, path::{path_angled_args_to_type_path, path_compare_str, path_to_single_ident}, }; -use quote::format_ident; use std::collections::HashMap; use syn::{ spanned::Spanned, Error, Ident, Item, ItemEnum, ItemImpl, ItemStruct, Result, Type, TypePath, @@ -29,14 +28,12 @@ impl ParsedCxxQtData { pub fn find_qobject_keys(&mut self, items: &[Item]) -> Result<()> { for item in items { if let Item::Struct(s) = item { - // TODO: instead find the cxx_qt::qobject macro - // and support multiple QObjects in one block - if s.ident == "RustObj" { + if attribute_find_path(&s.attrs, &["cxx_qt", "qobject"]).is_some() { // TODO: for now we only support one qobject per block if !self.qobjects.is_empty() { return Err(Error::new( s.span(), - "Only one RustObj struct is supported per mod", + "Only one #[cxx_qt::qobject] struct is supported per mod", )); } @@ -114,39 +111,30 @@ impl ParsedCxxQtData { } return Ok(None); } else { - // TODO: once Data, RustObj, and impl UpdateRequestHandler are removed (?) - // other items can be ignored and just returned, so this block of code below - // can be removed in the future. - // - // For now we need to find the Data, RustObj, and impl UpdateRequestHandler - if path_compare_str(path, &["Data"]) { + // TODO: Once Data and "RustObj" have been merged this can be removed + if !self.qobjects.is_empty() && path_compare_str(path, &["Data"]) { // TODO: for now we assume that Data is related to the only struct - // which is called "RustObj" + let qobject_ident = self.qobjects.keys().next().unwrap().clone(); self.qobjects - .entry(format_ident!("RustObj")) + .entry(qobject_ident) .and_modify(|qobject| qobject.others.push(Item::Impl(imp))); return Ok(None); - } else if path_compare_str(path, &["RustObj"]) { + // Find if we are an impl block for a qobject + } else if let Some(qobject) = self.qobjects.get_mut(&path_to_single_ident(path)?) { // If we are the UpdateRequestHandler, then we need to store in list + // + // TODO: once impl UpdateRequestHandler is removed this block can go if let Some(trait_) = &imp.trait_ { if let Some(first) = trait_.1.segments.first() { if first.ident == "UpdateRequestHandler" { - self.qobjects - .entry(format_ident!("RustObj")) - // We assume that there is only one impl block from the compiler - // - // TODO: later this might be removed/changed anyway - .and_modify(|qobject| { - qobject.update_requester_handler = Some(imp.clone()) - }); + // We assume that there is only one impl block from the compiler + qobject.update_requester_handler = Some(imp.clone()); return Ok(None); } } } - self.qobjects - .entry(format_ident!("RustObj")) - .and_modify(|qobject| qobject.others.push(Item::Impl(imp))); + qobject.others.push(Item::Impl(imp)); return Ok(None); } } @@ -158,35 +146,36 @@ impl ParsedCxxQtData { /// Parse a [syn::ItemStruct] into the qobjects if it's a CXX-Qt struct /// otherwise return as a [syn::Item] to pass through. fn parse_struct(&mut self, s: ItemStruct) -> Result> { - // TODO: instead check for the cxx_qt::qobject macro + // If the attribute is #[cxx_qt::qobject] then this the struct defining a qobject + if let Some(index) = attribute_find_path(&s.attrs, &["cxx_qt", "qobject"]) { + // Remove the macro from the struct + // + // TODO: we need to read the base class from the macro + let mut s = s.clone(); + s.attrs.remove(index); + + if let Some(qobject) = self.qobjects.get_mut(&s.ident) { + qobject.qobject_struct = Some(s); + return Ok(None); + } else { + return Err(Error::new( + s.span(), + "cxx_qt::qobject struct was not found by find_qobject_keys", + )); + } + } + + // TODO: for now we assume that Data is related to the only struct in the qobjects // - // // If the attribute is cxx_qt::qobject then this the struct defining a qobject - // if let Some(attr) = attribute_find_path(&s.attrs, &["cxx_qt", "qobject"]) { - // if let Some(qobject) = attribute_tokens_to_ident(attr)? { - // self - // .qobjects - // .entry(qobject) - // .and_modify(|qobject| qobject.rust_struct = Some(s.clone())); - // return Ok(None); - // } - // } + // Once Data and "RustObj" have been merged this can be removed match s.ident.to_string().as_str() { - // TODO: for now we assume that Data is related to the only struct - // which is called "RustObj" - "Data" => { + "Data" if !self.qobjects.is_empty() => { + let qobject_ident = self.qobjects.keys().next().unwrap().clone(); self.qobjects - .entry(format_ident!("RustObj")) + .entry(qobject_ident) .and_modify(|qobject| qobject.data_struct = Some(s.clone())); Ok(None) } - // TODO: for now we assume that Data is related to the only struct - // which is called "RustObj" - "RustObj" => { - self.qobjects - .entry(s.ident.clone()) - .and_modify(|qobject| qobject.rust_struct = Some(s.clone())); - Ok(None) - } _others => Ok(Some(Item::Struct(s))), } } @@ -197,13 +186,13 @@ mod tests { use super::*; use crate::tests::tokens_to_syn; - use quote::quote; + use quote::{format_ident, quote}; use syn::ItemMod; /// The QObject ident used in these tests as the ident that already /// has been found. fn qobject_ident() -> Ident { - format_ident!("RustObj") + format_ident!("MyObject") } /// Creates a ParsedCxxQtData with a QObject definition already found @@ -220,7 +209,8 @@ mod tests { let module: ItemMod = tokens_to_syn(quote! { mod module { struct Other; - struct RustObj; + #[cxx_qt::qobject] + struct MyObject; } }); let result = cxx_qt_data.find_qobject_keys(&module.content.unwrap().1); @@ -236,20 +226,37 @@ mod tests { let module: ItemMod = tokens_to_syn(quote! { mod module { struct Other; - struct RustObj; - struct RustObj; + #[cxx_qt::qobject] + struct MyObject; + #[cxx_qt::qobject] + struct MyObject; } }); let result = cxx_qt_data.find_qobject_keys(&module.content.unwrap().1); assert!(result.is_err()); } + #[test] + fn test_find_qobjects_no_macro() { + let mut cxx_qt_data = ParsedCxxQtData::default(); + + let module: ItemMod = tokens_to_syn(quote! { + mod module { + struct Other; + struct MyObject; + } + }); + let result = cxx_qt_data.find_qobject_keys(&module.content.unwrap().1); + assert!(result.is_ok()); + assert_eq!(cxx_qt_data.qobjects.len(), 0); + } + #[test] fn test_find_and_merge_cxx_qt_item_enum_valid_signals() { let mut cxx_qt_data = create_parsed_cxx_qt_data(); let item: Item = tokens_to_syn(quote! { - #[cxx_qt::signals(RustObj)] + #[cxx_qt::signals(MyObject)] enum MySignals { Ready, } @@ -318,11 +325,14 @@ mod tests { let mut cxx_qt_data = create_parsed_cxx_qt_data(); let item: Item = tokens_to_syn(quote! { - struct RustObj; + #[cxx_qt::qobject] + struct MyObject; }); let result = cxx_qt_data.parse_cxx_qt_item(item).unwrap(); assert!(result.is_none()); - assert!(cxx_qt_data.qobjects[&qobject_ident()].rust_struct.is_some()); + assert!(cxx_qt_data.qobjects[&qobject_ident()] + .qobject_struct + .is_some()); } #[test] @@ -341,7 +351,7 @@ mod tests { let mut cxx_qt_data = create_parsed_cxx_qt_data(); let item: Item = tokens_to_syn(quote! { - impl cxx_qt::QObject { + impl cxx_qt::QObject { #[invokable] fn invokable() {} @@ -401,7 +411,7 @@ mod tests { let mut cxx_qt_data = create_parsed_cxx_qt_data(); let item: Item = tokens_to_syn(quote! { - impl RustObj { + impl MyObject { fn method() {} } }); @@ -415,7 +425,7 @@ mod tests { let mut cxx_qt_data = create_parsed_cxx_qt_data(); let item: Item = tokens_to_syn(quote! { - impl UpdateRequestHandler for RustObj { + impl UpdateRequestHandler for MyObject { fn method() {} } }); diff --git a/cxx-qt-gen/src/parser/mod.rs b/cxx-qt-gen/src/parser/mod.rs index 70ccda911..baddbbc59 100644 --- a/cxx-qt-gen/src/parser/mod.rs +++ b/cxx-qt-gen/src/parser/mod.rs @@ -131,9 +131,10 @@ mod tests { let module: ItemMod = tokens_to_syn(quote! { #[cxx_qt::bridge(namespace = "cxx_qt")] mod ffi { - struct RustObj; + #[cxx_qt::qobject] + struct MyObject; - #[cxx_qt::signals(RustObj)] + #[cxx_qt::signals(MyObject)] enum MySignals { Ready, } @@ -155,9 +156,10 @@ mod tests { let module: ItemMod = tokens_to_syn(quote! { #[cxx_qt::bridge] mod ffi { - struct RustObj; + #[cxx_qt::qobject] + struct MyObject; - #[cxx_qt::signals(RustObj)] + #[cxx_qt::signals(MyObject)] enum MySignals { Ready, } @@ -183,7 +185,8 @@ mod tests { let module: ItemMod = tokens_to_syn(quote! { #[cxx_qt::bridge] mod ffi { - struct RustObj; + #[cxx_qt::qobject] + struct MyObject; #[cxx_qt::signals(UnknownObj)] enum MySignals { diff --git a/cxx-qt-gen/src/parser/qobject.rs b/cxx-qt-gen/src/parser/qobject.rs index d30e1ca60..67e8603cd 100644 --- a/cxx-qt-gen/src/parser/qobject.rs +++ b/cxx-qt-gen/src/parser/qobject.rs @@ -17,8 +17,8 @@ pub struct ParsedQObject { /// /// In the future this will be removed pub data_struct: Option, - /// RustObj struct that stores the invokables for the QObject - pub rust_struct: Option, + /// QObject struct that stores the invokables for the QObject + pub qobject_struct: Option, /// Representation of the Signals enum that defines the Q_SIGNALS for the QObject pub signals: Option, /// List of invokables that need to be implemented on the C++ object in Rust diff --git a/cxx-qt-gen/test_inputs/custom_default.rs b/cxx-qt-gen/test_inputs/custom_default.rs index 9eea0dab1..45e26e479 100644 --- a/cxx-qt-gen/test_inputs/custom_default.rs +++ b/cxx-qt-gen/test_inputs/custom_default.rs @@ -1,5 +1,5 @@ #[cxx_qt::bridge(namespace = "cxx_qt::my_object")] -mod my_object { +mod ffi { pub struct Data { public: i32, } @@ -10,11 +10,12 @@ mod my_object { } } - pub struct RustObj { + #[cxx_qt::qobject] + pub struct MyObject { private: i32, } - impl Default for RustObj { + impl Default for MyObject { fn default() -> Self { Self { private: 64 } } diff --git a/cxx-qt-gen/test_inputs/handlers.rs b/cxx-qt-gen/test_inputs/handlers.rs index 0a3624da4..8372defcf 100644 --- a/cxx-qt-gen/test_inputs/handlers.rs +++ b/cxx-qt-gen/test_inputs/handlers.rs @@ -1,5 +1,5 @@ #[cxx_qt::bridge(namespace = "cxx_qt::my_object")] -mod my_object { +mod ffi { #[namespace = ""] unsafe extern "C++" { include!("cxx-qt-lib/include/qt_types.h"); @@ -12,10 +12,11 @@ mod my_object { string: QString, } + #[cxx_qt::qobject] #[derive(Default)] - pub struct RustObj; + pub struct MyObject; - impl UpdateRequestHandler for RustObj { + impl UpdateRequestHandler for MyObject { fn handle_update_request(&mut self, _cpp: &mut CppObj) { println!("update") } diff --git a/cxx-qt-gen/test_inputs/invokables.rs b/cxx-qt-gen/test_inputs/invokables.rs index 90e21aca9..e0d8abf25 100644 --- a/cxx-qt-gen/test_inputs/invokables.rs +++ b/cxx-qt-gen/test_inputs/invokables.rs @@ -1,5 +1,5 @@ #[cxx_qt::bridge(namespace = "cxx_qt::my_object")] -mod my_object { +mod ffi { #[namespace = ""] unsafe extern "C++" { include!("cxx-qt-lib/include/qt_types.h"); @@ -8,10 +8,11 @@ mod my_object { type QString = cxx_qt_lib::QString; } + #[cxx_qt::qobject] #[derive(Default)] - pub struct RustObj; + pub struct MyObject; - impl cxx_qt::QObject { + impl cxx_qt::QObject { #[invokable] pub fn invokable(&self) { println!("invokable"); @@ -79,7 +80,7 @@ mod my_object { } } - impl RustObj { + impl MyObject { pub fn rust_only_method(&self) { println!("QML or C++ can't call this :)"); } diff --git a/cxx-qt-gen/test_inputs/naming.rs b/cxx-qt-gen/test_inputs/naming.rs index 6f512620e..c6e21addf 100644 --- a/cxx-qt-gen/test_inputs/naming.rs +++ b/cxx-qt-gen/test_inputs/naming.rs @@ -1,14 +1,15 @@ #[cxx_qt::bridge(namespace = "cxx_qt::my_object")] -mod my_object { +mod ffi { #[derive(Default)] pub struct Data { property_name: i32, } + #[cxx_qt::qobject] #[derive(Default)] - pub struct RustObj; + pub struct MyObject; - impl cxx_qt::QObject { + impl cxx_qt::QObject { #[invokable] pub fn invokable_name(&self) { println!("Bye from Rust!"); diff --git a/cxx-qt-gen/test_inputs/passthrough.rs b/cxx-qt-gen/test_inputs/passthrough.rs index a8959540c..85e48228f 100644 --- a/cxx-qt-gen/test_inputs/passthrough.rs +++ b/cxx-qt-gen/test_inputs/passthrough.rs @@ -1,7 +1,7 @@ #[attrA] #[cxx_qt::bridge(namespace = "cxx_qt::my_object")] #[attrB] -pub mod my_object { +pub mod ffi { // ItemConst const MAX: u16 = 65535; @@ -86,10 +86,11 @@ pub mod my_object { } } + #[cxx_qt::qobject] #[derive(Default)] - pub struct RustObj; + pub struct MyObject; - impl RustObj { + impl MyObject { fn test_angled(&self, optional: Option) -> Option { optional } @@ -99,7 +100,7 @@ pub mod my_object { } } - impl MyTrait for RustObj { + impl MyTrait for MyObject { fn my_func() -> String { "Hello".to_owned() } diff --git a/cxx-qt-gen/test_inputs/properties.rs b/cxx-qt-gen/test_inputs/properties.rs index 52e61a5b2..43b3b402e 100644 --- a/cxx-qt-gen/test_inputs/properties.rs +++ b/cxx-qt-gen/test_inputs/properties.rs @@ -1,5 +1,5 @@ #[cxx_qt::bridge(namespace = "cxx_qt::my_object")] -mod my_object { +mod ffi { #[namespace = ""] unsafe extern "C++" { include!("cxx-qt-lib/include/qt_types.h"); @@ -12,6 +12,7 @@ mod my_object { opaque: UniquePtr, } + #[cxx_qt::qobject] #[derive(Default)] - pub struct RustObj; + pub struct MyObject; } diff --git a/cxx-qt-gen/test_inputs/signals.rs b/cxx-qt-gen/test_inputs/signals.rs index 22d47dc02..afec33dca 100644 --- a/cxx-qt-gen/test_inputs/signals.rs +++ b/cxx-qt-gen/test_inputs/signals.rs @@ -1,5 +1,5 @@ #[cxx_qt::bridge(namespace = "cxx_qt::my_object")] -mod my_object { +mod ffi { #[namespace = ""] unsafe extern "C++" { include!("cxx-qt-lib/include/qt_types.h"); @@ -7,7 +7,7 @@ mod my_object { type QVariant = cxx_qt_lib::QVariant; } - #[cxx_qt::signals(RustObj)] + #[cxx_qt::signals(MyObject)] enum MySignals { Ready, DataChanged { @@ -20,10 +20,11 @@ mod my_object { #[derive(Default)] pub struct Data; + #[cxx_qt::qobject] #[derive(Default)] - pub struct RustObj; + pub struct MyObject; - impl cxx_qt::QObject { + impl cxx_qt::QObject { #[invokable] pub fn invokable(&self, cpp: &mut CppObj) { unsafe { diff --git a/cxx-qt-gen/test_inputs/types_primitive_property.rs b/cxx-qt-gen/test_inputs/types_primitive_property.rs index 27a813d69..9cc758704 100644 --- a/cxx-qt-gen/test_inputs/types_primitive_property.rs +++ b/cxx-qt-gen/test_inputs/types_primitive_property.rs @@ -1,5 +1,5 @@ #[cxx_qt::bridge(namespace = "cxx_qt::my_object")] -mod my_object { +mod ffi { #[derive(Default)] pub struct Data { boolean: bool, @@ -13,6 +13,7 @@ mod my_object { uint_32: u32, } + #[cxx_qt::qobject] #[derive(Default)] - pub struct RustObj; + pub struct MyObject; } diff --git a/cxx-qt-gen/test_inputs/types_qt_invokable.rs b/cxx-qt-gen/test_inputs/types_qt_invokable.rs index a368e380b..beda5de7e 100644 --- a/cxx-qt-gen/test_inputs/types_qt_invokable.rs +++ b/cxx-qt-gen/test_inputs/types_qt_invokable.rs @@ -1,5 +1,5 @@ #[cxx_qt::bridge(namespace = "cxx_qt::my_object")] -mod my_object { +mod ffi { #[namespace = ""] unsafe extern "C++" { include!("cxx-qt-lib/include/qt_types.h"); @@ -21,10 +21,11 @@ mod my_object { #[derive(Default)] pub struct Data; + #[cxx_qt::qobject] #[derive(Default)] - pub struct RustObj; + pub struct MyObject; - impl cxx_qt::QObject { + impl cxx_qt::QObject { #[invokable] pub fn test_color(&self, _cpp: &mut CppObj, color: &QColor) -> UniquePtr { color diff --git a/cxx-qt-gen/test_inputs/types_qt_property.rs b/cxx-qt-gen/test_inputs/types_qt_property.rs index 16c6a07d5..bd9d125a7 100644 --- a/cxx-qt-gen/test_inputs/types_qt_property.rs +++ b/cxx-qt-gen/test_inputs/types_qt_property.rs @@ -1,5 +1,5 @@ #[cxx_qt::bridge(namespace = "cxx_qt::my_object")] -mod my_object { +mod ffi { #[namespace = ""] unsafe extern "C++" { include!("cxx-qt-lib/include/qt_types.h"); @@ -35,6 +35,7 @@ mod my_object { variant: UniquePtr, } + #[cxx_qt::qobject] #[derive(Default)] - pub struct RustObj; + pub struct MyObject; } diff --git a/cxx-qt-gen/test_outputs/custom_default.rs b/cxx-qt-gen/test_outputs/custom_default.rs index 1e73c7115..cb0274bc6 100644 --- a/cxx-qt-gen/test_outputs/custom_default.rs +++ b/cxx-qt-gen/test_outputs/custom_default.rs @@ -1,5 +1,5 @@ #[cxx::bridge(namespace = "cxx_qt::my_object")] -mod my_object { +mod ffi { unsafe extern "C++" { include!("cxx-qt-gen/include/my_object.cxxqt.h"); @@ -12,40 +12,40 @@ mod my_object { fn setPublic(self: Pin<&mut MyObjectQt>, value: i32); #[cxx_name = "unsafe_rust"] - fn rust(self: &MyObjectQt) -> &RustObj; + fn rust(self: &MyObjectQt) -> &MyObject; #[rust_name = "new_cpp_object"] fn newCppObject() -> UniquePtr; } extern "C++" { #[cxx_name = "unsafe_rust_mut"] - unsafe fn rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut RustObj>; + unsafe fn rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut MyObject>; } extern "Rust" { #[cxx_name = "MyObjectRust"] - type RustObj; + type MyObject; #[cxx_name = "createRs"] - fn create_rs() -> Box; + fn create_rs() -> Box; #[cxx_name = "initialiseCpp"] fn initialise_cpp(cpp: Pin<&mut MyObjectQt>); } } -pub use self::cxx_qt_my_object::*; -mod cxx_qt_my_object { - use super::my_object::*; +pub use self::cxx_qt_ffi::*; +mod cxx_qt_ffi { + use super::ffi::*; - pub type FFICppObj = super::my_object::MyObjectQt; + pub type FFICppObj = super::ffi::MyObjectQt; type UniquePtr = cxx::UniquePtr; - pub struct RustObj { + pub struct MyObject { private: i32, } - impl RustObj {} + impl MyObject {} pub struct CppObj<'a> { cpp: std::pin::Pin<&'a mut FFICppObj>, @@ -93,13 +93,13 @@ mod cxx_qt_my_object { } } - impl Default for RustObj { + impl Default for MyObject { fn default() -> Self { Self { private: 64 } } } - pub fn create_rs() -> std::boxed::Box { + pub fn create_rs() -> std::boxed::Box { std::default::Default::default() } diff --git a/cxx-qt-gen/test_outputs/handlers.rs b/cxx-qt-gen/test_outputs/handlers.rs index 62af9f231..ded5fc97f 100644 --- a/cxx-qt-gen/test_outputs/handlers.rs +++ b/cxx-qt-gen/test_outputs/handlers.rs @@ -1,5 +1,5 @@ #[cxx::bridge(namespace = "cxx_qt::my_object")] -mod my_object { +mod ffi { unsafe extern "C++" { include!("cxx-qt-gen/include/my_object.cxxqt.h"); @@ -20,7 +20,7 @@ mod my_object { fn setString(self: Pin<&mut MyObjectQt>, value: &QString); #[cxx_name = "unsafe_rust"] - fn rust(self: &MyObjectQt) -> &RustObj; + fn rust(self: &MyObjectQt) -> &MyObject; #[rust_name = "new_cpp_object"] fn newCppObject() -> UniquePtr; @@ -30,21 +30,21 @@ mod my_object { extern "C++" { #[cxx_name = "unsafe_rust_mut"] - unsafe fn rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut RustObj>; + unsafe fn rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut MyObject>; } extern "Rust" { #[cxx_name = "MyObjectRust"] - type RustObj; + type MyObject; #[cxx_name = "createRs"] - fn create_rs() -> Box; + fn create_rs() -> Box; #[cxx_name = "initialiseCpp"] fn initialise_cpp(cpp: Pin<&mut MyObjectQt>); #[cxx_name = "handleUpdateRequest"] - fn call_handle_update_request(self: &mut RustObj, cpp: Pin<&mut MyObjectQt>); + fn call_handle_update_request(self: &mut MyObject, cpp: Pin<&mut MyObjectQt>); } #[namespace = ""] @@ -54,19 +54,19 @@ mod my_object { } } -pub use self::cxx_qt_my_object::*; -mod cxx_qt_my_object { - use super::my_object::*; +pub use self::cxx_qt_ffi::*; +mod cxx_qt_ffi { + use super::ffi::*; use cxx_qt_lib::UpdateRequestHandler; - pub type FFICppObj = super::my_object::MyObjectQt; + pub type FFICppObj = super::ffi::MyObjectQt; type UniquePtr = cxx::UniquePtr; #[derive(Default)] - pub struct RustObj; + pub struct MyObject; - impl RustObj { + impl MyObject { pub fn call_handle_update_request(&mut self, cpp: std::pin::Pin<&mut FFICppObj>) { let mut cpp = CppObj::new(cpp); self.handle_update_request(&mut cpp); @@ -129,13 +129,13 @@ mod cxx_qt_my_object { } } - impl UpdateRequestHandler for RustObj { + impl UpdateRequestHandler for MyObject { fn handle_update_request(&mut self, _cpp: &mut CppObj) { println!("update") } } - pub fn create_rs() -> std::boxed::Box { + pub fn create_rs() -> std::boxed::Box { std::default::Default::default() } diff --git a/cxx-qt-gen/test_outputs/invokables.rs b/cxx-qt-gen/test_outputs/invokables.rs index 6066945eb..2ebe80ffb 100644 --- a/cxx-qt-gen/test_outputs/invokables.rs +++ b/cxx-qt-gen/test_outputs/invokables.rs @@ -1,5 +1,5 @@ #[cxx::bridge(namespace = "cxx_qt::my_object")] -mod my_object { +mod ffi { unsafe extern "C++" { include!("cxx-qt-gen/include/my_object.cxxqt.h"); @@ -7,45 +7,45 @@ mod my_object { type MyObjectQt; #[cxx_name = "unsafe_rust"] - fn rust(self: &MyObjectQt) -> &RustObj; + fn rust(self: &MyObjectQt) -> &MyObject; #[rust_name = "new_cpp_object"] fn newCppObject() -> UniquePtr; } extern "C++" { #[cxx_name = "unsafe_rust_mut"] - unsafe fn rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut RustObj>; + unsafe fn rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut MyObject>; } extern "Rust" { #[cxx_name = "MyObjectRust"] - type RustObj; + type MyObject; #[cxx_name = "invokable"] - fn invokable(self: &RustObj); + fn invokable(self: &MyObject); #[cxx_name = "invokableCppObjWrapper"] - fn invokable_cpp_obj_wrapper(self: &RustObj, cpp: Pin<&mut MyObjectQt>); + fn invokable_cpp_obj_wrapper(self: &MyObject, cpp: Pin<&mut MyObjectQt>); #[cxx_name = "invokableMutable"] - fn invokable_mutable(self: &mut RustObj); + fn invokable_mutable(self: &mut MyObject); #[cxx_name = "invokableMutableCppObjWrapper"] - fn invokable_mutable_cpp_obj_wrapper(self: &mut RustObj, cpp: Pin<&mut MyObjectQt>); + fn invokable_mutable_cpp_obj_wrapper(self: &mut MyObject, cpp: Pin<&mut MyObjectQt>); #[cxx_name = "invokableParameters"] - fn invokable_parameters(self: &RustObj, opaque: &QColor, trivial: &QPoint, primitive: i32); + fn invokable_parameters(self: &MyObject, opaque: &QColor, trivial: &QPoint, primitive: i32); #[cxx_name = "invokableParametersCppObjWrapper"] fn invokable_parameters_cpp_obj_wrapper( - self: &RustObj, + self: &MyObject, primitive: i32, cpp: Pin<&mut MyObjectQt>, ); #[cxx_name = "invokableReturnOpaqueWrapper"] - fn invokable_return_opaque_wrapper(self: &mut RustObj) -> UniquePtr; + fn invokable_return_opaque_wrapper(self: &mut MyObject) -> UniquePtr; #[cxx_name = "invokableReturnPrimitive"] - fn invokable_return_primitive(self: &mut RustObj) -> i32; + fn invokable_return_primitive(self: &mut MyObject) -> i32; #[cxx_name = "invokableReturnStaticWrapper"] - fn invokable_return_static_wrapper(self: &mut RustObj) -> UniquePtr; + fn invokable_return_static_wrapper(self: &mut MyObject) -> UniquePtr; #[cxx_name = "createRs"] - fn create_rs() -> Box; + fn create_rs() -> Box; #[cxx_name = "initialiseCpp"] fn initialise_cpp(cpp: Pin<&mut MyObjectQt>); @@ -60,17 +60,17 @@ mod my_object { } } -pub use self::cxx_qt_my_object::*; -mod cxx_qt_my_object { - use super::my_object::*; +pub use self::cxx_qt_ffi::*; +mod cxx_qt_ffi { + use super::ffi::*; - pub type FFICppObj = super::my_object::MyObjectQt; + pub type FFICppObj = super::ffi::MyObjectQt; type UniquePtr = cxx::UniquePtr; #[derive(Default)] - pub struct RustObj; + pub struct MyObject; - impl RustObj { + impl MyObject { pub fn invokable_cpp_obj_wrapper(&self, cpp: std::pin::Pin<&mut FFICppObj>) { let mut cpp = CppObj::new(cpp); self.invokable_cpp_obj(&mut cpp); @@ -182,13 +182,13 @@ mod cxx_qt_my_object { } } - impl RustObj { + impl MyObject { pub fn rust_only_method(&self) { println!("QML or C++ can't call this :)"); } } - pub fn create_rs() -> std::boxed::Box { + pub fn create_rs() -> std::boxed::Box { std::default::Default::default() } diff --git a/cxx-qt-gen/test_outputs/naming.rs b/cxx-qt-gen/test_outputs/naming.rs index 4de3da52d..1ef328cc7 100644 --- a/cxx-qt-gen/test_outputs/naming.rs +++ b/cxx-qt-gen/test_outputs/naming.rs @@ -1,5 +1,5 @@ #[cxx::bridge(namespace = "cxx_qt::my_object")] -mod my_object { +mod ffi { unsafe extern "C++" { include!("cxx-qt-gen/include/my_object.cxxqt.h"); @@ -12,42 +12,42 @@ mod my_object { fn setPropertyName(self: Pin<&mut MyObjectQt>, value: i32); #[cxx_name = "unsafe_rust"] - fn rust(self: &MyObjectQt) -> &RustObj; + fn rust(self: &MyObjectQt) -> &MyObject; #[rust_name = "new_cpp_object"] fn newCppObject() -> UniquePtr; } extern "C++" { #[cxx_name = "unsafe_rust_mut"] - unsafe fn rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut RustObj>; + unsafe fn rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut MyObject>; } extern "Rust" { #[cxx_name = "MyObjectRust"] - type RustObj; + type MyObject; #[cxx_name = "invokableName"] - fn invokable_name(self: &RustObj); + fn invokable_name(self: &MyObject); #[cxx_name = "createRs"] - fn create_rs() -> Box; + fn create_rs() -> Box; #[cxx_name = "initialiseCpp"] fn initialise_cpp(cpp: Pin<&mut MyObjectQt>); } } -pub use self::cxx_qt_my_object::*; -mod cxx_qt_my_object { - use super::my_object::*; +pub use self::cxx_qt_ffi::*; +mod cxx_qt_ffi { + use super::ffi::*; - pub type FFICppObj = super::my_object::MyObjectQt; + pub type FFICppObj = super::ffi::MyObjectQt; type UniquePtr = cxx::UniquePtr; #[derive(Default)] - pub struct RustObj; + pub struct MyObject; - impl RustObj { + impl MyObject { pub fn invokable_name(&self) { println!("Bye from Rust!"); } @@ -94,7 +94,7 @@ mod cxx_qt_my_object { } } - pub fn create_rs() -> std::boxed::Box { + pub fn create_rs() -> std::boxed::Box { std::default::Default::default() } diff --git a/cxx-qt-gen/test_outputs/passthrough.rs b/cxx-qt-gen/test_outputs/passthrough.rs index 3b6abb2e7..5356c16fd 100644 --- a/cxx-qt-gen/test_outputs/passthrough.rs +++ b/cxx-qt-gen/test_outputs/passthrough.rs @@ -1,5 +1,5 @@ #[cxx::bridge(namespace = "cxx_qt::my_object")] -pub mod my_object { +pub mod ffi { unsafe extern "C++" { include!("cxx-qt-gen/include/my_object.cxxqt.h"); @@ -12,22 +12,22 @@ pub mod my_object { fn setNumber(self: Pin<&mut MyObjectQt>, value: i32); #[cxx_name = "unsafe_rust"] - fn rust(self: &MyObjectQt) -> &RustObj; + fn rust(self: &MyObjectQt) -> &MyObject; #[rust_name = "new_cpp_object"] fn newCppObject() -> UniquePtr; } extern "C++" { #[cxx_name = "unsafe_rust_mut"] - unsafe fn rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut RustObj>; + unsafe fn rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut MyObject>; } extern "Rust" { #[cxx_name = "MyObjectRust"] - type RustObj; + type MyObject; #[cxx_name = "createRs"] - fn create_rs() -> Box; + fn create_rs() -> Box; #[cxx_name = "initialiseCpp"] fn initialise_cpp(cpp: Pin<&mut MyObjectQt>); @@ -91,19 +91,19 @@ pub mod my_object { } } -pub use self::cxx_qt_my_object::*; +pub use self::cxx_qt_ffi::*; #[attrA] #[attrB] -pub mod cxx_qt_my_object { - use super::my_object::*; +pub mod cxx_qt_ffi { + use super::ffi::*; - pub type FFICppObj = super::my_object::MyObjectQt; + pub type FFICppObj = super::ffi::MyObjectQt; type UniquePtr = cxx::UniquePtr; #[derive(Default)] - pub struct RustObj; + pub struct MyObject; - impl RustObj {} + impl MyObject {} pub struct CppObj<'a> { cpp: std::pin::Pin<&'a mut FFICppObj>, @@ -154,7 +154,7 @@ pub mod cxx_qt_my_object { } } - impl RustObj { + impl MyObject { fn test_angled(&self, optional: Option) -> Option { optional } @@ -164,13 +164,13 @@ pub mod cxx_qt_my_object { } } - impl MyTrait for RustObj { + impl MyTrait for MyObject { fn my_func() -> String { "Hello".to_owned() } } - pub fn create_rs() -> std::boxed::Box { + pub fn create_rs() -> std::boxed::Box { std::default::Default::default() } diff --git a/cxx-qt-gen/test_outputs/properties.rs b/cxx-qt-gen/test_outputs/properties.rs index 162b5b9ef..6cbda66cc 100644 --- a/cxx-qt-gen/test_outputs/properties.rs +++ b/cxx-qt-gen/test_outputs/properties.rs @@ -1,5 +1,5 @@ #[cxx::bridge(namespace = "cxx_qt::my_object")] -mod my_object { +mod ffi { unsafe extern "C++" { include!("cxx-qt-gen/include/my_object.cxxqt.h"); @@ -17,22 +17,22 @@ mod my_object { fn setOpaque(self: Pin<&mut MyObjectQt>, value: &QColor); #[cxx_name = "unsafe_rust"] - fn rust(self: &MyObjectQt) -> &RustObj; + fn rust(self: &MyObjectQt) -> &MyObject; #[rust_name = "new_cpp_object"] fn newCppObject() -> UniquePtr; } extern "C++" { #[cxx_name = "unsafe_rust_mut"] - unsafe fn rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut RustObj>; + unsafe fn rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut MyObject>; } extern "Rust" { #[cxx_name = "MyObjectRust"] - type RustObj; + type MyObject; #[cxx_name = "createRs"] - fn create_rs() -> Box; + fn create_rs() -> Box; #[cxx_name = "initialiseCpp"] fn initialise_cpp(cpp: Pin<&mut MyObjectQt>); @@ -45,17 +45,17 @@ mod my_object { } } -pub use self::cxx_qt_my_object::*; -mod cxx_qt_my_object { - use super::my_object::*; +pub use self::cxx_qt_ffi::*; +mod cxx_qt_ffi { + use super::ffi::*; - pub type FFICppObj = super::my_object::MyObjectQt; + pub type FFICppObj = super::ffi::MyObjectQt; type UniquePtr = cxx::UniquePtr; #[derive(Default)] - pub struct RustObj; + pub struct MyObject; - impl RustObj {} + impl MyObject {} pub struct CppObj<'a> { cpp: std::pin::Pin<&'a mut FFICppObj>, @@ -109,7 +109,7 @@ mod cxx_qt_my_object { } } - pub fn create_rs() -> std::boxed::Box { + pub fn create_rs() -> std::boxed::Box { std::default::Default::default() } diff --git a/cxx-qt-gen/test_outputs/signals.rs b/cxx-qt-gen/test_outputs/signals.rs index 848a25147..4a445e44a 100644 --- a/cxx-qt-gen/test_outputs/signals.rs +++ b/cxx-qt-gen/test_outputs/signals.rs @@ -1,5 +1,5 @@ #[cxx::bridge(namespace = "cxx_qt::my_object")] -mod my_object { +mod ffi { unsafe extern "C++" { include!("cxx-qt-gen/include/my_object.cxxqt.h"); @@ -22,25 +22,25 @@ mod my_object { ); #[cxx_name = "unsafe_rust"] - fn rust(self: &MyObjectQt) -> &RustObj; + fn rust(self: &MyObjectQt) -> &MyObject; #[rust_name = "new_cpp_object"] fn newCppObject() -> UniquePtr; } extern "C++" { #[cxx_name = "unsafe_rust_mut"] - unsafe fn rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut RustObj>; + unsafe fn rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut MyObject>; } extern "Rust" { #[cxx_name = "MyObjectRust"] - type RustObj; + type MyObject; #[cxx_name = "invokableWrapper"] - fn invokable_wrapper(self: &RustObj, cpp: Pin<&mut MyObjectQt>); + fn invokable_wrapper(self: &MyObject, cpp: Pin<&mut MyObjectQt>); #[cxx_name = "createRs"] - fn create_rs() -> Box; + fn create_rs() -> Box; #[cxx_name = "initialiseCpp"] fn initialise_cpp(cpp: Pin<&mut MyObjectQt>); @@ -54,11 +54,11 @@ mod my_object { } } -pub use self::cxx_qt_my_object::*; -mod cxx_qt_my_object { - use super::my_object::*; +pub use self::cxx_qt_ffi::*; +mod cxx_qt_ffi { + use super::ffi::*; - pub type FFICppObj = super::my_object::MyObjectQt; + pub type FFICppObj = super::ffi::MyObjectQt; type UniquePtr = cxx::UniquePtr; enum MySignals { @@ -71,9 +71,9 @@ mod cxx_qt_my_object { } #[derive(Default)] - pub struct RustObj; + pub struct MyObject; - impl RustObj { + impl MyObject { pub fn invokable_wrapper(&self, cpp: std::pin::Pin<&mut FFICppObj>) { let mut cpp = CppObj::new(cpp); self.invokable(&mut cpp); @@ -141,7 +141,7 @@ mod cxx_qt_my_object { } } - pub fn create_rs() -> std::boxed::Box { + pub fn create_rs() -> std::boxed::Box { std::default::Default::default() } diff --git a/cxx-qt-gen/test_outputs/types_primitive_property.rs b/cxx-qt-gen/test_outputs/types_primitive_property.rs index 3cb60f3c2..184bc7b3e 100644 --- a/cxx-qt-gen/test_outputs/types_primitive_property.rs +++ b/cxx-qt-gen/test_outputs/types_primitive_property.rs @@ -1,5 +1,5 @@ #[cxx::bridge(namespace = "cxx_qt::my_object")] -mod my_object { +mod ffi { unsafe extern "C++" { include!("cxx-qt-gen/include/my_object.cxxqt.h"); @@ -52,39 +52,39 @@ mod my_object { fn setUint32(self: Pin<&mut MyObjectQt>, value: u32); #[cxx_name = "unsafe_rust"] - fn rust(self: &MyObjectQt) -> &RustObj; + fn rust(self: &MyObjectQt) -> &MyObject; #[rust_name = "new_cpp_object"] fn newCppObject() -> UniquePtr; } extern "C++" { #[cxx_name = "unsafe_rust_mut"] - unsafe fn rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut RustObj>; + unsafe fn rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut MyObject>; } extern "Rust" { #[cxx_name = "MyObjectRust"] - type RustObj; + type MyObject; #[cxx_name = "createRs"] - fn create_rs() -> Box; + fn create_rs() -> Box; #[cxx_name = "initialiseCpp"] fn initialise_cpp(cpp: Pin<&mut MyObjectQt>); } } -pub use self::cxx_qt_my_object::*; -mod cxx_qt_my_object { - use super::my_object::*; +pub use self::cxx_qt_ffi::*; +mod cxx_qt_ffi { + use super::ffi::*; - pub type FFICppObj = super::my_object::MyObjectQt; + pub type FFICppObj = super::ffi::MyObjectQt; type UniquePtr = cxx::UniquePtr; #[derive(Default)] - pub struct RustObj; + pub struct MyObject; - impl RustObj {} + impl MyObject {} pub struct CppObj<'a> { cpp: std::pin::Pin<&'a mut FFICppObj>, @@ -215,7 +215,7 @@ mod cxx_qt_my_object { } } - pub fn create_rs() -> std::boxed::Box { + pub fn create_rs() -> std::boxed::Box { std::default::Default::default() } diff --git a/cxx-qt-gen/test_outputs/types_qt_invokable.rs b/cxx-qt-gen/test_outputs/types_qt_invokable.rs index dc9cbdfc3..3a2a1b354 100644 --- a/cxx-qt-gen/test_outputs/types_qt_invokable.rs +++ b/cxx-qt-gen/test_outputs/types_qt_invokable.rs @@ -1,5 +1,5 @@ #[cxx::bridge(namespace = "cxx_qt::my_object")] -mod my_object { +mod ffi { unsafe extern "C++" { include!("cxx-qt-gen/include/my_object.cxxqt.h"); @@ -7,88 +7,97 @@ mod my_object { type MyObjectQt; #[cxx_name = "unsafe_rust"] - fn rust(self: &MyObjectQt) -> &RustObj; + fn rust(self: &MyObjectQt) -> &MyObject; #[rust_name = "new_cpp_object"] fn newCppObject() -> UniquePtr; } extern "C++" { #[cxx_name = "unsafe_rust_mut"] - unsafe fn rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut RustObj>; + unsafe fn rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut MyObject>; } extern "Rust" { #[cxx_name = "MyObjectRust"] - type RustObj; + type MyObject; #[cxx_name = "testColorWrapper"] fn test_color_wrapper( - self: &RustObj, + self: &MyObject, _cpp: Pin<&mut MyObjectQt>, color: &QColor, ) -> UniquePtr; #[cxx_name = "testDateWrapper"] - fn test_date_wrapper(self: &RustObj, _cpp: Pin<&mut MyObjectQt>, date: &QDate) -> QDate; + fn test_date_wrapper(self: &MyObject, _cpp: Pin<&mut MyObjectQt>, date: &QDate) -> QDate; #[cxx_name = "testDateTimeWrapper"] fn test_date_time_wrapper( - self: &RustObj, + self: &MyObject, _cpp: Pin<&mut MyObjectQt>, dateTime: &QDateTime, ) -> UniquePtr; #[cxx_name = "testPointWrapper"] - fn test_point_wrapper(self: &RustObj, _cpp: Pin<&mut MyObjectQt>, point: &QPoint) - -> QPoint; + fn test_point_wrapper( + self: &MyObject, + _cpp: Pin<&mut MyObjectQt>, + point: &QPoint, + ) -> QPoint; #[cxx_name = "testPointfWrapper"] fn test_pointf_wrapper( - self: &RustObj, + self: &MyObject, _cpp: Pin<&mut MyObjectQt>, pointf: &QPointF, ) -> QPointF; #[cxx_name = "testRectWrapper"] - fn test_rect_wrapper(self: &RustObj, _cpp: Pin<&mut MyObjectQt>, rect: &QRect) -> QRect; + fn test_rect_wrapper(self: &MyObject, _cpp: Pin<&mut MyObjectQt>, rect: &QRect) -> QRect; #[cxx_name = "testRectfWrapper"] - fn test_rectf_wrapper(self: &RustObj, _cpp: Pin<&mut MyObjectQt>, rectf: &QRectF) - -> QRectF; + fn test_rectf_wrapper( + self: &MyObject, + _cpp: Pin<&mut MyObjectQt>, + rectf: &QRectF, + ) -> QRectF; #[cxx_name = "testSizeWrapper"] - fn test_size_wrapper(self: &RustObj, _cpp: Pin<&mut MyObjectQt>, size: &QSize) -> QSize; + fn test_size_wrapper(self: &MyObject, _cpp: Pin<&mut MyObjectQt>, size: &QSize) -> QSize; #[cxx_name = "testSizefWrapper"] - fn test_sizef_wrapper(self: &RustObj, _cpp: Pin<&mut MyObjectQt>, sizef: &QSizeF) - -> QSizeF; + fn test_sizef_wrapper( + self: &MyObject, + _cpp: Pin<&mut MyObjectQt>, + sizef: &QSizeF, + ) -> QSizeF; #[cxx_name = "testStringWrapper"] fn test_string_wrapper( - self: &RustObj, + self: &MyObject, _cpp: Pin<&mut MyObjectQt>, string: &QString, ) -> UniquePtr; #[cxx_name = "testTimeWrapper"] - fn test_time_wrapper(self: &RustObj, _cpp: Pin<&mut MyObjectQt>, time: &QTime) -> QTime; + fn test_time_wrapper(self: &MyObject, _cpp: Pin<&mut MyObjectQt>, time: &QTime) -> QTime; #[cxx_name = "testUrlWrapper"] fn test_url_wrapper( - self: &RustObj, + self: &MyObject, _cpp: Pin<&mut MyObjectQt>, url: &QUrl, ) -> UniquePtr; #[cxx_name = "testVariantWrapper"] fn test_variant_wrapper( - self: &RustObj, + self: &MyObject, _cpp: Pin<&mut MyObjectQt>, variant: &QVariant, ) -> UniquePtr; #[cxx_name = "createRs"] - fn create_rs() -> Box; + fn create_rs() -> Box; #[cxx_name = "initialiseCpp"] fn initialise_cpp(cpp: Pin<&mut MyObjectQt>); @@ -113,17 +122,17 @@ mod my_object { } } -pub use self::cxx_qt_my_object::*; -mod cxx_qt_my_object { - use super::my_object::*; +pub use self::cxx_qt_ffi::*; +mod cxx_qt_ffi { + use super::ffi::*; - pub type FFICppObj = super::my_object::MyObjectQt; + pub type FFICppObj = super::ffi::MyObjectQt; type UniquePtr = cxx::UniquePtr; #[derive(Default)] - pub struct RustObj; + pub struct MyObject; - impl RustObj { + impl MyObject { pub fn test_color_wrapper( &self, _cpp: std::pin::Pin<&mut FFICppObj>, @@ -325,7 +334,7 @@ mod cxx_qt_my_object { } } - pub fn create_rs() -> std::boxed::Box { + pub fn create_rs() -> std::boxed::Box { std::default::Default::default() } diff --git a/cxx-qt-gen/test_outputs/types_qt_property.rs b/cxx-qt-gen/test_outputs/types_qt_property.rs index 8780fa62e..2d8cdc55c 100644 --- a/cxx-qt-gen/test_outputs/types_qt_property.rs +++ b/cxx-qt-gen/test_outputs/types_qt_property.rs @@ -1,5 +1,5 @@ #[cxx::bridge(namespace = "cxx_qt::my_object")] -mod my_object { +mod ffi { unsafe extern "C++" { include!("cxx-qt-gen/include/my_object.cxxqt.h"); @@ -72,22 +72,22 @@ mod my_object { fn setVariant(self: Pin<&mut MyObjectQt>, value: &QVariant); #[cxx_name = "unsafe_rust"] - fn rust(self: &MyObjectQt) -> &RustObj; + fn rust(self: &MyObjectQt) -> &MyObject; #[rust_name = "new_cpp_object"] fn newCppObject() -> UniquePtr; } extern "C++" { #[cxx_name = "unsafe_rust_mut"] - unsafe fn rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut RustObj>; + unsafe fn rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut MyObject>; } extern "Rust" { #[cxx_name = "MyObjectRust"] - type RustObj; + type MyObject; #[cxx_name = "createRs"] - fn create_rs() -> Box; + fn create_rs() -> Box; #[cxx_name = "initialiseCpp"] fn initialise_cpp(cpp: Pin<&mut MyObjectQt>); @@ -112,17 +112,17 @@ mod my_object { } } -pub use self::cxx_qt_my_object::*; -mod cxx_qt_my_object { - use super::my_object::*; +pub use self::cxx_qt_ffi::*; +mod cxx_qt_ffi { + use super::ffi::*; - pub type FFICppObj = super::my_object::MyObjectQt; + pub type FFICppObj = super::ffi::MyObjectQt; type UniquePtr = cxx::UniquePtr; #[derive(Default)] - pub struct RustObj; + pub struct MyObject; - impl RustObj {} + impl MyObject {} pub struct CppObj<'a> { cpp: std::pin::Pin<&'a mut FFICppObj>, @@ -297,7 +297,7 @@ mod cxx_qt_my_object { } } - pub fn create_rs() -> std::boxed::Box { + pub fn create_rs() -> std::boxed::Box { std::default::Default::default() } diff --git a/cxx-qt/src/lib.rs b/cxx-qt/src/lib.rs index 54e9ce23f..578c8e471 100644 --- a/cxx-qt/src/lib.rs +++ b/cxx-qt/src/lib.rs @@ -3,8 +3,11 @@ // SPDX-FileContributor: Gerhard de Clercq // // SPDX-License-Identifier: MIT OR Apache-2.0 +#![feature(proc_macro_span)] + +use std::path::PathBuf; use proc_macro::TokenStream; -use syn::{parse_macro_input, ItemMod}; +use syn::{spanned::Spanned, parse_macro_input, ItemMod}; use cxx_qt_gen::{extract_qobject, generate_qobject_rs}; @@ -49,8 +52,11 @@ pub fn bridge(args: TokenStream, input: TokenStream) -> TokenStream { let attrs = syn::parse_str::(&args_input).unwrap().attrs; module.attrs = attrs.into_iter().chain(module.attrs.into_iter()).collect(); + // Extract the source file of the module via nightly API + let source = module.span().unwrap().source_file(); + // Extract and generate the rust code - extract_and_generate(module) + extract_and_generate(module, source.path()) } /// A macro which describes that an enum defines the signals for a QObject. @@ -73,6 +79,24 @@ pub fn signals(_args: TokenStream, _input: TokenStream) -> TokenStream { unreachable!("cxx_qt::signals should not be used as a macro by itself. Instead it should be used within a cxx_qt::bridge definition") } +/// A macro which describes that a struct should be made into a QObject. +/// +/// It should not be used by itself and instead should be used inside a cxx_qt::bridge definition. +/// +/// # Example +/// +/// ```ignore +/// #[cxx_qt::bridge(namespace = "cxx_qt::my_object")] +/// mod my_object { +/// #[cxx_qt::qobject] +/// struct MyObject; +/// } +/// ``` +#[proc_macro_attribute] +pub fn qobject(_args: TokenStream, _input: TokenStream) -> TokenStream { + unreachable!("cxx_qt::qobject should not be used as a macro by itself. Instead it should be used within a cxx_qt::bridge definition") +} + /// A macro which describes that the inner methods should be implemented on the C++ QObject. /// This allows for defining C++ methods which are Q_INVOKABLE for QML in Rust. /// @@ -106,9 +130,9 @@ pub fn QObject(_input: TokenStream) -> TokenStream { } // Take the module and C++ namespace and generate the rust code -fn extract_and_generate(module: ItemMod) -> TokenStream { +fn extract_and_generate(module: ItemMod, path: PathBuf) -> TokenStream { // Attempt to extract information about a QObject inside the module - let qobject = match extract_qobject(&module) { + let qobject = match extract_qobject(&module, path) { Ok(o) => o, Err(e) => return e.into(), }; diff --git a/examples/demo_threading/src/lib.rs b/examples/demo_threading/src/lib.rs index 6c677c521..fd3964907 100644 --- a/examples/demo_threading/src/lib.rs +++ b/examples/demo_threading/src/lib.rs @@ -112,7 +112,7 @@ impl Default for SensorData { } #[cxx_qt::bridge(namespace = "cxx_qt::energy_usage")] -mod energy_usage { +mod ffi { use super::{NetworkChannel, Request, RequestCommand, Response, SensorData, Status}; use async_std::{ net::{TcpListener, TcpStream}, @@ -149,13 +149,14 @@ mod energy_usage { } } - pub struct RustObj { + #[cxx_qt::qobject] + pub struct EnergyUsage { qt_rx: Receiver, qt_tx: SyncSender, join_handles: Option<[JoinHandle<()>; 4]>, } - impl Default for RustObj { + impl Default for EnergyUsage { fn default() -> Self { let (qt_tx, qt_rx) = sync_channel(super::CHANNEL_QT_COUNT); Self { @@ -166,7 +167,7 @@ mod energy_usage { } } - impl RustObj { + impl EnergyUsage { /// Read from a TCP stream and create a Request async fn build_request(stream: &mut TcpStream) -> Result { let mut buf = vec![0u8; 128]; @@ -184,7 +185,7 @@ mod energy_usage { } async fn handle_connection(mut stream: TcpStream, network_tx: SyncSender) { - let response: Response = match RustObj::build_request(&mut stream).await { + let response: Response = match EnergyUsage::build_request(&mut stream).await { Ok(request) => { match request.command { RequestCommand::Power { value } => { @@ -216,7 +217,7 @@ mod energy_usage { } } - impl cxx_qt::QObject { + impl cxx_qt::QObject { #[invokable] pub fn start_server(&mut self, cpp: &mut CppObj) { if self.join_handles.is_some() { @@ -353,7 +354,7 @@ mod energy_usage { .map(|stream| (stream, network_tx.clone())) .for_each_concurrent(/* limit */ None, |(stream, network_tx)| async move { let stream = stream.unwrap(); - spawn(RustObj::handle_connection(stream, network_tx)); + spawn(EnergyUsage::handle_connection(stream, network_tx)); }) .await; }; @@ -368,7 +369,7 @@ mod energy_usage { } } - impl UpdateRequestHandler> for RustObj { + impl UpdateRequestHandler> for EnergyUsage { fn handle_update_request(&mut self, cpp: &mut CppObj) { // Process the new data from the background thread if let Some(data) = self.qt_rx.try_iter().last() { diff --git a/examples/qml_extension_plugin/core/src/lib.rs b/examples/qml_extension_plugin/core/src/lib.rs index 6b6c5d08b..80666fe8c 100644 --- a/examples/qml_extension_plugin/core/src/lib.rs +++ b/examples/qml_extension_plugin/core/src/lib.rs @@ -27,7 +27,7 @@ impl From for DataSerde { const DEFAULT_STR: &str = r#"{"number": 1, "string": "Hello World!"}"#; #[cxx_qt::bridge(namespace = "cxx_qt::my_object")] -mod my_object { +mod ffi { use super::{DataSerde, DEFAULT_STR}; #[namespace = ""] @@ -57,10 +57,11 @@ mod my_object { } } + #[cxx_qt::qobject] #[derive(Default)] - pub struct RustObj; + pub struct MyObject; - impl cxx_qt::QObject { + impl cxx_qt::QObject { #[invokable] pub fn increment(&self, cpp: &mut CppObj) { cpp.set_number(cpp.number() + 1); diff --git a/examples/qml_features/src/data_struct_properties.rs b/examples/qml_features/src/data_struct_properties.rs index bf19398ef..2a2691750 100644 --- a/examples/qml_features/src/data_struct_properties.rs +++ b/examples/qml_features/src/data_struct_properties.rs @@ -5,13 +5,14 @@ // ANCHOR: book_macro_code #[cxx_qt::bridge(namespace = "cxx_qt::data_struct_properties")] -mod data_struct_properties { +mod ffi { #[derive(Default)] pub struct Data { number: i32, } + #[cxx_qt::qobject] #[derive(Default)] - pub struct RustObj; + pub struct DataStructProperties; } // ANCHOR_END: book_macro_code diff --git a/examples/qml_features/src/empty.rs b/examples/qml_features/src/empty.rs index a951cff54..03ed73eee 100644 --- a/examples/qml_features/src/empty.rs +++ b/examples/qml_features/src/empty.rs @@ -4,10 +4,11 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 #[cxx_qt::bridge(namespace = "cxx_qt::empty")] -mod empty { +mod ffi { #[derive(Default)] pub struct Data; + #[cxx_qt::qobject] #[derive(Default)] - pub struct RustObj; + pub struct Empty; } diff --git a/examples/qml_features/src/lib.rs b/examples/qml_features/src/lib.rs index 775aa9e61..2166fd213 100644 --- a/examples/qml_features/src/lib.rs +++ b/examples/qml_features/src/lib.rs @@ -13,7 +13,7 @@ mod signals; mod types; #[cxx_qt::bridge(namespace = "cxx_qt::my_object")] -mod my_object { +mod ffi { #[namespace = ""] unsafe extern "C++" { include!("cxx-qt-lib/include/qt_types.h"); @@ -34,10 +34,11 @@ mod my_object { } } + #[cxx_qt::qobject] #[derive(Default)] - pub struct RustObj; + pub struct MyObject; - impl cxx_qt::QObject { + impl cxx_qt::QObject { #[invokable] pub fn increment_number_self(&self, cpp: &mut CppObj) { let value = cpp.number() + 1; diff --git a/examples/qml_features/src/mock_qt_types.rs b/examples/qml_features/src/mock_qt_types.rs index bc2580140..0cf6cb896 100644 --- a/examples/qml_features/src/mock_qt_types.rs +++ b/examples/qml_features/src/mock_qt_types.rs @@ -5,7 +5,7 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 #[cxx_qt::bridge(namespace = "cxx_qt::mock_qt_types")] -mod mock_qt_types { +mod ffi { use cxx_qt_lib::QVariantValue; #[namespace = ""] @@ -26,7 +26,7 @@ mod mock_qt_types { type QVariant = cxx_qt_lib::QVariant; } - #[cxx_qt::signals(RustObj)] + #[cxx_qt::signals(MockQtTypes)] pub enum Signal { Ready, DataChanged { variant: UniquePtr }, @@ -71,10 +71,11 @@ mod mock_qt_types { } } + #[cxx_qt::qobject] #[derive(Default)] - pub struct RustObj; + pub struct MockQtTypes; - impl cxx_qt::QObject { + impl cxx_qt::QObject { #[invokable] pub fn test_signal(&self, cpp: &mut CppObj) { cpp.emit_queued(Signal::Ready); diff --git a/examples/qml_features/src/rust_obj_invokables.rs b/examples/qml_features/src/rust_obj_invokables.rs index b46d83c52..c995c129d 100644 --- a/examples/qml_features/src/rust_obj_invokables.rs +++ b/examples/qml_features/src/rust_obj_invokables.rs @@ -5,23 +5,24 @@ // ANCHOR: book_macro_code #[cxx_qt::bridge(namespace = "cxx_qt::rust_obj_invokables")] -pub mod rust_obj_invokables { +pub mod ffi { #[derive(Default)] pub struct Data { number: i32, } - pub struct RustObj { + #[cxx_qt::qobject] + pub struct RustObjInvokables { rust_only_field: i32, } - impl Default for RustObj { + impl Default for RustObjInvokables { fn default() -> Self { Self { rust_only_field: 1 } } } - impl cxx_qt::QObject { + impl cxx_qt::QObject { // ANCHOR: book_cpp_obj #[invokable] pub fn invokable_mutate_cpp(&self, cpp: &mut CppObj) { @@ -41,7 +42,7 @@ pub mod rust_obj_invokables { } } - impl RustObj { + impl RustObjInvokables { fn rust_only_method(&mut self, factor: i32) { self.rust_only_field *= factor; } diff --git a/examples/qml_features/src/serialisation.rs b/examples/qml_features/src/serialisation.rs index efb49ba34..43259301d 100644 --- a/examples/qml_features/src/serialisation.rs +++ b/examples/qml_features/src/serialisation.rs @@ -24,7 +24,7 @@ impl From for DataSerde { } #[cxx_qt::bridge(namespace = "cxx_qt::serialisation")] -mod serialisation { +mod ffi { use super::DataSerde; #[namespace = ""] @@ -55,10 +55,11 @@ mod serialisation { } } + #[cxx_qt::qobject] #[derive(Default)] - pub struct RustObj; + pub struct Serialisation; - impl cxx_qt::QObject { + impl cxx_qt::QObject { #[invokable] pub fn as_json_str(&self, cpp: &mut CppObj) -> UniquePtr { let data = Data::from(cpp); diff --git a/examples/qml_features/src/signals.rs b/examples/qml_features/src/signals.rs index d5e9e5f3a..ee3cd9be8 100644 --- a/examples/qml_features/src/signals.rs +++ b/examples/qml_features/src/signals.rs @@ -5,7 +5,7 @@ // ANCHOR: book_macro_code #[cxx_qt::bridge(namespace = "cxx_qt::signals")] -pub mod signals { +pub mod ffi { #[namespace = ""] unsafe extern "C++" { include!("cxx-qt-lib/include/qt_types.h"); @@ -14,7 +14,7 @@ pub mod signals { } // ANCHOR: book_signals_enum - #[cxx_qt::signals(RustObj)] + #[cxx_qt::signals(Signals)] pub enum Signal { Ready, RustDataChanged { data: i32 }, @@ -39,11 +39,12 @@ pub mod signals { } } + #[cxx_qt::qobject] #[derive(Default)] - pub struct RustObj; + pub struct Signals; // ANCHOR: book_rust_obj_impl - impl cxx_qt::QObject { + impl cxx_qt::QObject { #[invokable] pub fn invokable(&self, cpp: &mut CppObj) { unsafe { diff --git a/examples/qml_features/src/types.rs b/examples/qml_features/src/types.rs index fdf84fbd2..7bb634fcb 100644 --- a/examples/qml_features/src/types.rs +++ b/examples/qml_features/src/types.rs @@ -5,7 +5,7 @@ // ANCHOR: book_macro_code #[cxx_qt::bridge(namespace = "cxx_qt::types")] -mod types { +mod ffi { use cxx_qt_lib::QVariantValue; #[namespace = ""] @@ -26,10 +26,11 @@ mod types { } } + #[cxx_qt::qobject] #[derive(Default)] - pub struct RustObj; + pub struct Types; - impl cxx_qt::QObject { + impl cxx_qt::QObject { #[invokable] pub fn test_variant_property(&self, cpp: &mut CppObj) { match cpp.variant().value() { diff --git a/examples/qml_minimal/src/lib.rs b/examples/qml_minimal/src/lib.rs index c2a955c48..e17689d06 100644 --- a/examples/qml_minimal/src/lib.rs +++ b/examples/qml_minimal/src/lib.rs @@ -8,7 +8,7 @@ // ANCHOR: book_bridge_macro #[cxx_qt::bridge(namespace = "cxx_qt::my_object")] -mod my_object { +mod ffi { // ANCHOR_END: book_bridge_macro #[namespace = ""] @@ -35,12 +35,13 @@ mod my_object { // ANCHOR_END: book_data_struct // ANCHOR: book_rustobj_struct + #[cxx_qt::qobject] #[derive(Default)] - pub struct RustObj; + pub struct MyObject; // ANCHOR_END: book_rustobj_struct // ANCHOR: book_rustobj_impl - impl cxx_qt::QObject { + impl cxx_qt::QObject { #[invokable] pub fn increment_number(&self, cpp: &mut CppObj) { cpp.set_number(cpp.number() + 1); diff --git a/examples/qml_minimal/src/main.cpp b/examples/qml_minimal/src/main.cpp index 3791bc8d7..be7d10ed0 100644 --- a/examples/qml_minimal/src/main.cpp +++ b/examples/qml_minimal/src/main.cpp @@ -11,7 +11,7 @@ #include // ANCHOR: book_cpp_include -#include "cxx-qt-gen/include/my_object.cxxqt.h" +#include "cxx-qt-gen/include/lib.cxxqt.h" // ANCHOR_END: book_cpp_include int diff --git a/examples/qml_with_threaded_logic/src/lib.rs b/examples/qml_with_threaded_logic/src/lib.rs index 34e8ffa04..a80450337 100644 --- a/examples/qml_with_threaded_logic/src/lib.rs +++ b/examples/qml_with_threaded_logic/src/lib.rs @@ -10,7 +10,7 @@ enum Event { } #[cxx_qt::bridge(namespace = "cxx_qt::website")] -mod website { +mod ffi { use super::Event; use futures::{ channel::mpsc::{UnboundedReceiver, UnboundedSender}, @@ -44,13 +44,14 @@ mod website { } } - pub struct RustObj { + #[cxx_qt::qobject] + pub struct Website { event_sender: UnboundedSender, event_queue: UnboundedReceiver, loading: AtomicBool, } - impl Default for RustObj { + impl Default for Website { fn default() -> Self { let (event_sender, event_queue) = futures::channel::mpsc::unbounded(); @@ -62,7 +63,7 @@ mod website { } } - impl cxx_qt::QObject { + impl cxx_qt::QObject { #[invokable] pub fn change_url(&self, cpp: &mut CppObj) { let url = cpp.url().to_string(); @@ -132,7 +133,7 @@ mod website { } // ANCHOR: book_update_request_handler - impl UpdateRequestHandler> for RustObj { + impl UpdateRequestHandler> for Website { fn handle_update_request(&mut self, cpp: &mut CppObj) { while let Some(event) = self.event_queue.next().now_or_never() { if let Some(event) = event { diff --git a/tests/basic_cxx_qt/src/data.rs b/tests/basic_cxx_qt/src/data.rs index b5cd59e42..ad9095fe6 100644 --- a/tests/basic_cxx_qt/src/data.rs +++ b/tests/basic_cxx_qt/src/data.rs @@ -23,7 +23,7 @@ impl From for DataSerde { } #[cxx_qt::bridge(namespace = "cxx_qt::my_data")] -mod my_data { +mod ffi { use super::DataSerde; #[namespace = ""] @@ -54,10 +54,11 @@ mod my_data { } } + #[cxx_qt::qobject] #[derive(Default)] - pub struct RustObj; + pub struct MyData; - impl cxx_qt::QObject { + impl cxx_qt::QObject { #[invokable] pub fn as_json_str(&self, cpp: &mut CppObj) -> UniquePtr { let data = Data::from(cpp); diff --git a/tests/basic_cxx_qt/src/lib.rs b/tests/basic_cxx_qt/src/lib.rs index 85a001d6c..143860884 100644 --- a/tests/basic_cxx_qt/src/lib.rs +++ b/tests/basic_cxx_qt/src/lib.rs @@ -8,7 +8,7 @@ mod data; mod types; #[cxx_qt::bridge(namespace = "cxx_qt::my_object")] -mod my_object { +mod ffi { #[namespace = ""] unsafe extern "C++" { include!("cxx-qt-lib/include/qt_types.h"); @@ -29,12 +29,13 @@ mod my_object { } } + #[cxx_qt::qobject] #[derive(Default)] - pub struct RustObj { + pub struct MyObject { update_call_count: i32, } - impl cxx_qt::QObject { + impl cxx_qt::QObject { #[invokable] pub fn double_number_self(&self, cpp: &mut CppObj) { let value = cpp.number() * 2; @@ -92,7 +93,7 @@ mod my_object { } } - impl UpdateRequestHandler> for RustObj { + impl UpdateRequestHandler> for MyObject { fn handle_update_request(&mut self, _cpp: &mut CppObj) { self.update_call_count += 1; } diff --git a/tests/basic_cxx_qt/src/types.rs b/tests/basic_cxx_qt/src/types.rs index 6a29429ef..80fde26a8 100644 --- a/tests/basic_cxx_qt/src/types.rs +++ b/tests/basic_cxx_qt/src/types.rs @@ -5,7 +5,7 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 #[cxx_qt::bridge(namespace = "cxx_qt::my_types")] -mod my_types { +mod ffi { #[derive(Default)] pub struct Data { boolean: bool, @@ -19,6 +19,7 @@ mod my_types { uint_32: u32, } + #[cxx_qt::qobject] #[derive(Default)] - pub struct RustObj; + pub struct MyTypes; }