KDAB / cxx-qt

Safe interop between Rust and Qt
https://kdab.github.io/cxx-qt/book/
1.03k stars 68 forks source link

Support u64 and i64 #36

Closed ahayzen-kdab closed 1 year ago

ahayzen-kdab commented 2 years ago

Add u64 and i64 support, qint64 and std::int64_t disagree on long long int vs long int so cxx becomes confused. And using just std means QML is confused (we need to register the types?).

ahayzen-kdab commented 2 years ago

If u64/i64 support is added the following compile issues occur

[build] /workspaces/cxx-qt/examples/basic_cxx_qt/target/cxx-qt-gen/src/my_types.rs.cpp: In function ‘int64_t cxx_qt::my_types::cxx_qt$my_types$cxxbridge1$MyTypes$int_64(const MyTypes&)’:
[build] /workspaces/cxx-qt/examples/basic_cxx_qt/target/cxx-qt-gen/src/my_types.rs.cpp:362:98: error: cannot convert ‘qint64 (cxx_qt::my_types::MyTypes::*)() const’ {aka ‘long long int (cxx_qt::my_types::MyTypes::*)() const’} to ‘int64_t (cxx_qt::my_types::MyTypes::*)() const’ {aka ‘long int (cxx_qt::my_types::MyTypes::*)() const’} in initialization
[build]   362 |   ::std::int64_t (::cxx_qt::my_types::MyTypes::*int_64$)() const = &::cxx_qt::my_types::MyTypes::getInt64;
[build]       |                                                                                                  ^~~~~~~~
[build] /workspaces/cxx-qt/examples/basic_cxx_qt/target/cxx-qt-gen/src/my_types.rs.cpp: In function ‘void cxx_qt::my_types::cxx_qt$my_types$cxxbridge1$MyTypes$set_int_64(cxx_qt::my_types::MyTypes&, int64_t)’:
[build] /workspaces/cxx-qt/examples/basic_cxx_qt/target/cxx-qt-gen/src/my_types.rs.cpp:367:100: error: cannot convert ‘void (cxx_qt::my_types::MyTypes::*)(qint64)’ {aka ‘void (cxx_qt::my_types::MyTypes::*)(long long int)’} to ‘void (cxx_qt::my_types::MyTypes::*)(int64_t)’ {aka ‘void (cxx_qt::my_types::MyTypes::*)(long int)’} in initialization
[build]   367 |   void (::cxx_qt::my_types::MyTypes::*set_int_64$)(::std::int64_t) = &::cxx_qt::my_types::MyTypes::setInt64;
[build]       |                                                                                                    ^~~~~~~~
[build] /workspaces/cxx-qt/examples/basic_cxx_qt/target/cxx-qt-gen/src/my_types.rs.cpp: In function ‘uint64_t cxx_qt::my_types::cxx_qt$my_types$cxxbridge1$MyTypes$uint_64(const MyTypes&)’:
[build] /workspaces/cxx-qt/examples/basic_cxx_qt/target/cxx-qt-gen/src/my_types.rs.cpp:402:100: error: cannot convert ‘quint64 (cxx_qt::my_types::MyTypes::*)() const’ {aka ‘long long unsigned int (cxx_qt::my_types::MyTypes::*)() const’} to ‘uint64_t (cxx_qt::my_types::MyTypes::*)() const’ {aka ‘long unsigned int (cxx_qt::my_types::MyTypes::*)() const’} in initialization
[build]   402 |   ::std::uint64_t (::cxx_qt::my_types::MyTypes::*uint_64$)() const = &::cxx_qt::my_types::MyTypes::getUint64;
[build]       |                                                                                                    ^~~~~~~~~
[build] /workspaces/cxx-qt/examples/basic_cxx_qt/target/cxx-qt-gen/src/my_types.rs.cpp: In function ‘void cxx_qt::my_types::cxx_qt$my_types$cxxbridge1$MyTypes$set_uint_64(cxx_qt::my_types::MyTypes&, uint64_t)’:
[build] /workspaces/cxx-qt/examples/basic_cxx_qt/target/cxx-qt-gen/src/my_types.rs.cpp:407:102: error: cannot convert ‘void (cxx_qt::my_types::MyTypes::*)(quint64)’ {aka ‘void (cxx_qt::my_types::MyTypes::*)(long long unsigned int)’} to ‘void (cxx_qt::my_types::MyTypes::*)(uint64_t)’ {aka ‘void (cxx_qt::my_types::MyTypes::*)(long unsigned int)’} in initialization
[build]   407 |   void (::cxx_qt::my_types::MyTypes::*set_uint_64$)(::std::uint64_t) = &::cxx_qt::my_types::MyTypes::setUint64;
[build]       |                                                                                                      ^~~~~~~~~

This is due to the difference here of long long int vs long int

std

#if __WORDSIZE == 64
typedef signed long int __int64_t;
typedef unsigned long int __uint64_t;
#else
__extension__ typedef signed long long int __int64_t;
__extension__ typedef unsigned long long int __uint64_t;
#endif 

Qt

#if defined(Q_OS_WIN) && !defined(Q_CC_GNU)
#  define Q_INT64_C(c) c ## i64    /* signed 64 bit constant */
#  define Q_UINT64_C(c) c ## ui64   /* unsigned 64 bit constant */
typedef __int64 qint64;            /* 64 bit signed */
typedef unsigned __int64 quint64;  /* 64 bit unsigned */
#else
#ifdef __cplusplus
#  define Q_INT64_C(c) static_cast<long long>(c ## LL)     /* signed 64 bit constant */
#  define Q_UINT64_C(c) static_cast<unsigned long long>(c ## ULL) /* unsigned 64 bit constant */
#else
#  define Q_INT64_C(c) ((long long)(c ## LL))               /* signed 64 bit constant */
#  define Q_UINT64_C(c) ((unsigned long long)(c ## ULL))    /* unsigned 64 bit constant */
#endif
typedef long long qint64;           /* 64 bit signed */
typedef unsigned long long quint64; /* 64 bit unsigned */
#endif 

We might need to define a custom type on the Rust side which then maps to qint64.

#[repr(transparent)]
struct QInt64 {
    value: i64,
}

Or the preferred way would be to figure out a way of registering std::int64_t to Qt/QML nicely, the following didn't work fully.

Q_DECLARE_METATYPE(std::int64_t)

However do note that a qml int has a limitation of "around -2000000000 to around 2000000000" https://doc.qt.io/qt-5/qml-int.html

ahayzen-kdab commented 1 year ago

Once we use std types ( #316 ) then this can be solved by just using std::uint64_t. If Qt 5 developers want the qint64 that is different they can implement their own support...