From 327a46f32334944bd16be09a6978797e3c630370 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Tue, 8 Oct 2024 15:36:22 +0200 Subject: [PATCH] ffi: add our own macro for processing exports Including one that will always warn if used with async functions, and the other one always setting the tokio runtime if used for async stuff. --- Cargo.lock | 12 +++ Cargo.toml | 1 + bindings/matrix-sdk-crypto-ffi/Cargo.toml | 1 + .../src/backup_recovery_key.rs | 2 +- .../src/dehydrated_devices.rs | 6 +- bindings/matrix-sdk-crypto-ffi/src/lib.rs | 18 ++--- bindings/matrix-sdk-crypto-ffi/src/logger.rs | 4 +- bindings/matrix-sdk-crypto-ffi/src/machine.rs | 2 +- .../matrix-sdk-crypto-ffi/src/verification.rs | 14 ++-- bindings/matrix-sdk-ffi/Cargo.toml | 1 + bindings/matrix-sdk-ffi/src/authentication.rs | 4 +- bindings/matrix-sdk-ffi/src/client.rs | 18 ++--- bindings/matrix-sdk-ffi/src/client_builder.rs | 6 +- bindings/matrix-sdk-ffi/src/element.rs | 2 +- bindings/matrix-sdk-ffi/src/encryption.rs | 16 ++-- bindings/matrix-sdk-ffi/src/event.rs | 2 +- bindings/matrix-sdk-ffi/src/lib.rs | 2 +- bindings/matrix-sdk-ffi/src/notification.rs | 2 +- .../src/notification_settings.rs | 4 +- bindings/matrix-sdk-ffi/src/platform.rs | 2 +- bindings/matrix-sdk-ffi/src/room.rs | 12 +-- .../src/room_directory_search.rs | 4 +- bindings/matrix-sdk-ffi/src/room_list.rs | 20 ++--- bindings/matrix-sdk-ffi/src/room_member.rs | 6 +- bindings/matrix-sdk-ffi/src/ruma.rs | 16 ++-- .../src/session_verification.rs | 6 +- bindings/matrix-sdk-ffi/src/sync_service.rs | 8 +- bindings/matrix-sdk-ffi/src/task_handle.rs | 2 +- .../matrix-sdk-ffi/src/timeline/content.rs | 2 +- bindings/matrix-sdk-ffi/src/timeline/mod.rs | 18 ++--- .../src/timeline_event_filter.rs | 2 +- bindings/matrix-sdk-ffi/src/tracing.rs | 4 +- bindings/matrix-sdk-ffi/src/widget.rs | 14 ++-- crates/matrix-sdk/Cargo.toml | 3 +- .../matrix-sdk/src/oidc/auth_code_builder.rs | 2 +- testing/matrix-sdk-ffi-macros/Cargo.toml | 24 ++++++ testing/matrix-sdk-ffi-macros/README.md | 14 ++++ testing/matrix-sdk-ffi-macros/src/lib.rs | 78 +++++++++++++++++++ 38 files changed, 243 insertions(+), 111 deletions(-) create mode 100644 testing/matrix-sdk-ffi-macros/Cargo.toml create mode 100644 testing/matrix-sdk-ffi-macros/README.md create mode 100644 testing/matrix-sdk-ffi-macros/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 0f672765b80..88a5555799d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3136,6 +3136,7 @@ dependencies = [ "mas-oidc-client", "matrix-sdk-base", "matrix-sdk-common", + "matrix-sdk-ffi-macros", "matrix-sdk-indexeddb", "matrix-sdk-sqlite", "matrix-sdk-test", @@ -3293,6 +3294,7 @@ dependencies = [ "js_int", "matrix-sdk-common", "matrix-sdk-crypto", + "matrix-sdk-ffi-macros", "matrix-sdk-sqlite", "pbkdf2", "rand", @@ -3323,6 +3325,7 @@ dependencies = [ "language-tags", "log-panics", "matrix-sdk", + "matrix-sdk-ffi-macros", "matrix-sdk-ui", "mime", "once_cell", @@ -3344,6 +3347,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "matrix-sdk-ffi-macros" +version = "0.7.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + [[package]] name = "matrix-sdk-indexeddb" version = "0.7.0" diff --git a/Cargo.toml b/Cargo.toml index 456d92b226a..448a450312f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,6 +85,7 @@ matrix-sdk = { path = "crates/matrix-sdk", version = "0.7.0", default-features = matrix-sdk-base = { path = "crates/matrix-sdk-base", version = "0.7.0" } matrix-sdk-common = { path = "crates/matrix-sdk-common", version = "0.7.0" } matrix-sdk-crypto = { path = "crates/matrix-sdk-crypto", version = "0.7.0" } +matrix-sdk-ffi-macros = { path = "testing/matrix-sdk-ffi-macros", version = "0.7.0" } matrix-sdk-indexeddb = { path = "crates/matrix-sdk-indexeddb", version = "0.7.0", default-features = false } matrix-sdk-qrcode = { path = "crates/matrix-sdk-qrcode", version = "0.7.0" } matrix-sdk-sqlite = { path = "crates/matrix-sdk-sqlite", version = "0.7.0", default-features = false } diff --git a/bindings/matrix-sdk-crypto-ffi/Cargo.toml b/bindings/matrix-sdk-crypto-ffi/Cargo.toml index 50dcaf137fe..3432c965ef8 100644 --- a/bindings/matrix-sdk-crypto-ffi/Cargo.toml +++ b/bindings/matrix-sdk-crypto-ffi/Cargo.toml @@ -26,6 +26,7 @@ futures-util = { workspace = true } hmac = "0.12.1" http = { workspace = true } matrix-sdk-common = { workspace = true, features = ["uniffi"] } +matrix-sdk-ffi-macros = { workspace = true } pbkdf2 = "0.12.2" rand = { workspace = true } ruma = { workspace = true } diff --git a/bindings/matrix-sdk-crypto-ffi/src/backup_recovery_key.rs b/bindings/matrix-sdk-crypto-ffi/src/backup_recovery_key.rs index b9b97062e6a..05c17b8aec5 100644 --- a/bindings/matrix-sdk-crypto-ffi/src/backup_recovery_key.rs +++ b/bindings/matrix-sdk-crypto-ffi/src/backup_recovery_key.rs @@ -69,7 +69,7 @@ impl BackupRecoveryKey { const PBKDF_ROUNDS: i32 = 500_000; } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl BackupRecoveryKey { /// Create a new random [`BackupRecoveryKey`]. #[allow(clippy::new_without_default)] diff --git a/bindings/matrix-sdk-crypto-ffi/src/dehydrated_devices.rs b/bindings/matrix-sdk-crypto-ffi/src/dehydrated_devices.rs index c57d5ae4bbf..585eb7a9be1 100644 --- a/bindings/matrix-sdk-crypto-ffi/src/dehydrated_devices.rs +++ b/bindings/matrix-sdk-crypto-ffi/src/dehydrated_devices.rs @@ -53,7 +53,7 @@ impl Drop for DehydratedDevices { } } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl DehydratedDevices { pub fn create(&self) -> Result, DehydrationError> { let inner = self.runtime.block_on(self.inner.create())?; @@ -107,7 +107,7 @@ impl Drop for RehydratedDevice { } } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl RehydratedDevice { pub fn receive_events(&self, events: String) -> Result<(), crate::CryptoStoreError> { let events: Vec> = serde_json::from_str(&events)?; @@ -133,7 +133,7 @@ impl Drop for DehydratedDevice { } } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl DehydratedDevice { pub fn keys_for_upload( &self, diff --git a/bindings/matrix-sdk-crypto-ffi/src/lib.rs b/bindings/matrix-sdk-crypto-ffi/src/lib.rs index 769c7876fef..125abd99ed3 100644 --- a/bindings/matrix-sdk-crypto-ffi/src/lib.rs +++ b/bindings/matrix-sdk-crypto-ffi/src/lib.rs @@ -196,7 +196,7 @@ impl From for MigrationError { /// /// * `progress_listener` - A callback that can be used to introspect the /// progress of the migration. -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] pub fn migrate( data: MigrationData, path: String, @@ -359,7 +359,7 @@ async fn save_changes( /// /// * `progress_listener` - A callback that can be used to introspect the /// progress of the migration. -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] pub fn migrate_sessions( data: SessionMigrationData, path: String, @@ -532,7 +532,7 @@ fn collect_sessions( /// * `passphrase` - The passphrase that should be used to encrypt the data at /// rest in the Sqlite store. **Warning**, if no passphrase is given, the /// store and all its data will remain unencrypted. -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] pub fn migrate_room_settings( room_settings: HashMap, path: String, @@ -558,7 +558,7 @@ pub fn migrate_room_settings( } /// Callback that will be passed over the FFI to report progress -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait ProgressListener { /// The callback that should be called on the Rust side /// @@ -794,7 +794,7 @@ pub struct BackupKeys { backup_version: String, } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl BackupKeys { /// Get the recovery key that we're holding on to. pub fn recovery_key(&self) -> Arc { @@ -891,7 +891,7 @@ fn parse_user_id(user_id: &str) -> Result { ruma::UserId::parse(user_id).map_err(|e| CryptoStoreError::InvalidUserId(user_id.to_owned(), e)) } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] fn version_info() -> VersionInfo { VersionInfo { version: matrix_sdk_crypto::VERSION.to_owned(), @@ -915,12 +915,12 @@ pub struct VersionInfo { pub git_description: String, } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] fn version() -> String { matrix_sdk_crypto::VERSION.to_owned() } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] fn vodozemac_version() -> String { vodozemac::VERSION.to_owned() } @@ -935,7 +935,7 @@ pub struct PkEncryption { inner: matrix_sdk_crypto::vodozemac::pk_encryption::PkEncryption, } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl PkEncryption { /// Create a new [`PkEncryption`] object from a `Curve25519PublicKey` /// encoded as Base64. diff --git a/bindings/matrix-sdk-crypto-ffi/src/logger.rs b/bindings/matrix-sdk-crypto-ffi/src/logger.rs index 328999ea15a..6b53a352a77 100644 --- a/bindings/matrix-sdk-crypto-ffi/src/logger.rs +++ b/bindings/matrix-sdk-crypto-ffi/src/logger.rs @@ -7,7 +7,7 @@ use tracing_subscriber::{fmt::MakeWriter, EnvFilter}; /// Trait that can be used to forward Rust logs over FFI to a language specific /// logger. -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait Logger: Send { /// Called every time the Rust side wants to post a log line. fn log(&self, log_line: String); @@ -42,7 +42,7 @@ pub struct LoggerWrapper { } /// Set the logger that should be used to forward Rust logs over FFI. -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] pub fn set_logger(logger: Box) { let logger = LoggerWrapper { inner: Arc::new(Mutex::new(logger)) }; diff --git a/bindings/matrix-sdk-crypto-ffi/src/machine.rs b/bindings/matrix-sdk-crypto-ffi/src/machine.rs index 8bb1fedd718..da12075bfe4 100644 --- a/bindings/matrix-sdk-crypto-ffi/src/machine.rs +++ b/bindings/matrix-sdk-crypto-ffi/src/machine.rs @@ -178,7 +178,7 @@ impl From for SignatureVerification { } } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl OlmMachine { /// Create a new `OlmMachine` /// diff --git a/bindings/matrix-sdk-crypto-ffi/src/verification.rs b/bindings/matrix-sdk-crypto-ffi/src/verification.rs index 179200503ba..e8c31c4a3a8 100644 --- a/bindings/matrix-sdk-crypto-ffi/src/verification.rs +++ b/bindings/matrix-sdk-crypto-ffi/src/verification.rs @@ -15,7 +15,7 @@ use crate::{CryptoStoreError, OutgoingVerificationRequest, SignatureUploadReques /// Listener that will be passed over the FFI to report changes to a SAS /// verification. -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait SasListener: Send { /// The callback that should be called on the Rust side /// @@ -82,7 +82,7 @@ pub struct Verification { pub(crate) runtime: Handle, } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl Verification { /// Try to represent the `Verification` as an `Sas` verification object, /// returns `None` if the verification is not a `Sas` verification. @@ -112,7 +112,7 @@ pub struct Sas { pub(crate) runtime: Handle, } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl Sas { /// Get the user id of the other side. pub fn other_user_id(&self) -> String { @@ -276,7 +276,7 @@ impl Sas { /// Listener that will be passed over the FFI to report changes to a QrCode /// verification. -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait QrCodeListener: Send { /// The callback that should be called on the Rust side /// @@ -328,7 +328,7 @@ pub struct QrCode { pub(crate) runtime: Handle, } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl QrCode { /// Get the user id of the other side. pub fn other_user_id(&self) -> String { @@ -522,7 +522,7 @@ pub struct ConfirmVerificationResult { /// Listener that will be passed over the FFI to report changes to a /// verification request. -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait VerificationRequestListener: Send { /// The callback that should be called on the Rust side /// @@ -562,7 +562,7 @@ pub struct VerificationRequest { pub(crate) runtime: Handle, } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl VerificationRequest { /// The id of the other user that is participating in this verification /// request. diff --git a/bindings/matrix-sdk-ffi/Cargo.toml b/bindings/matrix-sdk-ffi/Cargo.toml index abab2bff692..02400423b17 100644 --- a/bindings/matrix-sdk-ffi/Cargo.toml +++ b/bindings/matrix-sdk-ffi/Cargo.toml @@ -28,6 +28,7 @@ eyeball-im = { workspace = true } extension-trait = "1.0.1" futures-util = { workspace = true } log-panics = { version = "2", features = ["with-backtrace"] } +matrix-sdk-ffi-macros = { workspace = true } matrix-sdk-ui = { workspace = true, features = ["uniffi"] } mime = "0.3.16" once_cell = { workspace = true } diff --git a/bindings/matrix-sdk-ffi/src/authentication.rs b/bindings/matrix-sdk-ffi/src/authentication.rs index 37aaff4e8e2..3a22244c519 100644 --- a/bindings/matrix-sdk-ffi/src/authentication.rs +++ b/bindings/matrix-sdk-ffi/src/authentication.rs @@ -29,7 +29,7 @@ pub struct HomeserverLoginDetails { pub(crate) supports_password_login: bool, } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl HomeserverLoginDetails { /// The URL of the currently configured homeserver. pub fn url(&self) -> String { @@ -62,7 +62,7 @@ pub struct SsoHandler { pub(crate) url: String, } -#[uniffi::export(async_runtime = "tokio")] +#[matrix_sdk_ffi_macros::export_async] impl SsoHandler { /// Returns the URL for starting SSO authentication. The URL should be /// opened in a web view. Once the web view succeeds, call `finish` with diff --git a/bindings/matrix-sdk-ffi/src/client.rs b/bindings/matrix-sdk-ffi/src/client.rs index e37cbba6f8b..314b19eab1e 100644 --- a/bindings/matrix-sdk-ffi/src/client.rs +++ b/bindings/matrix-sdk-ffi/src/client.rs @@ -140,25 +140,25 @@ impl From for RumaPushFormat { } } -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait ClientDelegate: Sync + Send { fn did_receive_auth_error(&self, is_soft_logout: bool); fn did_refresh_tokens(&self); } -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait ClientSessionDelegate: Sync + Send { fn retrieve_session_from_keychain(&self, user_id: String) -> Result; fn save_session_in_keychain(&self, session: Session); } -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait ProgressWatcher: Send + Sync { fn transmission_progress(&self, progress: TransmissionProgress); } /// A listener to the global (client-wide) error reporter of the send queue. -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait SendQueueRoomErrorListener: Sync + Send { /// Called every time the send queue has ran into an error for a given room, /// which will disable the send queue for that particular room. @@ -260,7 +260,7 @@ impl Client { } } -#[uniffi::export(async_runtime = "tokio")] +#[matrix_sdk_ffi_macros::export_async] impl Client { /// Information about login options for the client's homeserver. pub async fn homeserver_login_details(&self) -> Arc { @@ -526,7 +526,7 @@ impl Client { } } -#[uniffi::export(async_runtime = "tokio")] +#[matrix_sdk_ffi_macros::export_async] impl Client { /// The sliding sync version. pub fn sliding_sync_version(&self) -> SlidingSyncVersion { @@ -1092,7 +1092,7 @@ impl Client { } } -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait IgnoredUsersListener: Sync + Send { fn call(&self, ignored_user_ids: Vec); } @@ -1649,7 +1649,7 @@ impl From for AccountManagementActionFull { } } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] fn gen_transaction_id() -> String { TransactionId::new().to_string() } @@ -1667,7 +1667,7 @@ impl MediaFileHandle { } } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl MediaFileHandle { /// Get the media file's path. pub fn path(&self) -> Result { diff --git a/bindings/matrix-sdk-ffi/src/client_builder.rs b/bindings/matrix-sdk-ffi/src/client_builder.rs index ec0522fafd2..9b817dd4f66 100644 --- a/bindings/matrix-sdk-ffi/src/client_builder.rs +++ b/bindings/matrix-sdk-ffi/src/client_builder.rs @@ -47,7 +47,7 @@ pub struct QrCodeData { inner: qrcode::QrCodeData, } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl QrCodeData { /// Attempt to decode a slice of bytes into a [`QrCodeData`] object. /// @@ -159,7 +159,7 @@ pub enum QrLoginProgress { Done, } -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait QrLoginProgressListener: Sync + Send { fn on_update(&self, state: QrLoginProgress); } @@ -270,7 +270,7 @@ pub struct ClientBuilder { request_config: Option, } -#[uniffi::export(async_runtime = "tokio")] +#[matrix_sdk_ffi_macros::export_async] impl ClientBuilder { #[uniffi::constructor] pub fn new() -> Arc { diff --git a/bindings/matrix-sdk-ffi/src/element.rs b/bindings/matrix-sdk-ffi/src/element.rs index 6ff2dff5b53..87722b4d278 100644 --- a/bindings/matrix-sdk-ffi/src/element.rs +++ b/bindings/matrix-sdk-ffi/src/element.rs @@ -16,7 +16,7 @@ pub struct ElementWellKnown { } /// Helper function to parse a string into a ElementWellKnown struct -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] pub fn make_element_well_known(string: String) -> Result { serde_json::from_str(&string).map_err(ClientError::new) } diff --git a/bindings/matrix-sdk-ffi/src/encryption.rs b/bindings/matrix-sdk-ffi/src/encryption.rs index 7f6e35b4aac..cd7c6e94fc1 100644 --- a/bindings/matrix-sdk-ffi/src/encryption.rs +++ b/bindings/matrix-sdk-ffi/src/encryption.rs @@ -23,22 +23,22 @@ pub struct Encryption { pub(crate) _client: Arc, } -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait BackupStateListener: Sync + Send { fn on_update(&self, status: BackupState); } -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait BackupSteadyStateListener: Sync + Send { fn on_update(&self, status: BackupUploadState); } -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait RecoveryStateListener: Sync + Send { fn on_update(&self, status: RecoveryState); } -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait VerificationStateListener: Sync + Send { fn on_update(&self, status: VerificationState); } @@ -162,7 +162,7 @@ impl From for RecoveryState { } } -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait EnableRecoveryProgressListener: Sync + Send { fn on_update(&self, status: EnableRecoveryProgress); } @@ -212,7 +212,7 @@ impl From for VerificationState { } } -#[uniffi::export(async_runtime = "tokio")] +#[matrix_sdk_ffi_macros::export_async] impl Encryption { /// Get the public ed25519 key of our own device. This is usually what is /// called the fingerprint of the device. @@ -432,7 +432,7 @@ pub struct UserIdentity { inner: matrix_sdk::encryption::identities::UserIdentity, } -#[uniffi::export(async_runtime = "tokio")] +#[matrix_sdk_ffi_macros::export_async] impl UserIdentity { /// Remember this identity, ensuring it does not result in a pin violation. /// @@ -468,7 +468,7 @@ pub struct IdentityResetHandle { pub(crate) inner: matrix_sdk::encryption::recovery::IdentityResetHandle, } -#[uniffi::export(async_runtime = "tokio")] +#[matrix_sdk_ffi_macros::export_async] impl IdentityResetHandle { /// Get the underlying [`CrossSigningResetAuthType`] this identity reset /// process is using. diff --git a/bindings/matrix-sdk-ffi/src/event.rs b/bindings/matrix-sdk-ffi/src/event.rs index 3cd4304a281..b5b98d792c8 100644 --- a/bindings/matrix-sdk-ffi/src/event.rs +++ b/bindings/matrix-sdk-ffi/src/event.rs @@ -20,7 +20,7 @@ use crate::{ #[derive(uniffi::Object)] pub struct TimelineEvent(pub(crate) AnySyncTimelineEvent); -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl TimelineEvent { pub fn event_id(&self) -> String { self.0.event_id().to_string() diff --git a/bindings/matrix-sdk-ffi/src/lib.rs b/bindings/matrix-sdk-ffi/src/lib.rs index 801887b6fee..0e404a848ff 100644 --- a/bindings/matrix-sdk-ffi/src/lib.rs +++ b/bindings/matrix-sdk-ffi/src/lib.rs @@ -44,7 +44,7 @@ use self::{ uniffi::include_scaffolding!("api"); -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] fn sdk_git_sha() -> String { env!("VERGEN_GIT_SHA").to_owned() } diff --git a/bindings/matrix-sdk-ffi/src/notification.rs b/bindings/matrix-sdk-ffi/src/notification.rs index eda3f6232a1..35d047b94a2 100644 --- a/bindings/matrix-sdk-ffi/src/notification.rs +++ b/bindings/matrix-sdk-ffi/src/notification.rs @@ -88,7 +88,7 @@ pub struct NotificationClient { pub(crate) _client: Arc, } -#[uniffi::export(async_runtime = "tokio")] +#[matrix_sdk_ffi_macros::export_async] impl NotificationClient { /// See also documentation of /// `MatrixNotificationClient::get_notification`. diff --git a/bindings/matrix-sdk-ffi/src/notification_settings.rs b/bindings/matrix-sdk-ffi/src/notification_settings.rs index f758a2fda97..1a01011a889 100644 --- a/bindings/matrix-sdk-ffi/src/notification_settings.rs +++ b/bindings/matrix-sdk-ffi/src/notification_settings.rs @@ -49,7 +49,7 @@ impl From for SdkRoomNotificationMode { } /// Delegate to notify of changes in push rules -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait NotificationSettingsDelegate: Sync + Send { fn settings_did_change(&self); } @@ -98,7 +98,7 @@ impl Drop for NotificationSettings { } } -#[uniffi::export(async_runtime = "tokio")] +#[matrix_sdk_ffi_macros::export_async] impl NotificationSettings { pub fn set_delegate(&self, delegate: Option>) { if let Some(delegate) = delegate { diff --git a/bindings/matrix-sdk-ffi/src/platform.rs b/bindings/matrix-sdk-ffi/src/platform.rs index 7e61b93a2fb..a811474f9f3 100644 --- a/bindings/matrix-sdk-ffi/src/platform.rs +++ b/bindings/matrix-sdk-ffi/src/platform.rs @@ -242,7 +242,7 @@ pub struct TracingConfiguration { write_to_files: Option, } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] pub fn setup_tracing(config: TracingConfiguration) { log_panics(); diff --git a/bindings/matrix-sdk-ffi/src/room.rs b/bindings/matrix-sdk-ffi/src/room.rs index d12a3f0c945..d5d36e57a19 100644 --- a/bindings/matrix-sdk-ffi/src/room.rs +++ b/bindings/matrix-sdk-ffi/src/room.rs @@ -82,7 +82,7 @@ impl Room { } } -#[uniffi::export(async_runtime = "tokio")] +#[matrix_sdk_ffi_macros::export_async] impl Room { pub fn id(&self) -> String { self.inner.room_id().to_string() @@ -861,7 +861,7 @@ impl Room { } /// Generates a `matrix.to` permalink to the given room alias. -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] pub fn matrix_to_room_alias_permalink( room_alias: String, ) -> std::result::Result { @@ -917,17 +917,17 @@ impl From for RoomPowerLevels { } } -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait RoomInfoListener: Sync + Send { fn call(&self, room_info: RoomInfo); } -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait TypingNotificationsListener: Sync + Send { fn call(&self, typing_user_ids: Vec); } -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait IdentityStatusChangeListener: Sync + Send { fn call(&self, identity_status_change: Vec); } @@ -943,7 +943,7 @@ impl RoomMembersIterator { } } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl RoomMembersIterator { fn len(&self) -> u32 { self.chunk_iterator.len() diff --git a/bindings/matrix-sdk-ffi/src/room_directory_search.rs b/bindings/matrix-sdk-ffi/src/room_directory_search.rs index b3af0058b94..0666b50e3b3 100644 --- a/bindings/matrix-sdk-ffi/src/room_directory_search.rs +++ b/bindings/matrix-sdk-ffi/src/room_directory_search.rs @@ -79,7 +79,7 @@ impl RoomDirectorySearch { } } -#[uniffi::export(async_runtime = "tokio")] +#[matrix_sdk_ffi_macros::export_async] impl RoomDirectorySearch { pub async fn next_page(&self) -> Result<(), ClientError> { let mut inner = self.inner.write().await; @@ -169,7 +169,7 @@ impl From> } } -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait RoomDirectorySearchEntriesListener: Send + Sync + Debug { fn on_update(&self, room_entries_update: Vec); } diff --git a/bindings/matrix-sdk-ffi/src/room_list.rs b/bindings/matrix-sdk-ffi/src/room_list.rs index b9e4dca9623..9f70e9e71f3 100644 --- a/bindings/matrix-sdk-ffi/src/room_list.rs +++ b/bindings/matrix-sdk-ffi/src/room_list.rs @@ -85,7 +85,7 @@ pub struct RoomListService { pub(crate) utd_hook: Option>, } -#[uniffi::export(async_runtime = "tokio")] +#[matrix_sdk_ffi_macros::export_async] impl RoomListService { fn state(&self, listener: Box) -> Arc { let state_stream = self.inner.state(); @@ -162,7 +162,7 @@ pub struct RoomList { inner: Arc, } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl RoomList { fn loading_state( &self, @@ -292,7 +292,7 @@ pub struct RoomListEntriesWithDynamicAdaptersResult { entries_stream: Arc, } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl RoomListEntriesWithDynamicAdaptersResult { fn controller(&self) -> Arc { self.controller.clone() @@ -370,17 +370,17 @@ impl From for RoomListLo } } -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait RoomListServiceStateListener: Send + Sync + Debug { fn on_update(&self, state: RoomListServiceState); } -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait RoomListLoadingStateListener: Send + Sync + Debug { fn on_update(&self, state: RoomListLoadingState); } -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait RoomListServiceSyncIndicatorListener: Send + Sync + Debug { fn on_update(&self, sync_indicator: RoomListServiceSyncIndicator); } @@ -443,7 +443,7 @@ impl RoomListEntriesUpdate { } } -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait RoomListEntriesListener: Send + Sync + Debug { fn on_update(&self, room_entries_update: Vec); } @@ -461,7 +461,7 @@ impl RoomListDynamicEntriesController { } } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl RoomListDynamicEntriesController { fn set_filter(&self, kind: RoomListEntriesDynamicFilterKind) -> bool { self.inner.set_filter(kind.into()) @@ -549,7 +549,7 @@ impl RoomListItem { } } -#[uniffi::export(async_runtime = "tokio")] +#[matrix_sdk_ffi_macros::export_async] impl RoomListItem { fn id(&self) -> String { self.inner.id().to_string() @@ -711,7 +711,7 @@ pub struct UnreadNotificationsCount { notification_count: u32, } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl UnreadNotificationsCount { fn highlight_count(&self) -> u32 { self.highlight_count diff --git a/bindings/matrix-sdk-ffi/src/room_member.rs b/bindings/matrix-sdk-ffi/src/room_member.rs index 7fe579b1154..96aed25a00f 100644 --- a/bindings/matrix-sdk-ffi/src/room_member.rs +++ b/bindings/matrix-sdk-ffi/src/room_member.rs @@ -42,20 +42,20 @@ impl From for Membershi } } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] pub fn suggested_role_for_power_level(power_level: i64) -> RoomMemberRole { // It's not possible to expose the constructor on the Enum through Uniffi ☹️ RoomMemberRole::suggested_role_for_power_level(power_level) } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] pub fn suggested_power_level_for_role(role: RoomMemberRole) -> i64 { // It's not possible to expose methods on an Enum through Uniffi ☹️ role.suggested_power_level() } /// Generates a `matrix.to` permalink to the given userID. -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] pub fn matrix_to_user_permalink(user_id: String) -> Result { let user_id = UserId::parse(user_id)?; Ok(user_id.matrix_to_uri().to_string()) diff --git a/bindings/matrix-sdk-ffi/src/ruma.rs b/bindings/matrix-sdk-ffi/src/ruma.rs index 20c00e62025..fa4bdbb95b5 100644 --- a/bindings/matrix-sdk-ffi/src/ruma.rs +++ b/bindings/matrix-sdk-ffi/src/ruma.rs @@ -90,7 +90,7 @@ impl From for ruma::api::client::uiaa::AuthData { /// Parse a matrix entity from a given URI, be it either /// a `matrix.to` link or a `matrix:` URI -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] pub fn parse_matrix_entity_from(uri: String) -> Option { if let Ok(matrix_uri) = RumaMatrixUri::parse(&uri) { return Some(MatrixEntity { @@ -154,33 +154,33 @@ impl From<&RumaMatrixId> for MatrixId { } } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] pub fn media_source_from_url(url: String) -> Arc { Arc::new(MediaSource::Plain(url.into())) } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] pub fn message_event_content_new( msgtype: MessageType, ) -> Result, ClientError> { Ok(Arc::new(RoomMessageEventContentWithoutRelation::new(msgtype.try_into()?))) } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] pub fn message_event_content_from_markdown( md: String, ) -> Arc { Arc::new(RoomMessageEventContentWithoutRelation::new(RumaMessageType::text_markdown(md))) } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] pub fn message_event_content_from_markdown_as_emote( md: String, ) -> Arc { Arc::new(RoomMessageEventContentWithoutRelation::new(RumaMessageType::emote_markdown(md))) } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] pub fn message_event_content_from_html( body: String, html_body: String, @@ -190,7 +190,7 @@ pub fn message_event_content_from_html( ))) } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] pub fn message_event_content_from_html_as_emote( body: String, html_body: String, @@ -918,7 +918,7 @@ impl From for PollKind { /// Creates a [`RoomMessageEventContentWithoutRelation`] given a /// [`MessageContent`] value. -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] pub fn content_without_relation_from_message( message: MessageContent, ) -> Result, ClientError> { diff --git a/bindings/matrix-sdk-ffi/src/session_verification.rs b/bindings/matrix-sdk-ffi/src/session_verification.rs index a34ecfa6aa3..f0cf5437425 100644 --- a/bindings/matrix-sdk-ffi/src/session_verification.rs +++ b/bindings/matrix-sdk-ffi/src/session_verification.rs @@ -20,7 +20,7 @@ pub struct SessionVerificationEmoji { description: String, } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl SessionVerificationEmoji { pub fn symbol(&self) -> String { self.symbol.clone() @@ -37,7 +37,7 @@ pub enum SessionVerificationData { Decimals { values: Vec }, } -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait SessionVerificationControllerDelegate: Sync + Send { fn did_accept_verification_request(&self); fn did_start_sas_verification(&self); @@ -58,7 +58,7 @@ pub struct SessionVerificationController { sas_verification: Arc>>, } -#[uniffi::export(async_runtime = "tokio")] +#[matrix_sdk_ffi_macros::export_async] impl SessionVerificationController { pub async fn is_verified(&self) -> Result { let device = diff --git a/bindings/matrix-sdk-ffi/src/sync_service.rs b/bindings/matrix-sdk-ffi/src/sync_service.rs index 329784c3e1b..3d3d30b0a66 100644 --- a/bindings/matrix-sdk-ffi/src/sync_service.rs +++ b/bindings/matrix-sdk-ffi/src/sync_service.rs @@ -51,7 +51,7 @@ impl From for SyncServiceState { } } -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait SyncServiceStateObserver: Send + Sync + Debug { fn on_update(&self, state: SyncServiceState); } @@ -62,7 +62,7 @@ pub struct SyncService { utd_hook: Option>, } -#[uniffi::export(async_runtime = "tokio")] +#[matrix_sdk_ffi_macros::export_async] impl SyncService { pub fn room_list_service(&self) -> Arc { Arc::new(RoomListService { @@ -110,7 +110,7 @@ impl SyncServiceBuilder { } } -#[uniffi::export(async_runtime = "tokio")] +#[matrix_sdk_ffi_macros::export_async] impl SyncServiceBuilder { pub fn with_cross_process_lock(self: Arc, app_identifier: Option) -> Arc { let this = unwrap_or_clone_arc(self); @@ -153,7 +153,7 @@ impl SyncServiceBuilder { } } -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait UnableToDecryptDelegate: Sync + Send { fn on_utd(&self, info: UnableToDecryptInfo); } diff --git a/bindings/matrix-sdk-ffi/src/task_handle.rs b/bindings/matrix-sdk-ffi/src/task_handle.rs index e1e50bf6fbe..5a593fa55fa 100644 --- a/bindings/matrix-sdk-ffi/src/task_handle.rs +++ b/bindings/matrix-sdk-ffi/src/task_handle.rs @@ -17,7 +17,7 @@ impl TaskHandle { } } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl TaskHandle { // Cancel a task handle. pub fn cancel(&self) { diff --git a/bindings/matrix-sdk-ffi/src/timeline/content.rs b/bindings/matrix-sdk-ffi/src/timeline/content.rs index 3705e3ccd59..e39f2c0798d 100644 --- a/bindings/matrix-sdk-ffi/src/timeline/content.rs +++ b/bindings/matrix-sdk-ffi/src/timeline/content.rs @@ -195,7 +195,7 @@ impl InReplyToDetails { } } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl InReplyToDetails { pub fn event_id(&self) -> String { self.event_id.clone() diff --git a/bindings/matrix-sdk-ffi/src/timeline/mod.rs b/bindings/matrix-sdk-ffi/src/timeline/mod.rs index 8ca950f5c02..9182fcf55fb 100644 --- a/bindings/matrix-sdk-ffi/src/timeline/mod.rs +++ b/bindings/matrix-sdk-ffi/src/timeline/mod.rs @@ -142,7 +142,7 @@ impl Timeline { } } -#[uniffi::export(async_runtime = "tokio")] +#[matrix_sdk_ffi_macros::export_async] impl Timeline { pub async fn add_listener(&self, listener: Box) -> Arc { let (timeline_items, timeline_stream) = self.inner.subscribe_batched().await; @@ -688,7 +688,7 @@ pub struct SendHandle { inner: Mutex>, } -#[uniffi::export(async_runtime = "tokio")] +#[matrix_sdk_ffi_macros::export_async] impl SendHandle { /// Try to abort the sending of the current event. /// @@ -723,12 +723,12 @@ pub enum FocusEventError { Other { msg: String }, } -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait TimelineListener: Sync + Send { fn on_update(&self, diff: Vec>); } -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait PaginationStatusListener: Sync + Send { fn on_update(&self, status: LiveBackPaginationStatus); } @@ -778,7 +778,7 @@ impl TimelineDiff { } } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl TimelineDiff { pub fn change(&self) -> TimelineChange { match self { @@ -878,7 +878,7 @@ impl TimelineItem { } } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl TimelineItem { pub fn as_event(self: Arc) -> Option { let event_item = self.0.as_event()?; @@ -1108,7 +1108,7 @@ impl From for Receipt { #[derive(uniffi::Object)] pub struct EventTimelineItemDebugInfoProvider(Arc); -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl EventTimelineItemDebugInfoProvider { fn get(&self) -> EventTimelineItemDebugInfo { EventTimelineItemDebugInfo { @@ -1202,7 +1202,7 @@ impl SendAttachmentJoinHandle { } } -#[uniffi::export(async_runtime = "tokio")] +#[matrix_sdk_ffi_macros::export_async] impl SendAttachmentJoinHandle { pub async fn join(&self) -> Result<(), RoomError> { let join_hdl = self.join_hdl.clone(); @@ -1274,7 +1274,7 @@ impl TryFrom for SdkEditedContent { #[derive(Clone, uniffi::Object)] pub struct EventShieldsProvider(Arc); -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl EventShieldsProvider { fn get_shields(&self, strict: bool) -> Option { self.0.get_shield(strict).map(Into::into) diff --git a/bindings/matrix-sdk-ffi/src/timeline_event_filter.rs b/bindings/matrix-sdk-ffi/src/timeline_event_filter.rs index 9d6472eaf4a..5da36b9b1e4 100644 --- a/bindings/matrix-sdk-ffi/src/timeline_event_filter.rs +++ b/bindings/matrix-sdk-ffi/src/timeline_event_filter.rs @@ -10,7 +10,7 @@ pub struct TimelineEventTypeFilter { inner: InnerTimelineEventTypeFilter, } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl TimelineEventTypeFilter { #[uniffi::constructor] pub fn include(event_types: Vec) -> Arc { diff --git a/bindings/matrix-sdk-ffi/src/tracing.rs b/bindings/matrix-sdk-ffi/src/tracing.rs index 9e1207d62fb..cc50f14a1e3 100644 --- a/bindings/matrix-sdk-ffi/src/tracing.rs +++ b/bindings/matrix-sdk-ffi/src/tracing.rs @@ -19,7 +19,7 @@ use tracing_core::{identify_callsite, metadata::Kind as MetadataKind}; /// level + target) it is called with. Please make sure that the number of /// different combinations of those parameters this can be called with is /// constant in the final executable. -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] fn log_event(file: String, line: Option, level: LogLevel, target: String, message: String) { static CALLSITES: Mutex> = Mutex::new(BTreeMap::new()); @@ -96,7 +96,7 @@ fn span_or_event_enabled(callsite: &'static DefaultCallsite) -> bool { #[derive(uniffi::Object)] pub struct Span(tracing::Span); -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl Span { /// Create a span originating at the given callsite (file, line and column). /// diff --git a/bindings/matrix-sdk-ffi/src/widget.rs b/bindings/matrix-sdk-ffi/src/widget.rs index 9cdd5856033..2e5ca65c8a1 100644 --- a/bindings/matrix-sdk-ffi/src/widget.rs +++ b/bindings/matrix-sdk-ffi/src/widget.rs @@ -15,7 +15,7 @@ pub struct WidgetDriverAndHandle { pub handle: Arc, } -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] pub fn make_widget_driver(settings: WidgetSettings) -> Result { let (driver, handle) = matrix_sdk::widget::WidgetDriver::new(settings.try_into()?); Ok(WidgetDriverAndHandle { @@ -29,7 +29,7 @@ pub fn make_widget_driver(settings: WidgetSettings) -> Result>); -#[uniffi::export(async_runtime = "tokio")] +#[matrix_sdk_ffi_macros::export_async] impl WidgetDriver { pub async fn run( &self, @@ -96,7 +96,7 @@ impl From for WidgetSettings { /// * `room` - A matrix room which is used to query the logged in username /// * `props` - Properties from the client that can be used by a widget to adapt /// to the client. e.g. language, font-scale... -#[uniffi::export(async_runtime = "tokio")] +#[matrix_sdk_ffi_macros::export_async] pub async fn generate_webview_url( widget_settings: WidgetSettings, room: Arc, @@ -241,7 +241,7 @@ impl From for matrix_sdk::widget::VirtualElemen /// /// * `props` - A struct containing the configuration parameters for a element /// call widget. -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] pub fn new_virtual_element_call_widget( props: VirtualElementCallWidgetOptions, ) -> Result { @@ -261,7 +261,7 @@ pub fn new_virtual_element_call_widget( /// Editing and extending the capabilities from this function is also possible, /// but should only be done as temporal workarounds until this function is /// adjusted -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] pub fn get_element_call_required_permissions( own_user_id: String, own_device_id: String, @@ -354,7 +354,7 @@ impl From for matrix_sdk::widget::ClientProperties { #[derive(uniffi::Object)] pub struct WidgetDriverHandle(matrix_sdk::widget::WidgetDriverHandle); -#[uniffi::export(async_runtime = "tokio")] +#[matrix_sdk_ffi_macros::export_async] impl WidgetDriverHandle { /// Receive a message from the widget driver. /// @@ -469,7 +469,7 @@ impl From for WidgetEventFilter { } } -#[uniffi::export(callback_interface)] +#[matrix_sdk_ffi_macros::export(callback_interface)] pub trait WidgetCapabilitiesProvider: Send + Sync { fn acquire_capabilities(&self, capabilities: WidgetCapabilities) -> WidgetCapabilities; } diff --git a/crates/matrix-sdk/Cargo.toml b/crates/matrix-sdk/Cargo.toml index 096ce0250e9..f2dcdf32933 100644 --- a/crates/matrix-sdk/Cargo.toml +++ b/crates/matrix-sdk/Cargo.toml @@ -44,7 +44,7 @@ sso-login = ["dep:axum", "dep:rand", "dep:tower"] image-proc = ["dep:image"] image-rayon = ["image-proc", "image?/rayon"] -uniffi = ["dep:uniffi", "matrix-sdk-base/uniffi"] +uniffi = ["dep:uniffi", "matrix-sdk-base/uniffi", "dep:matrix-sdk-ffi-macros"] experimental-oidc = [ "ruma/unstable-msc2967", @@ -92,6 +92,7 @@ language-tags = { version = "0.3.2", optional = true } mas-oidc-client = { version = "0.10.0", default-features = false, optional = true } matrix-sdk-base = { workspace = true } matrix-sdk-common = { workspace = true } +matrix-sdk-ffi-macros = { workspace = true, optional = true } matrix-sdk-indexeddb = { workspace = true, optional = true } matrix-sdk-sqlite = { workspace = true, optional = true } matrix-sdk-test = { workspace = true, optional = true } diff --git a/crates/matrix-sdk/src/oidc/auth_code_builder.rs b/crates/matrix-sdk/src/oidc/auth_code_builder.rs index 148c6ca7d7d..97b4c799743 100644 --- a/crates/matrix-sdk/src/oidc/auth_code_builder.rs +++ b/crates/matrix-sdk/src/oidc/auth_code_builder.rs @@ -246,7 +246,7 @@ pub struct OidcAuthorizationData { } #[cfg(feature = "uniffi")] -#[uniffi::export] +#[matrix_sdk_ffi_macros::export] impl OidcAuthorizationData { /// The login URL to use for authorization. pub fn login_url(&self) -> String { diff --git a/testing/matrix-sdk-ffi-macros/Cargo.toml b/testing/matrix-sdk-ffi-macros/Cargo.toml new file mode 100644 index 00000000000..54fb31ea7d5 --- /dev/null +++ b/testing/matrix-sdk-ffi-macros/Cargo.toml @@ -0,0 +1,24 @@ +[package] +description = "Helper macros to write FFI bindings" +edition = "2021" +homepage = "https://github.com/matrix-org/matrix-rust-sdk" +keywords = ["matrix", "chat", "messaging", "ruma"] +license = "Apache-2.0" +name = "matrix-sdk-ffi-macros" +readme = "README.md" +repository = "https://github.com/matrix-org/matrix-rust-sdk" +rust-version = { workspace = true } +version = "0.7.0" + +[lib] +proc-macro = true +test = false +doctest = false + +[dependencies] +proc-macro2 = "1.0.86" +quote = "1.0.18" +syn = { version = "2.0.43", features = ["full", "extra-traits"] } + +[lints] +workspace = true diff --git a/testing/matrix-sdk-ffi-macros/README.md b/testing/matrix-sdk-ffi-macros/README.md new file mode 100644 index 00000000000..17c29d67bbf --- /dev/null +++ b/testing/matrix-sdk-ffi-macros/README.md @@ -0,0 +1,14 @@ +[![Build Status](https://img.shields.io/travis/matrix-org/matrix-rust-sdk.svg?style=flat-square)](https://travis-ci.org/matrix-org/matrix-rust-sdk) +[![codecov](https://img.shields.io/codecov/c/github/matrix-org/matrix-rust-sdk/main.svg?style=flat-square)](https://codecov.io/gh/matrix-org/matrix-rust-sdk) +[![License](https://img.shields.io/badge/License-Apache%202.0-yellowgreen.svg?style=flat-square)](https://opensource.org/licenses/Apache-2.0) +[![#matrix-rust-sdk](https://img.shields.io/badge/matrix-%23matrix--rust--sdk-blue?style=flat-square)](https://matrix.to/#/#matrix-rust-sdk:matrix.org) + +# matrix-sdk-ffi-macros + +Internal macros used for the FFI layer (bindings) of the Rust Matrix SDK. + +**NOTE:** These are just macros that help build the matrix-rust-sdk bindings, you're probably +interested in the main [rust-sdk](https://github.com/matrix-org/matrix-rust-sdk/) crate. + +[Matrix]: https://matrix.org/ +[Rust]: https://www.rust-lang.org/ diff --git a/testing/matrix-sdk-ffi-macros/src/lib.rs b/testing/matrix-sdk-ffi-macros/src/lib.rs new file mode 100644 index 00000000000..6c55aa0c797 --- /dev/null +++ b/testing/matrix-sdk-ffi-macros/src/lib.rs @@ -0,0 +1,78 @@ +// Copyright 2024 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use proc_macro::TokenStream; +use quote::quote; +use syn::{spanned::Spanned as _, ImplItem, Item}; + +/// Attribute to always specify the async runtime parameter for the `uniffi` +/// export macros. +#[proc_macro_attribute] +pub fn export_async(_attr: TokenStream, item: TokenStream) -> TokenStream { + let item = proc_macro2::TokenStream::from(item); + + quote! { + #[uniffi::export(async_runtime = "tokio")] + #item + } + .into() +} + +/// Attribute to always specify the async runtime parameter for the `uniffi` +/// export macros. +#[proc_macro_attribute] +pub fn export(attr: TokenStream, item: TokenStream) -> TokenStream { + let run_checks = || { + let item: Item = syn::parse(item.clone())?; + if let Item::Fn(fun) = &item { + // Fail compilation if the function is async. + if fun.sig.asyncness.is_some() { + let error = syn::Error::new( + fun.span(), + "async function must be exported with #[export_async]", + ); + return Err(error); + } + } else if let Item::Impl(blk) = &item { + // Fail compilation if at least one function in the impl block is async. + for item in &blk.items { + if let ImplItem::Fn(fun) = item { + if fun.sig.asyncness.is_some() { + let error = syn::Error::new( + blk.span(), + "impl block with async functions must be exported with #[export_async]", + ); + return Err(error); + } + } + } + } + + Ok(()) + }; + + let maybe_error = + if let Err(err) = run_checks() { Some(err.into_compile_error()) } else { None }; + + let item = proc_macro2::TokenStream::from(item); + let attr = proc_macro2::TokenStream::from(attr); + + quote! { + #maybe_error + + #[uniffi::export(#attr)] + #item + } + .into() +}