Qt Bridges の継続的な開発の一環として、私たちは Qt Bridge for Rust の新しいベータ版を公開しました。今回のリリースでは、CXX-Qt との互換性と健全性(Soundness)に重点を置いています。API 表面(API surface)は、バージョン 0.2 と比較してほんの数か所しか変更されていません。変更が行われた箇所についても、その大半は、健全性を保証できない API を削除したことによるものです。
CXX-Qt との共通基盤
私たちは以前から、基本的な互換性を保証するために CXX-Qt のビルドユーティリティ を利用していました。0.3 ではさらに一歩進み、その基本的な型も内部実装で利用するようになりました: `QString`, `QByteArray`, `QModelIndex`, コンテナ型, QJson 関連の型, `QGuiApplication` そして `QQmlApplicationEngine`が対象です。その目的は、保守作業を集約し、CXX-Qt と Qt Bridge の両方を同じ高い品質に保つことです。また、これは両プロジェクト間の相互運用性に向けた取り組みでもあります。これはパブリックベータ公開以来、私たちのロードマップに含まれていました。私たちは、両プロジェクトが同じアプリケーション内で問題なく共存できるようになることを目指しています。この変更によって Qt Bridge の公開 API が影響を受けることはありません。ただし、将来的には適切な場面で CXX-Qt の型を公開 API に採用する可能性があります。例えば、シグナルやスロットのプロパティで QString を利用できるようになれば、UTF-8 と UTF-16 の間の変換回数が減り、性能向上につながるかもしれません。
実用上の注意点が 2 つあります: 0.2 からプロジェクトを更新する際に問題が発生した場合、典型的にはリンカエラーとして現れます。その場合は Cargo.lock と target ディレクトリを削除してください。また、CXX-Qt への移行に伴い、コンパイル時間は大幅に増加しています。私たちはこの問題を認識しており、将来のバージョンでコンパイル時間を改善することを予定しています。
健全性(Soundness)
私たちは今回の開発サイクルのかなりの部分を、フレームワークを壊そうと試み、そのうえで健全なものにすることに費やしました。
健全性を保証できなかった API はすべて削除しました。例えば、`#[qobject]`ユーザー定義型の`as_qvariant()`関数がそれに該当します。内部実装や生成コードにおいては、多くの関数やトレイトが unsafe としてマークされるようになりました。その結果、それらを呼び出すことは意図的な行為となり、偶発的に呼び出されることはなくなります。残りの関数についてはかなりの自信を持っていますが、将来のバージョンで修正予定の既知の問題がいくつか残っています。
障害発生時の挙動も改善されました。`QObject`がまだアタッチされていない状態でシグナルを発行したり、アイテムモデルを変更したりしても、パニックが発生しなくなりました。また、`include_bytes_qml!`はパニックを発生させる代わりにコンパイルエラーを出力するようになり、さらにネストされた `Cargo.lock`を持つワークスペースでもパスを正しく解決できるようになりました。
所有権(Ownership)の刷新
所有権(Ownership)の概念は全面的に見直されました。また、Rust と QML のライフタイム要件を調整するためのレジストリが導入されました(同僚が昼食時にこのアイデアを出してくれたおかげです!)。`QObject`は必要になった時点で `#[qobject]`のユーザー定義型にアタッチされるようになり、ユーザーが `default_with_attached_qobject()`を呼び出す必要はなくなりました。
公開 API は引き続き、ユーザーオブジェクトのコンテナおよびライフタイム管理機構として `Rc<RefCell<_>>` を採用しています。そのため、この点に関してユーザー側で変更する必要はありません。実際には、このコンテナの役割は大幅に強化されています。任意の `#[qobject]`型に対する `Rc<RefCell<_>>` は、QmlEngine が理解できるものとして扱われると考えて構いません。内部的には、ユーザーオブジェクトのライフタイム管理も`Rc<RefCell<_>>`が担うようになり、問題が発生する可能性が大幅に低減されました。
また、私たちはこの API を今後も維持していけると確信しています。そして、この結果に非常に満足しています。
知っておく価値のあるその他の変更点
-
`QmlRegister`は `QmlElement`に名前が変更されました。また、ユーザー向けのインスタンス API は `QObjectHolder`から`QmlObject`へ移動しました。
-
`Default`が必要なのは、すべての公開型ではなく、QML 要素のみになりました。
-
`#[qobject(LinkMe)]` はクレートの機能(crate feature)になりました。
-
`invoke_method` は、最も派生した型を優先して解決し、引数にもマッチングを行います。
-
`QObject`のプロパティおよび引数に対して、具体的な`T*`メタタイプが公開されるようになりました。また、スロットの戻り値のメタタイプも登録されるようになりました。
-
`include_bytes_qml!`はディレクトリを受け付けるようになりました。
-
サポートする Rust の最小バージョンは 1.88 です 🦀。
フィードバックをお寄せください
Qt Bridge for Rust はまだベータ版であり、皆様からのフィードバックが Technology Preview へ向けた進化を後押しします。フォーラム、Discord、またはバグトラッカーを通じて、あらゆるフィードバックを歓迎しています。もちろん、このブログへのコメントも歓迎します。
また、私たちは今後開催されるさまざまなカンファレンスにも参加する予定です:
-
KDE Akademy (19.-24.09.26),
-
NDC Techtown (21.-24.09.26),
-
EuroRust (14.-17.10.26),
-
そして、もちろん Qt Contributor Summit (27.-30.10.26)
Rust についてぜひ会場でお声がけください! 👋