Skip to content

Commit

Permalink
cxx-qt-gen: move #[qinvokable] to be inside extern "RustQt"
Browse files Browse the repository at this point in the history
Closes KDAB#558
  • Loading branch information
ahayzen-kdab committed Jun 9, 2023
1 parent 10e324c commit 4b9cb99
Show file tree
Hide file tree
Showing 44 changed files with 1,218 additions and 1,213 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Moved to `syn` 2.0 internally and for any exported `syn` types
- `impl cxx_qt::Threading for qobject::T` now needs to be specified for `qt_thread()` to be available
- `#[cxx_qt::qsignals]` and `#[cxx_qt::inherit]` are now used in an `extern "RustQt"` block as `#[qsignal]` and `#[inherit]`
- `#[qinvokable]` is now defined as a signature in `extern "RustQt"`

### Removed

Expand Down
1 change: 1 addition & 0 deletions book/src/concepts/inheritance.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ To support creating such subclasses directly from within Rust, CXX-Qt provides y
To access the methods of a base class in Rust, use the `#[inherit]` macro.
It can be placed in front of a function in a `extern "RustQt"` block in a `#[cxx_qt::bridge]`.

TODO: all of these examples need sorting out
```rust,ignore
{{#include ../../../examples/qml_features/rust/src/custom_base_class.rs:book_inherit_qalm}}
Expand Down
20 changes: 15 additions & 5 deletions crates/cxx-qt-gen/src/generator/cpp/invokable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,32 +161,40 @@ mod tests {
fn test_generate_cpp_invokables() {
let invokables = vec![
ParsedQInvokable {
method: parse_quote! { fn void_invokable(&self) {} },
method: parse_quote! { fn void_invokable(self: &qobject::MyObject); },
qobject_ident: format_ident!("MyObject"),
mutable: false,
safe: true,
parameters: vec![],
specifiers: HashSet::new(),
},
ParsedQInvokable {
method: parse_quote! { fn trivial_invokable(&self, param: i32) -> i32 {} },
method: parse_quote! { fn trivial_invokable(self: &qobject::MyObject, param: i32) -> i32; },
qobject_ident: format_ident!("MyObject"),
mutable: false,
safe: true,
parameters: vec![ParsedFunctionParameter {
ident: format_ident!("param"),
ty: parse_quote! { i32 },
}],
specifiers: HashSet::new(),
},
ParsedQInvokable {
method: parse_quote! { fn opaque_invokable(self: Pin<&mut Self>, param: &QColor) -> UniquePtr<QColor> {} },
method: parse_quote! { fn opaque_invokable(self: Pin<&mut qobject::MyObject>, param: &QColor) -> UniquePtr<QColor>; },
qobject_ident: format_ident!("MyObject"),
mutable: true,
safe: true,
parameters: vec![ParsedFunctionParameter {
ident: format_ident!("param"),
ty: parse_quote! { &QColor },
}],
specifiers: HashSet::new(),
},
ParsedQInvokable {
method: parse_quote! { fn specifiers_invokable(&self, param: i32) -> i32 {} },
method: parse_quote! { fn specifiers_invokable(self: &qobject::MyObject, param: i32) -> i32; },
qobject_ident: format_ident!("MyObject"),
mutable: false,
safe: true,
parameters: vec![ParsedFunctionParameter {
ident: format_ident!("param"),
ty: parse_quote! { i32 },
Expand Down Expand Up @@ -298,8 +306,10 @@ mod tests {
#[test]
fn test_generate_cpp_invokables_mapped_cxx_name() {
let invokables = vec![ParsedQInvokable {
method: parse_quote! { fn trivial_invokable(&self, param: A) -> B {} },
method: parse_quote! { fn trivial_invokable(self: &qobject::MyObject, param: A) -> B; },
qobject_ident: format_ident!("MyObject"),
mutable: false,
safe: true,
parameters: vec![ParsedFunctionParameter {
ident: format_ident!("param"),
ty: parse_quote! { i32 },
Expand Down
17 changes: 8 additions & 9 deletions crates/cxx-qt-gen/src/generator/naming/invokable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use crate::{generator::naming::CombinedIdent, parser::invokable::ParsedQInvokable};
use convert_case::{Case, Casing};
use quote::format_ident;
use syn::{Ident, ImplItemFn};
use syn::{ForeignItemFn, Ident};

/// Names for parts of a Q_INVOKABLE
pub struct QInvokableName {
Expand All @@ -19,8 +19,8 @@ impl From<&ParsedQInvokable> for QInvokableName {
}
}

impl From<&ImplItemFn> for QInvokableName {
fn from(method: &ImplItemFn) -> Self {
impl From<&ForeignItemFn> for QInvokableName {
fn from(method: &ForeignItemFn) -> Self {
let ident = &method.sig.ident;
Self {
name: CombinedIdent::from_rust_function(ident.clone()),
Expand Down Expand Up @@ -50,14 +50,13 @@ mod tests {

#[test]
fn test_from_impl_method() {
let item: ImplItemFn = parse_quote! {
fn my_invokable() {

}
};
let parsed = ParsedQInvokable {
method: item,
method: parse_quote! {
fn my_invokable(self: &qobject::MyObject);
},
qobject_ident: format_ident!("MyObject"),
mutable: false,
safe: true,
parameters: vec![],
specifiers: HashSet::new(),
};
Expand Down
94 changes: 27 additions & 67 deletions crates/cxx-qt-gen/src/generator/rust/invokable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@
use crate::{
generator::{
naming::{invokable::QInvokableName, qobject::QObjectName},
rust::{
fragment::RustFragmentPair, qobject::GeneratedRustQObjectBlocks,
types::is_unsafe_cxx_type,
},
rust::{fragment::RustFragmentPair, qobject::GeneratedRustQObjectBlocks},
},
parser::invokable::ParsedQInvokable,
};
Expand All @@ -30,7 +27,6 @@ pub fn generate_rust_invokables(
let wrapper_ident_cpp = idents.wrapper.cpp.to_string();
let wrapper_ident_rust = &idents.wrapper.rust;
let invokable_ident_rust = &idents.name.rust;
let original_method = &invokable.method;

let cpp_struct = if invokable.mutable {
quote! { Pin<&mut #cpp_class_name_rust> }
Expand Down Expand Up @@ -62,21 +58,13 @@ pub fn generate_rust_invokables(
} else {
quote! { return }
};
// Determine if unsafe is required due to an unsafe parameter or return type
let has_unsafe_param = invokable
.parameters
.iter()
.any(|parameter| is_unsafe_cxx_type(&parameter.ty));
let has_unsafe_return = if let ReturnType::Type(_, ty) = return_type {
is_unsafe_cxx_type(ty)
} else {
false
};
let has_unsafe = if has_unsafe_param || has_unsafe_return {
quote! { unsafe }
} else {
quote! {}
};

let mut unsafe_block = None;
let mut unsafe_call = Some(quote! { unsafe });
if invokable.safe {
std::mem::swap(&mut unsafe_call, &mut unsafe_block);
}

let parameter_names = invokable
.parameters
.iter()
Expand All @@ -85,26 +73,22 @@ pub fn generate_rust_invokables(

let fragment = RustFragmentPair {
cxx_bridge: vec![quote! {
// TODO: is an unsafe block valid?
extern "Rust" {
#[cxx_name = #wrapper_ident_cpp]
#has_unsafe fn #wrapper_ident_rust(#parameter_signatures) #return_type;
#unsafe_call fn #wrapper_ident_rust(#parameter_signatures) #return_type;
}
}],
implementation: vec![
// TODO: not all methods have a wrapper
quote! {
impl #rust_struct_name_rust {
#[doc(hidden)]
pub #has_unsafe fn #wrapper_ident_rust(#parameter_signatures) #return_type {
pub #unsafe_call fn #wrapper_ident_rust(#parameter_signatures) #return_type {
#has_return cpp.#invokable_ident_rust(#(#parameter_names),*);
}
}
},
quote! {
impl #cpp_class_name_rust {
#original_method
}
},
],
};

Expand Down Expand Up @@ -134,32 +118,40 @@ mod tests {
fn test_generate_rust_invokables() {
let invokables = vec![
ParsedQInvokable {
method: parse_quote! { fn void_invokable(&self) {} },
method: parse_quote! { fn void_invokable(self: &qobject::MyObject); },
qobject_ident: format_ident!("MyObject"),
mutable: false,
safe: true,
parameters: vec![],
specifiers: HashSet::new(),
},
ParsedQInvokable {
method: parse_quote! { fn trivial_invokable(&self, param: i32) -> i32 {} },
method: parse_quote! { fn trivial_invokable(self: &qobject::MyObject, param: i32) -> i32; },
qobject_ident: format_ident!("MyObject"),
mutable: false,
safe: true,
parameters: vec![ParsedFunctionParameter {
ident: format_ident!("param"),
ty: parse_quote! { i32 },
}],
specifiers: HashSet::new(),
},
ParsedQInvokable {
method: parse_quote! { fn opaque_invokable(self: Pin<&mut Self>, param: &QColor) -> UniquePtr<QColor> {} },
method: parse_quote! { fn opaque_invokable(self: Pin<&mut qobject::MyObject>, param: &QColor) -> UniquePtr<QColor>; },
qobject_ident: format_ident!("MyObject"),
mutable: true,
safe: true,
parameters: vec![ParsedFunctionParameter {
ident: format_ident!("param"),
ty: parse_quote! { &QColor },
}],
specifiers: HashSet::new(),
},
ParsedQInvokable {
method: parse_quote! { fn unsafe_invokable(&self, param: *mut T) -> *mut T {} },
method: parse_quote! { unsafe fn unsafe_invokable(self: &qobject::MyObject, param: *mut T) -> *mut T; },
qobject_ident: format_ident!("MyObject"),
mutable: false,
safe: false,
parameters: vec![ParsedFunctionParameter {
ident: format_ident!("param"),
ty: parse_quote! { *mut T },
Expand All @@ -172,7 +164,7 @@ mod tests {
let generated = generate_rust_invokables(&invokables, &qobject_idents).unwrap();

assert_eq!(generated.cxx_mod_contents.len(), 4);
assert_eq!(generated.cxx_qt_mod_contents.len(), 8);
assert_eq!(generated.cxx_qt_mod_contents.len(), 4);

// void_invokable
assert_tokens_eq(
Expand All @@ -195,14 +187,6 @@ mod tests {
}
},
);
assert_tokens_eq(
&generated.cxx_qt_mod_contents[1],
quote! {
impl MyObjectQt {
fn void_invokable(&self) {}
}
},
);

// trivial_invokable
assert_tokens_eq(
Expand All @@ -215,7 +199,7 @@ mod tests {
},
);
assert_tokens_eq(
&generated.cxx_qt_mod_contents[2],
&generated.cxx_qt_mod_contents[1],
quote! {
impl MyObject {
#[doc(hidden)]
Expand All @@ -225,14 +209,6 @@ mod tests {
}
},
);
assert_tokens_eq(
&generated.cxx_qt_mod_contents[3],
quote! {
impl MyObjectQt {
fn trivial_invokable(&self, param: i32) -> i32 {}
}
},
);

// opaque_invokable
assert_tokens_eq(
Expand All @@ -245,7 +221,7 @@ mod tests {
},
);
assert_tokens_eq(
&generated.cxx_qt_mod_contents[4],
&generated.cxx_qt_mod_contents[2],
quote! {
impl MyObject {
#[doc(hidden)]
Expand All @@ -255,14 +231,6 @@ mod tests {
}
},
);
assert_tokens_eq(
&generated.cxx_qt_mod_contents[5],
quote! {
impl MyObjectQt {
fn opaque_invokable(self: Pin<&mut Self>, param: &QColor) -> UniquePtr<QColor> {}
}
},
);

// unsafe_invokable
assert_tokens_eq(
Expand All @@ -275,7 +243,7 @@ mod tests {
},
);
assert_tokens_eq(
&generated.cxx_qt_mod_contents[6],
&generated.cxx_qt_mod_contents[3],
quote! {
impl MyObject {
#[doc(hidden)]
Expand All @@ -285,13 +253,5 @@ mod tests {
}
},
);
assert_tokens_eq(
&generated.cxx_qt_mod_contents[7],
quote! {
impl MyObjectQt {
fn unsafe_invokable(&self, param: *mut T) -> *mut T {}
}
},
);
}
}
6 changes: 3 additions & 3 deletions crates/cxx-qt-gen/src/generator/rust/property/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ mod tests {
#[doc = "\n"]
#[doc = "Note that this method uses a AutoConnection connection type."]
#[must_use]
fn on_trivial_property_changed(self: Pin<&mut MyObjectQt>, func: fn(Pin<&mut MyObjectQt>, )) -> CxxQtQMetaObjectConnection
pub fn on_trivial_property_changed(self: Pin<&mut MyObjectQt>, func: fn(Pin<&mut MyObjectQt>, )) -> CxxQtQMetaObjectConnection
{
self.connect_trivial_property_changed(func, CxxQtConnectionType::AutoConnection)
}
Expand Down Expand Up @@ -445,7 +445,7 @@ mod tests {
#[doc = "\n"]
#[doc = "Note that this method uses a AutoConnection connection type."]
#[must_use]
fn on_opaque_property_changed(self: Pin<&mut MyObjectQt>, func: fn(Pin<&mut MyObjectQt>, )) -> CxxQtQMetaObjectConnection
pub fn on_opaque_property_changed(self: Pin<&mut MyObjectQt>, func: fn(Pin<&mut MyObjectQt>, )) -> CxxQtQMetaObjectConnection
{
self.connect_opaque_property_changed(func, CxxQtConnectionType::AutoConnection)
}
Expand Down Expand Up @@ -486,7 +486,7 @@ mod tests {
#[doc = "\n"]
#[doc = "Note that this method uses a AutoConnection connection type."]
#[must_use]
fn on_unsafe_property_changed(self: Pin<&mut MyObjectQt>, func: fn(Pin<&mut MyObjectQt>, )) -> CxxQtQMetaObjectConnection
pub fn on_unsafe_property_changed(self: Pin<&mut MyObjectQt>, func: fn(Pin<&mut MyObjectQt>, )) -> CxxQtQMetaObjectConnection
{
self.connect_unsafe_property_changed(func, CxxQtConnectionType::AutoConnection)
}
Expand Down
Loading

0 comments on commit 4b9cb99

Please sign in to comment.