Взаємодія з C++

Спільнота Rust пропонує кілька варіантів взаємодії C++/Rust, при цьому постійно розробляються нові інструменти. Наразі у Chromium використовується інструмент під назвою CXX.

Ви описуєте всю вашу мовну границю мовою визначення інтерфейсів (яка дуже схожа на Rust), а потім інструменти CXX генерують оголошення для функцій і типів як на Rust, так і на C++.

Overview diagram of cxx, showing that the same interface definition is used to create both C++ and Rust side code which then communicate via a lowest common denominator C API

Перегляньте підручник з CXX, щоб отримати повний приклад використання цього.

Поговоріть про схему. Поясніть, що за лаштунками відбувається те саме, що ви робили раніше. Зазначте, що автоматизація процесу має такі переваги:

  • Інструмент гарантує, що сторони C++ та Rust збігаються (наприклад, ви отримаєте помилки компіляції, якщо #[cxx::bridge] не збігається з фактичними визначеннями C++ або Rust, а з несинхронізованими ручними прив'язками ви отримаєте Undefined Behavior).
  • Інструмент автоматизує генерацію заглушок FFI (невеликих, C-ABI-сумісних, вільних функцій) для не-C функціоналу (наприклад, увімкнення викликів FFI в методи Rust або C++; ручне прив'язування вимагало б написання таких вільних функцій верхнього рівня вручну).
  • Інструмент і бібліотека можуть працювати з набором основних типів, наприклад:
    • &[T] можна передавати через межу FFI, навіть якщо це не гарантує певного ABI або розміщення пам'яті. При ручному зв'язуванні std::span<T> / &[T] потрібно вручну деструктурувати і відновити з вказівника і довжини - це може призвести до помилок, оскільки кожна мова представляє порожні зрізи дещо по-різному
    • Розумні вказівники типу std::unique_ptr<T>, std::shared_ptr<T> та/або Box підтримуються за замовчуванням. При ручному прив'язуванні потрібно було б передавати C-ABI-сумісні необроблені вказівники, що збільшило б ризики для тривалості життя та безпеки пам'яті.
    • Типи rust::String і CxxString розуміють і підтримують відмінності у представленні рядків у різних мовах (наприклад, rust::String::lossy може створити рядок Rust із вхідних даних не у форматі UTF8, а rust::String::c_str може завершити рядок NUL).