From 4b532ef7e0b1ca4fefab152d5b0c5bb2887d7797 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 31 Jan 2024 09:34:18 +0000 Subject: [PATCH] Bump SDK version to 0.1.96 (matrix-rust-sdk to a356a20c3d0e97652fc95b3ff4f28283808ea23e) --- buildSrc/src/main/kotlin/BuildVersionsSDK.kt | 2 +- .../rustcomponents/sdk/matrix_sdk_ffi.kt | 645 +++++++++++++++-- .../kotlin/uniffi/matrix_sdk/matrix_sdk.kt | 642 +++++++++++++++++ .../uniffi/matrix_sdk_base/matrix_sdk_base.kt | 655 ++++++++++++++++++ 4 files changed, 1903 insertions(+), 41 deletions(-) create mode 100644 sdk/sdk-android/src/main/kotlin/uniffi/matrix_sdk/matrix_sdk.kt create mode 100644 sdk/sdk-android/src/main/kotlin/uniffi/matrix_sdk_base/matrix_sdk_base.kt diff --git a/buildSrc/src/main/kotlin/BuildVersionsSDK.kt b/buildSrc/src/main/kotlin/BuildVersionsSDK.kt index 2ec1840..e9d09fe 100644 --- a/buildSrc/src/main/kotlin/BuildVersionsSDK.kt +++ b/buildSrc/src/main/kotlin/BuildVersionsSDK.kt @@ -1,5 +1,5 @@ object BuildVersionsSDK { const val majorVersion = 0 const val minorVersion = 1 - const val patchVersion = 95 + const val patchVersion = 96 } diff --git a/sdk/sdk-android/src/main/kotlin/org/matrix/rustcomponents/sdk/matrix_sdk_ffi.kt b/sdk/sdk-android/src/main/kotlin/org/matrix/rustcomponents/sdk/matrix_sdk_ffi.kt index 50662a7..d594404 100644 --- a/sdk/sdk-android/src/main/kotlin/org/matrix/rustcomponents/sdk/matrix_sdk_ffi.kt +++ b/sdk/sdk-android/src/main/kotlin/org/matrix/rustcomponents/sdk/matrix_sdk_ffi.kt @@ -37,10 +37,16 @@ import kotlin.concurrent.withLock import kotlin.coroutines.resume import kotlinx.coroutines.CancellableContinuation import kotlinx.coroutines.suspendCancellableCoroutine +import uniffi.matrix_sdk.FfiConverterTypeRoomMemberRole +import uniffi.matrix_sdk.RoomMemberRole +import uniffi.matrix_sdk_base.FfiConverterTypeRoomNotableTags +import uniffi.matrix_sdk_base.RoomNotableTags import uniffi.matrix_sdk_ui.BackPaginationStatus import uniffi.matrix_sdk_ui.EventItemOrigin import uniffi.matrix_sdk_ui.FfiConverterTypeBackPaginationStatus import uniffi.matrix_sdk_ui.FfiConverterTypeEventItemOrigin +import uniffi.matrix_sdk.RustBuffer as RustBufferRoomMemberRole +import uniffi.matrix_sdk_base.RustBuffer as RustBufferRoomNotableTags import uniffi.matrix_sdk_ui.RustBuffer as RustBufferBackPaginationStatus import uniffi.matrix_sdk_ui.RustBuffer as RustBufferEventItemOrigin @@ -405,6 +411,7 @@ internal interface UniffiLib : Library { uniffiCallbackInterfaceRoomListLoadingStateListener.register(lib) uniffiCallbackInterfaceRoomListServiceStateListener.register(lib) uniffiCallbackInterfaceRoomListServiceSyncIndicatorListener.register(lib) + uniffiCallbackInterfaceRoomNotableTagsListener.register(lib) uniffiCallbackInterfaceSessionVerificationControllerDelegate.register(lib) uniffiCallbackInterfaceSyncServiceStateObserver.register(lib) uniffiCallbackInterfaceTimelineListener.register(lib) @@ -796,8 +803,6 @@ internal interface UniffiLib : Library { ): RustBuffer.ByValue fun uniffi_matrix_sdk_ffi_fn_method_room_own_user_id(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue - fun uniffi_matrix_sdk_ffi_fn_method_room_poll_history(`ptr`: Pointer, - ): Pointer fun uniffi_matrix_sdk_ffi_fn_method_room_redact(`ptr`: Pointer,`eventId`: RustBuffer.ByValue,`reason`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Unit fun uniffi_matrix_sdk_ffi_fn_method_room_remove_avatar(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, @@ -810,6 +815,8 @@ internal interface UniffiLib : Library { ): Unit fun uniffi_matrix_sdk_ffi_fn_method_room_set_topic(`ptr`: Pointer,`topic`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Unit + fun uniffi_matrix_sdk_ffi_fn_method_room_subscribe_to_notable_tags(`ptr`: Pointer,`listener`: Long,uniffi_out_err: UniffiRustCallStatus, + ): Pointer fun uniffi_matrix_sdk_ffi_fn_method_room_subscribe_to_room_info_updates(`ptr`: Pointer,`listener`: Long,uniffi_out_err: UniffiRustCallStatus, ): Pointer fun uniffi_matrix_sdk_ffi_fn_method_room_timeline(`ptr`: Pointer, @@ -858,8 +865,12 @@ internal interface UniffiLib : Library { ): Byte fun uniffi_matrix_sdk_ffi_fn_method_roomlistitem_id(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue + fun uniffi_matrix_sdk_ffi_fn_method_roomlistitem_init_timeline(`ptr`: Pointer,`eventTypeFilter`: RustBuffer.ByValue, + ): Pointer fun uniffi_matrix_sdk_ffi_fn_method_roomlistitem_is_direct(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, ): Byte + fun uniffi_matrix_sdk_ffi_fn_method_roomlistitem_is_timeline_initialized(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Byte fun uniffi_matrix_sdk_ffi_fn_method_roomlistitem_latest_event(`ptr`: Pointer, ): Pointer fun uniffi_matrix_sdk_ffi_fn_method_roomlistitem_name(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, @@ -926,6 +937,8 @@ internal interface UniffiLib : Library { ): Long fun uniffi_matrix_sdk_ffi_fn_method_roommember_power_level(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, ): Long + fun uniffi_matrix_sdk_ffi_fn_method_roommember_suggested_role_for_power_level(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): RustBufferRoomMemberRole.ByValue fun uniffi_matrix_sdk_ffi_fn_method_roommember_unignore(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, ): Unit fun uniffi_matrix_sdk_ffi_fn_method_roommember_user_id(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, @@ -1100,6 +1113,14 @@ internal interface UniffiLib : Library { ): RustBuffer.ByValue fun uniffi_matrix_sdk_ffi_fn_method_timelineevent_timestamp(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, ): Long + fun uniffi_matrix_sdk_ffi_fn_clone_timelineeventtypefilter(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Pointer + fun uniffi_matrix_sdk_ffi_fn_free_timelineeventtypefilter(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Unit + fun uniffi_matrix_sdk_ffi_fn_constructor_timelineeventtypefilter_exclude(`eventTypes`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, + ): Pointer + fun uniffi_matrix_sdk_ffi_fn_constructor_timelineeventtypefilter_include(`eventTypes`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, + ): Pointer fun uniffi_matrix_sdk_ffi_fn_clone_timelineitem(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, ): Pointer fun uniffi_matrix_sdk_ffi_fn_free_timelineitem(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, @@ -1172,6 +1193,8 @@ internal interface UniffiLib : Library { ): Unit fun uniffi_matrix_sdk_ffi_fn_init_callback_roomlistservicesyncindicatorlistener(`handle`: ForeignCallback, ): Unit + fun uniffi_matrix_sdk_ffi_fn_init_callback_roomnotabletagslistener(`handle`: ForeignCallback, + ): Unit fun uniffi_matrix_sdk_ffi_fn_init_callback_sessionverificationcontrollerdelegate(`handle`: ForeignCallback, ): Unit fun uniffi_matrix_sdk_ffi_fn_init_callback_syncservicestateobserver(`handle`: ForeignCallback, @@ -1664,8 +1687,6 @@ internal interface UniffiLib : Library { ): Short fun uniffi_matrix_sdk_ffi_checksum_method_room_own_user_id( ): Short - fun uniffi_matrix_sdk_ffi_checksum_method_room_poll_history( - ): Short fun uniffi_matrix_sdk_ffi_checksum_method_room_redact( ): Short fun uniffi_matrix_sdk_ffi_checksum_method_room_remove_avatar( @@ -1678,6 +1699,8 @@ internal interface UniffiLib : Library { ): Short fun uniffi_matrix_sdk_ffi_checksum_method_room_set_topic( ): Short + fun uniffi_matrix_sdk_ffi_checksum_method_room_subscribe_to_notable_tags( + ): Short fun uniffi_matrix_sdk_ffi_checksum_method_room_subscribe_to_room_info_updates( ): Short fun uniffi_matrix_sdk_ffi_checksum_method_room_timeline( @@ -1714,8 +1737,12 @@ internal interface UniffiLib : Library { ): Short fun uniffi_matrix_sdk_ffi_checksum_method_roomlistitem_id( ): Short + fun uniffi_matrix_sdk_ffi_checksum_method_roomlistitem_init_timeline( + ): Short fun uniffi_matrix_sdk_ffi_checksum_method_roomlistitem_is_direct( ): Short + fun uniffi_matrix_sdk_ffi_checksum_method_roomlistitem_is_timeline_initialized( + ): Short fun uniffi_matrix_sdk_ffi_checksum_method_roomlistitem_latest_event( ): Short fun uniffi_matrix_sdk_ffi_checksum_method_roomlistitem_name( @@ -1774,6 +1801,8 @@ internal interface UniffiLib : Library { ): Short fun uniffi_matrix_sdk_ffi_checksum_method_roommember_power_level( ): Short + fun uniffi_matrix_sdk_ffi_checksum_method_roommember_suggested_role_for_power_level( + ): Short fun uniffi_matrix_sdk_ffi_checksum_method_roommember_unignore( ): Short fun uniffi_matrix_sdk_ffi_checksum_method_roommember_user_id( @@ -1934,6 +1963,10 @@ internal interface UniffiLib : Library { ): Short fun uniffi_matrix_sdk_ffi_checksum_constructor_span_new( ): Short + fun uniffi_matrix_sdk_ffi_checksum_constructor_timelineeventtypefilter_exclude( + ): Short + fun uniffi_matrix_sdk_ffi_checksum_constructor_timelineeventtypefilter_include( + ): Short fun uniffi_matrix_sdk_ffi_checksum_method_backpaginationstatuslistener_on_update( ): Short fun uniffi_matrix_sdk_ffi_checksum_method_backupstatelistener_on_update( @@ -1966,6 +1999,8 @@ internal interface UniffiLib : Library { ): Short fun uniffi_matrix_sdk_ffi_checksum_method_roomlistservicesyncindicatorlistener_on_update( ): Short + fun uniffi_matrix_sdk_ffi_checksum_method_roomnotabletagslistener_call( + ): Short fun uniffi_matrix_sdk_ffi_checksum_method_sessionverificationcontrollerdelegate_did_accept_verification_request( ): Short fun uniffi_matrix_sdk_ffi_checksum_method_sessionverificationcontrollerdelegate_did_start_sas_verification( @@ -2514,9 +2549,6 @@ private fun uniffiCheckApiChecksums(lib: UniffiLib) { if (lib.uniffi_matrix_sdk_ffi_checksum_method_room_own_user_id() != 39510.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_matrix_sdk_ffi_checksum_method_room_poll_history() != 1091.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } if (lib.uniffi_matrix_sdk_ffi_checksum_method_room_redact() != 55672.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } @@ -2535,10 +2567,13 @@ private fun uniffiCheckApiChecksums(lib: UniffiLib) { if (lib.uniffi_matrix_sdk_ffi_checksum_method_room_set_topic() != 29413.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } + if (lib.uniffi_matrix_sdk_ffi_checksum_method_room_subscribe_to_notable_tags() != 3691.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } if (lib.uniffi_matrix_sdk_ffi_checksum_method_room_subscribe_to_room_info_updates() != 47774.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_matrix_sdk_ffi_checksum_method_room_timeline() != 57169.toShort()) { + if (lib.uniffi_matrix_sdk_ffi_checksum_method_room_timeline() != 701.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_matrix_sdk_ffi_checksum_method_room_topic() != 59745.toShort()) { @@ -2580,7 +2615,7 @@ private fun uniffiCheckApiChecksums(lib: UniffiLib) { if (lib.uniffi_matrix_sdk_ffi_checksum_method_roomlistitem_canonical_alias() != 63300.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_matrix_sdk_ffi_checksum_method_roomlistitem_full_room() != 12378.toShort()) { + if (lib.uniffi_matrix_sdk_ffi_checksum_method_roomlistitem_full_room() != 35618.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_matrix_sdk_ffi_checksum_method_roomlistitem_has_unread_notifications() != 49961.toShort()) { @@ -2589,9 +2624,15 @@ private fun uniffiCheckApiChecksums(lib: UniffiLib) { if (lib.uniffi_matrix_sdk_ffi_checksum_method_roomlistitem_id() != 41176.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } + if (lib.uniffi_matrix_sdk_ffi_checksum_method_roomlistitem_init_timeline() != 15676.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } if (lib.uniffi_matrix_sdk_ffi_checksum_method_roomlistitem_is_direct() != 46873.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } + if (lib.uniffi_matrix_sdk_ffi_checksum_method_roomlistitem_is_timeline_initialized() != 46855.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } if (lib.uniffi_matrix_sdk_ffi_checksum_method_roomlistitem_latest_event() != 41471.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } @@ -2679,6 +2720,9 @@ private fun uniffiCheckApiChecksums(lib: UniffiLib) { if (lib.uniffi_matrix_sdk_ffi_checksum_method_roommember_power_level() != 18720.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } + if (lib.uniffi_matrix_sdk_ffi_checksum_method_roommember_suggested_role_for_power_level() != 13704.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } if (lib.uniffi_matrix_sdk_ffi_checksum_method_roommember_unignore() != 18171.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } @@ -2919,6 +2963,12 @@ private fun uniffiCheckApiChecksums(lib: UniffiLib) { if (lib.uniffi_matrix_sdk_ffi_checksum_constructor_span_new() != 62579.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } + if (lib.uniffi_matrix_sdk_ffi_checksum_constructor_timelineeventtypefilter_exclude() != 48570.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_matrix_sdk_ffi_checksum_constructor_timelineeventtypefilter_include() != 21388.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } if (lib.uniffi_matrix_sdk_ffi_checksum_method_backpaginationstatuslistener_on_update() != 5891.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } @@ -2967,6 +3017,9 @@ private fun uniffiCheckApiChecksums(lib: UniffiLib) { if (lib.uniffi_matrix_sdk_ffi_checksum_method_roomlistservicesyncindicatorlistener_on_update() != 42394.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } + if (lib.uniffi_matrix_sdk_ffi_checksum_method_roomnotabletagslistener_call() != 33153.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } if (lib.uniffi_matrix_sdk_ffi_checksum_method_sessionverificationcontrollerdelegate_did_accept_verification_request() != 22759.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } @@ -6828,8 +6881,6 @@ public interface RoomInterface { fun `ownUserId`(): String - suspend fun `pollHistory`(): Timeline - /** * Redacts an event from the room. * @@ -6873,6 +6924,8 @@ public interface RoomInterface { */ fun `setTopic`(`topic`: String) + fun `subscribeToNotableTags`(`listener`: RoomNotableTagsListener): TaskHandle + fun `subscribeToRoomInfoUpdates`(`listener`: RoomInfoListener): TaskHandle suspend fun `timeline`(): Timeline @@ -7509,25 +7562,6 @@ open class Room : FFIObject, RoomInterface { } - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `pollHistory`() : Timeline { - return uniffiRustCallAsync( - callWithPointer { thisPtr -> - UniffiLib.INSTANCE.uniffi_matrix_sdk_ffi_fn_method_room_poll_history( - thisPtr, - - ) - }, - { future, callback, continuation -> UniffiLib.INSTANCE.ffi_matrix_sdk_ffi_rust_future_poll_pointer(future, callback, continuation) }, - { future, continuation -> UniffiLib.INSTANCE.ffi_matrix_sdk_ffi_rust_future_complete_pointer(future, continuation) }, - { future -> UniffiLib.INSTANCE.ffi_matrix_sdk_ffi_rust_future_free_pointer(future) }, - // lift function - { FfiConverterTypeTimeline.lift(it) }, - // Error FFI converter - UniffiNullRustCallStatusErrorHandler, - ) - } - /** * Redacts an event from the room. * @@ -7633,6 +7667,17 @@ open class Room : FFIObject, RoomInterface { } + override fun `subscribeToNotableTags`(`listener`: RoomNotableTagsListener): TaskHandle = + callWithPointer { + uniffiRustCall() { _status -> + UniffiLib.INSTANCE.uniffi_matrix_sdk_ffi_fn_method_room_subscribe_to_notable_tags(it, + FfiConverterTypeRoomNotableTagsListener.lower(`listener`), + _status) +} + }.let { + FfiConverterTypeTaskHandle.lift(it) + } + override fun `subscribeToRoomInfoUpdates`(`listener`: RoomInfoListener): TaskHandle = callWithPointer { uniffiRustCall() { _status -> @@ -7645,6 +7690,7 @@ open class Room : FFIObject, RoomInterface { } + @Throws(ClientException::class) @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") override suspend fun `timeline`() : Timeline { return uniffiRustCallAsync( @@ -7660,7 +7706,7 @@ open class Room : FFIObject, RoomInterface { // lift function { FfiConverterTypeTimeline.lift(it) }, // Error FFI converter - UniffiNullRustCallStatusErrorHandler, + ClientException.ErrorHandler, ) } override fun `topic`(): String? = @@ -8024,10 +8070,8 @@ public interface RoomListItemInterface { fun `canonicalAlias`(): String? /** - * Building a `Room`. - * - * Be careful that building a `Room` builds its entire `Timeline` at the - * same time. + * Building a `Room`. If its internal timeline hasn't been initialized + * it'll fail. */ suspend fun `fullRoom`(): Room @@ -8035,8 +8079,22 @@ public interface RoomListItemInterface { fun `id`(): String + /** + * Initializes the timeline for this room using the provided parameters. + * + * * `event_type_filter` - An optional [`TimelineEventTypeFilter`] to be + * used to filter timeline events besides the default timeline filter. If + * `None` is passed, only the default timeline filter will be used. + */ + suspend fun `initTimeline`(`eventTypeFilter`: TimelineEventTypeFilter?) + fun `isDirect`(): Boolean + /** + * Checks whether the Room's timeline has been initialized before. + */ + fun `isTimelineInitialized`(): Boolean + suspend fun `latestEvent`(): EventTimelineItem? fun `name`(): String? @@ -8109,11 +8167,10 @@ open class RoomListItem : FFIObject, RoomListItemInterface { /** - * Building a `Room`. - * - * Be careful that building a `Room` builds its entire `Timeline` at the - * same time. + * Building a `Room`. If its internal timeline hasn't been initialized + * it'll fail. */ + @Throws(RoomListException::class) @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") override suspend fun `fullRoom`() : Room { return uniffiRustCallAsync( @@ -8129,7 +8186,7 @@ open class RoomListItem : FFIObject, RoomListItemInterface { // lift function { FfiConverterTypeRoom.lift(it) }, // Error FFI converter - UniffiNullRustCallStatusErrorHandler, + RoomListException.ErrorHandler, ) } override fun `hasUnreadNotifications`(): Boolean = @@ -8154,6 +8211,34 @@ open class RoomListItem : FFIObject, RoomListItemInterface { FfiConverterString.lift(it) } + + /** + * Initializes the timeline for this room using the provided parameters. + * + * * `event_type_filter` - An optional [`TimelineEventTypeFilter`] to be + * used to filter timeline events besides the default timeline filter. If + * `None` is passed, only the default timeline filter will be used. + */ + @Throws(RoomListException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `initTimeline`(`eventTypeFilter`: TimelineEventTypeFilter?) { + return uniffiRustCallAsync( + callWithPointer { thisPtr -> + UniffiLib.INSTANCE.uniffi_matrix_sdk_ffi_fn_method_roomlistitem_init_timeline( + thisPtr, + FfiConverterOptionalTypeTimelineEventTypeFilter.lower(`eventTypeFilter`), + ) + }, + { future, callback, continuation -> UniffiLib.INSTANCE.ffi_matrix_sdk_ffi_rust_future_poll_void(future, callback, continuation) }, + { future, continuation -> UniffiLib.INSTANCE.ffi_matrix_sdk_ffi_rust_future_complete_void(future, continuation) }, + { future -> UniffiLib.INSTANCE.ffi_matrix_sdk_ffi_rust_future_free_void(future) }, + // lift function + { Unit }, + + // Error FFI converter + RoomListException.ErrorHandler, + ) + } override fun `isDirect`(): Boolean = callWithPointer { uniffiRustCall() { _status -> @@ -8166,6 +8251,20 @@ open class RoomListItem : FFIObject, RoomListItemInterface { } + /** + * Checks whether the Room's timeline has been initialized before. + */override fun `isTimelineInitialized`(): Boolean = + callWithPointer { + uniffiRustCall() { _status -> + UniffiLib.INSTANCE.uniffi_matrix_sdk_ffi_fn_method_roomlistitem_is_timeline_initialized(it, + + _status) +} + }.let { + FfiConverterBoolean.lift(it) + } + + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") override suspend fun `latestEvent`() : EventTimelineItem? { return uniffiRustCallAsync( @@ -8503,6 +8602,8 @@ public interface RoomMemberInterface { fun `powerLevel`(): Long + fun `suggestedRoleForPowerLevel`(): RoomMemberRole + /** * Removes the room member from the current account data's ignore list * which will unignore the user across all rooms. @@ -8738,6 +8839,17 @@ open class RoomMember : FFIObject, RoomMemberInterface { FfiConverterLong.lift(it) } + override fun `suggestedRoleForPowerLevel`(): RoomMemberRole = + callWithPointer { + uniffiRustCall() { _status -> + UniffiLib.INSTANCE.uniffi_matrix_sdk_ffi_fn_method_roommember_suggested_role_for_power_level(it, + + _status) +} + }.let { + FfiConverterTypeRoomMemberRole.lift(it) + } + /** * Removes the room member from the current account data's ignore list @@ -10678,6 +10790,93 @@ public object FfiConverterTypeTimelineEvent: FfiConverter + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_matrix_sdk_ffi_fn_free_timelineeventtypefilter(ptr, status) + } + } + } + } + + override fun uniffiClonePointer(): Pointer { + return uniffiRustCall() { status -> + UniffiLib.INSTANCE.uniffi_matrix_sdk_ffi_fn_clone_timelineeventtypefilter(pointer!!, status) + } + } + + + + companion object { + + fun `exclude`(`eventTypes`: List): TimelineEventTypeFilter = + TimelineEventTypeFilter( + uniffiRustCall() { _status -> + UniffiLib.INSTANCE.uniffi_matrix_sdk_ffi_fn_constructor_timelineeventtypefilter_exclude(FfiConverterSequenceTypeFilterTimelineEventType.lower(`eventTypes`),_status) +}) + + fun `include`(`eventTypes`: List): TimelineEventTypeFilter = + TimelineEventTypeFilter( + uniffiRustCall() { _status -> + UniffiLib.INSTANCE.uniffi_matrix_sdk_ffi_fn_constructor_timelineeventtypefilter_include(FfiConverterSequenceTypeFilterTimelineEventType.lower(`eventTypes`),_status) +}) + + } + +} + +public object FfiConverterTypeTimelineEventTypeFilter: FfiConverter { + + override fun lower(value: TimelineEventTypeFilter): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): TimelineEventTypeFilter { + return TimelineEventTypeFilter(value) + } + + override fun read(buf: ByteBuffer): TimelineEventTypeFilter { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(Pointer(buf.getLong())) + } + + override fun allocationSize(value: TimelineEventTypeFilter) = 8 + + override fun write(value: TimelineEventTypeFilter, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(Pointer.nativeValue(lower(value))) + } +} + + + + + public interface TimelineItemInterface { fun `asEvent`(): EventTimelineItem? @@ -14512,6 +14711,161 @@ public object FfiConverterTypeEventSendState : FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + FilterMessageLikeEventType.values()[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: FilterMessageLikeEventType) = 4 + + override fun write(value: FilterMessageLikeEventType, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + +enum class FilterStateEventType { + + POLICY_RULE_ROOM, + POLICY_RULE_SERVER, + POLICY_RULE_USER, + ROOM_ALIASES, + ROOM_AVATAR, + ROOM_CANONICAL_ALIAS, + ROOM_CREATE, + ROOM_ENCRYPTION, + ROOM_GUEST_ACCESS, + ROOM_HISTORY_VISIBILITY, + ROOM_JOIN_RULES, + ROOM_MEMBER, + ROOM_NAME, + ROOM_PINNED_EVENTS, + ROOM_POWER_LEVELS, + ROOM_SERVER_ACL, + ROOM_THIRD_PARTY_INVITE, + ROOM_TOMBSTONE, + ROOM_TOPIC, + SPACE_CHILD, + SPACE_PARENT; + companion object +} + +public object FfiConverterTypeFilterStateEventType: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + FilterStateEventType.values()[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: FilterStateEventType) = 4 + + override fun write(value: FilterStateEventType, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + +sealed class FilterTimelineEventType { + + data class MessageLike( + + val `eventType`: FilterMessageLikeEventType + ) : FilterTimelineEventType() { + companion object + } + + data class State( + + val `eventType`: FilterStateEventType + ) : FilterTimelineEventType() { + companion object + } + + + + companion object +} + +public object FfiConverterTypeFilterTimelineEventType : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): FilterTimelineEventType { + return when(buf.getInt()) { + 1 -> FilterTimelineEventType.MessageLike( + FfiConverterTypeFilterMessageLikeEventType.read(buf), + ) + 2 -> FilterTimelineEventType.State( + FfiConverterTypeFilterStateEventType.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: FilterTimelineEventType) = when(value) { + is FilterTimelineEventType.MessageLike -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4 + + FfiConverterTypeFilterMessageLikeEventType.allocationSize(value.`eventType`) + ) + } + is FilterTimelineEventType.State -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4 + + FfiConverterTypeFilterStateEventType.allocationSize(value.`eventType`) + ) + } + } + + override fun write(value: FilterTimelineEventType, buf: ByteBuffer) { + when(value) { + is FilterTimelineEventType.MessageLike -> { + buf.putInt(1) + FfiConverterTypeFilterMessageLikeEventType.write(value.`eventType`, buf) + Unit + } + is FilterTimelineEventType.State -> { + buf.putInt(2) + FfiConverterTypeFilterStateEventType.write(value.`eventType`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + enum class LogLevel { ERROR, @@ -17417,6 +17771,30 @@ sealed class RoomListException: Exception() { get() = "error=${ `error` }" } + class TimelineAlreadyExists( + + val `roomName`: String + ) : RoomListException() { + override val message + get() = "roomName=${ `roomName` }" + } + + class TimelineNotInitialized( + + val `roomName`: String + ) : RoomListException() { + override val message + get() = "roomName=${ `roomName` }" + } + + class InitializingTimeline( + + val `error`: String + ) : RoomListException() { + override val message + get() = "error=${ `error` }" + } + companion object ErrorHandler : UniffiRustCallStatusErrorHandler { override fun lift(error_buf: RustBuffer.ByValue): RoomListException = FfiConverterTypeRoomListError.lift(error_buf) @@ -17443,6 +17821,15 @@ public object FfiConverterTypeRoomListError : FfiConverterRustBuffer RoomListException.InvalidRoomId( FfiConverterString.read(buf), ) + 6 -> RoomListException.TimelineAlreadyExists( + FfiConverterString.read(buf), + ) + 7 -> RoomListException.TimelineNotInitialized( + FfiConverterString.read(buf), + ) + 8 -> RoomListException.InitializingTimeline( + FfiConverterString.read(buf), + ) else -> throw RuntimeException("invalid error enum value, something is very wrong!!") } } @@ -17473,6 +17860,21 @@ public object FfiConverterTypeRoomListError : FfiConverterRustBuffer ( + // Add the size for the Int that specifies the variant plus the size needed for all fields + 4 + + FfiConverterString.allocationSize(value.`roomName`) + ) + is RoomListException.TimelineNotInitialized -> ( + // Add the size for the Int that specifies the variant plus the size needed for all fields + 4 + + FfiConverterString.allocationSize(value.`roomName`) + ) + is RoomListException.InitializingTimeline -> ( + // Add the size for the Int that specifies the variant plus the size needed for all fields + 4 + + FfiConverterString.allocationSize(value.`error`) + ) } } @@ -17502,6 +17904,21 @@ public object FfiConverterTypeRoomListError : FfiConverterRustBuffer { + buf.putInt(6) + FfiConverterString.write(value.`roomName`, buf) + Unit + } + is RoomListException.TimelineNotInitialized -> { + buf.putInt(7) + FfiConverterString.write(value.`roomName`, buf) + Unit + } + is RoomListException.InitializingTimeline -> { + buf.putInt(8) + FfiConverterString.write(value.`error`, buf) + Unit + } }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } } @@ -20396,6 +20813,92 @@ public object FfiConverterTypeRoomListServiceSyncIndicatorListener: FfiConverter +public interface RoomNotableTagsListener { + + fun `call`(`notableTags`: RoomNotableTags) + + companion object +} + + +// Implement the foreign callback handler for RoomNotableTagsListener +internal class UniffiCallbackInterfaceRoomNotableTagsListener : ForeignCallback { + @Suppress("TooGenericExceptionCaught") + override fun invoke(handle: UniffiHandle, method: Int, argsData: Pointer, argsLen: Int, outBuf: RustBufferByReference): Int { + val cb = FfiConverterTypeRoomNotableTagsListener.handleMap.get(handle) + return when (method) { + IDX_CALLBACK_FREE -> { + FfiConverterTypeRoomNotableTagsListener.handleMap.remove(handle) + + // Successful return + // See docs of ForeignCallback in `uniffi_core/src/ffi/foreigncallbacks.rs` + UNIFFI_CALLBACK_SUCCESS + } + 1 -> { + // Call the method, write to outBuf and return a status code + // See docs of ForeignCallback in `uniffi_core/src/ffi/foreigncallbacks.rs` for info + try { + this.`invokeCall`(cb, argsData, argsLen, outBuf) + } catch (e: Throwable) { + // Unexpected error + try { + // Try to serialize the error into a string + outBuf.setValue(FfiConverterString.lower(e.toString())) + } catch (e: Throwable) { + // If that fails, then it's time to give up and just return + } + UNIFFI_CALLBACK_UNEXPECTED_ERROR + } + } + + else -> { + // An unexpected error happened. + // See docs of ForeignCallback in `uniffi_core/src/ffi/foreigncallbacks.rs` + try { + // Try to serialize the error into a string + outBuf.setValue(FfiConverterString.lower("Invalid Callback index")) + } catch (e: Throwable) { + // If that fails, then it's time to give up and just return + } + UNIFFI_CALLBACK_UNEXPECTED_ERROR + } + } + } + + + @Suppress("UNUSED_PARAMETER") + private fun `invokeCall`(kotlinCallbackInterface: RoomNotableTagsListener, argsData: Pointer, argsLen: Int, outBuf: RustBufferByReference): Int { + val argsBuf = argsData.getByteBuffer(0, argsLen.toLong()).also { + it.order(ByteOrder.BIG_ENDIAN) + } + fun makeCall() : Int { + kotlinCallbackInterface.`call`( + FfiConverterTypeRoomNotableTags.read(argsBuf) + ) + return UNIFFI_CALLBACK_SUCCESS + } + fun makeCallAndHandleError() : Int = makeCall() + + return makeCallAndHandleError() + } + + + // Registers the foreign callback with the Rust side. + // This method is generated for each callback interface. + internal fun register(lib: UniffiLib) { + lib.uniffi_matrix_sdk_ffi_fn_init_callback_roomnotabletagslistener(this) + } +} + +internal val uniffiCallbackInterfaceRoomNotableTagsListener = UniffiCallbackInterfaceRoomNotableTagsListener() + +// The ffiConverter which transforms the Callbacks in to UniffiHandles to pass to Rust. +public object FfiConverterTypeRoomNotableTagsListener: FfiConverterCallbackInterface() + + + + + public interface SessionVerificationControllerDelegate { fun `didAcceptVerificationRequest`() @@ -21326,6 +21829,35 @@ public object FfiConverterOptionalTypeTaskHandle: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): TimelineEventTypeFilter? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeTimelineEventTypeFilter.read(buf) + } + + override fun allocationSize(value: TimelineEventTypeFilter?): Int { + if (value == null) { + return 1 + } else { + return 1 + FfiConverterTypeTimelineEventTypeFilter.allocationSize(value) + } + } + + override fun write(value: TimelineEventTypeFilter?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeTimelineEventTypeFilter.write(value, buf) + } + } +} + + + + public object FfiConverterOptionalTypeTimelineItem: FfiConverterRustBuffer { override fun read(buf: ByteBuffer): TimelineItem? { if (buf.get().toInt() == 0) { @@ -22695,6 +23227,31 @@ public object FfiConverterSequenceTypeUserProfile: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeFilterTimelineEventType.read(buf) + } + } + + override fun allocationSize(value: List): Int { + val sizeForLength = 4 + val sizeForItems = value.map { FfiConverterTypeFilterTimelineEventType.allocationSize(it) }.sum() + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.forEach { + FfiConverterTypeFilterTimelineEventType.write(it, buf) + } + } +} + + + + public object FfiConverterSequenceTypeRoomListEntriesUpdate: FfiConverterRustBuffer> { override fun read(buf: ByteBuffer): List { val len = buf.getInt() @@ -22918,6 +23475,14 @@ public object FfiConverterMapStringSequenceString: FfiConverterRustBuffer + UniffiLib.INSTANCE.ffi_matrix_sdk_rustbuffer_alloc(size, status) + }.also { + if(it.data == null) { + throw RuntimeException("RustBuffer.alloc() returned null data pointer (size=${size})") + } + } + + internal fun create(capacity: Int, len: Int, data: Pointer?): RustBuffer.ByValue { + var buf = RustBuffer.ByValue() + buf.capacity = capacity + buf.len = len + buf.data = data + return buf + } + + internal fun free(buf: RustBuffer.ByValue) = uniffiRustCall() { status -> + UniffiLib.INSTANCE.ffi_matrix_sdk_rustbuffer_free(buf, status) + } + } + + @Suppress("TooGenericExceptionThrown") + fun asByteBuffer() = + this.data?.getByteBuffer(0, this.len.toLong())?.also { + it.order(ByteOrder.BIG_ENDIAN) + } +} + +/** + * The equivalent of the `*mut RustBuffer` type. + * Required for callbacks taking in an out pointer. + * + * Size is the sum of all values in the struct. + */ +class RustBufferByReference : ByReference(16) { + /** + * Set the pointed-to `RustBuffer` to the given value. + */ + fun setValue(value: RustBuffer.ByValue) { + // NOTE: The offsets are as they are in the C-like struct. + val pointer = getPointer() + pointer.setInt(0, value.capacity) + pointer.setInt(4, value.len) + pointer.setPointer(8, value.data) + } + + /** + * Get a `RustBuffer.ByValue` from this reference. + */ + fun getValue(): RustBuffer.ByValue { + val pointer = getPointer() + val value = RustBuffer.ByValue() + value.writeField("capacity", pointer.getInt(0)) + value.writeField("len", pointer.getInt(4)) + value.writeField("data", pointer.getPointer(8)) + + return value + } +} + +// This is a helper for safely passing byte references into the rust code. +// It's not actually used at the moment, because there aren't many things that you +// can take a direct pointer to in the JVM, and if we're going to copy something +// then we might as well copy it into a `RustBuffer`. But it's here for API +// completeness. + +@Structure.FieldOrder("len", "data") +open class ForeignBytes : Structure() { + @JvmField var len: Int = 0 + @JvmField var data: Pointer? = null + + class ByValue : ForeignBytes(), Structure.ByValue +} +// The FfiConverter interface handles converter types to and from the FFI +// +// All implementing objects should be public to support external types. When a +// type is external we need to import it's FfiConverter. +public interface FfiConverter { + // Convert an FFI type to a Kotlin type + fun lift(value: FfiType): KotlinType + + // Convert an Kotlin type to an FFI type + fun lower(value: KotlinType): FfiType + + // Read a Kotlin type from a `ByteBuffer` + fun read(buf: ByteBuffer): KotlinType + + // Calculate bytes to allocate when creating a `RustBuffer` + // + // This must return at least as many bytes as the write() function will + // write. It can return more bytes than needed, for example when writing + // Strings we can't know the exact bytes needed until we the UTF-8 + // encoding, so we pessimistically allocate the largest size possible (3 + // bytes per codepoint). Allocating extra bytes is not really a big deal + // because the `RustBuffer` is short-lived. + fun allocationSize(value: KotlinType): Int + + // Write a Kotlin type to a `ByteBuffer` + fun write(value: KotlinType, buf: ByteBuffer) + + // Lower a value into a `RustBuffer` + // + // This method lowers a value into a `RustBuffer` rather than the normal + // FfiType. It's used by the callback interface code. Callback interface + // returns are always serialized into a `RustBuffer` regardless of their + // normal FFI type. + fun lowerIntoRustBuffer(value: KotlinType): RustBuffer.ByValue { + val rbuf = RustBuffer.alloc(allocationSize(value)) + try { + val bbuf = rbuf.data!!.getByteBuffer(0, rbuf.capacity.toLong()).also { + it.order(ByteOrder.BIG_ENDIAN) + } + write(value, bbuf) + rbuf.writeField("len", bbuf.position()) + return rbuf + } catch (e: Throwable) { + RustBuffer.free(rbuf) + throw e + } + } + + // Lift a value from a `RustBuffer`. + // + // This here mostly because of the symmetry with `lowerIntoRustBuffer()`. + // It's currently only used by the `FfiConverterRustBuffer` class below. + fun liftFromRustBuffer(rbuf: RustBuffer.ByValue): KotlinType { + val byteBuf = rbuf.asByteBuffer()!! + try { + val item = read(byteBuf) + if (byteBuf.hasRemaining()) { + throw RuntimeException("junk remaining in buffer after lifting, something is very wrong!!") + } + return item + } finally { + RustBuffer.free(rbuf) + } + } +} + +// FfiConverter that uses `RustBuffer` as the FfiType +public interface FfiConverterRustBuffer: FfiConverter { + override fun lift(value: RustBuffer.ByValue) = liftFromRustBuffer(value) + override fun lower(value: KotlinType) = lowerIntoRustBuffer(value) +} +// A handful of classes and functions to support the generated data structures. +// This would be a good candidate for isolating in its own ffi-support lib. +// Error runtime. +@Structure.FieldOrder("code", "error_buf") +internal open class UniffiRustCallStatus : Structure() { + @JvmField var code: Byte = 0 + @JvmField var error_buf: RustBuffer.ByValue = RustBuffer.ByValue() + + class ByValue: UniffiRustCallStatus(), Structure.ByValue + + fun isSuccess(): Boolean { + return code == 0.toByte() + } + + fun isError(): Boolean { + return code == 1.toByte() + } + + fun isPanic(): Boolean { + return code == 2.toByte() + } +} + +class InternalException(message: String) : Exception(message) + +// Each top-level error class has a companion object that can lift the error from the call status's rust buffer +interface UniffiRustCallStatusErrorHandler { + fun lift(error_buf: RustBuffer.ByValue): E; +} + +// Helpers for calling Rust +// In practice we usually need to be synchronized to call this safely, so it doesn't +// synchronize itself + +// Call a rust function that returns a Result<>. Pass in the Error class companion that corresponds to the Err +private inline fun uniffiRustCallWithError(errorHandler: UniffiRustCallStatusErrorHandler, callback: (UniffiRustCallStatus) -> U): U { + var status = UniffiRustCallStatus(); + val return_value = callback(status) + uniffiCheckCallStatus(errorHandler, status) + return return_value +} + +// Check UniffiRustCallStatus and throw an error if the call wasn't successful +private fun uniffiCheckCallStatus(errorHandler: UniffiRustCallStatusErrorHandler, status: UniffiRustCallStatus) { + if (status.isSuccess()) { + return + } else if (status.isError()) { + throw errorHandler.lift(status.error_buf) + } else if (status.isPanic()) { + // when the rust code sees a panic, it tries to construct a rustbuffer + // with the message. but if that code panics, then it just sends back + // an empty buffer. + if (status.error_buf.len > 0) { + throw InternalException(FfiConverterString.lift(status.error_buf)) + } else { + throw InternalException("Rust panic") + } + } else { + throw InternalException("Unknown rust call status: $status.code") + } +} + +// UniffiRustCallStatusErrorHandler implementation for times when we don't expect a CALL_ERROR +object UniffiNullRustCallStatusErrorHandler: UniffiRustCallStatusErrorHandler { + override fun lift(error_buf: RustBuffer.ByValue): InternalException { + RustBuffer.free(error_buf) + return InternalException("Unexpected CALL_ERROR") + } +} + +// Call a rust function that returns a plain value +private inline fun uniffiRustCall(callback: (UniffiRustCallStatus) -> U): U { + return uniffiRustCallWithError(UniffiNullRustCallStatusErrorHandler, callback); +} + +// IntegerType that matches Rust's `usize` / C's `size_t` +public class USize(value: Long = 0) : IntegerType(Native.SIZE_T_SIZE, value, true) { + // This is needed to fill in the gaps of IntegerType's implementation of Number for Kotlin. + override fun toByte() = toInt().toByte() + // Needed until https://youtrack.jetbrains.com/issue/KT-47902 is fixed. + @Deprecated("`toInt().toChar()` is deprecated") + override fun toChar() = toInt().toChar() + override fun toShort() = toInt().toShort() + + fun writeToBuffer(buf: ByteBuffer) { + // Make sure we always write usize integers using native byte-order, since they may be + // casted to pointer values + buf.order(ByteOrder.nativeOrder()) + try { + when (Native.SIZE_T_SIZE) { + 4 -> buf.putInt(toInt()) + 8 -> buf.putLong(toLong()) + else -> throw RuntimeException("Invalid SIZE_T_SIZE: ${Native.SIZE_T_SIZE}") + } + } finally { + buf.order(ByteOrder.BIG_ENDIAN) + } + } + + companion object { + val size: Int + get() = Native.SIZE_T_SIZE + + fun readFromBuffer(buf: ByteBuffer) : USize { + // Make sure we always read usize integers using native byte-order, since they may be + // casted from pointer values + buf.order(ByteOrder.nativeOrder()) + try { + return when (Native.SIZE_T_SIZE) { + 4 -> USize(buf.getInt().toLong()) + 8 -> USize(buf.getLong()) + else -> throw RuntimeException("Invalid SIZE_T_SIZE: ${Native.SIZE_T_SIZE}") + } + } finally { + buf.order(ByteOrder.BIG_ENDIAN) + } + } + } +} + + +// Map handles to objects +// +// This is used when the Rust code expects an opaque pointer to represent some foreign object. +// Normally we would pass a pointer to the object, but JNA doesn't support getting a pointer from an +// object reference , nor does it support leaking a reference to Rust. +// +// Instead, this class maps USize values to objects so that we can pass a pointer-sized type to +// Rust when it needs an opaque pointer. +// +// TODO: refactor callbacks to use this class +internal class UniFfiHandleMap { + private val map = ConcurrentHashMap() + // Use AtomicInteger for our counter, since we may be on a 32-bit system. 4 billion possible + // values seems like enough. If somehow we generate 4 billion handles, then this will wrap + // around back to zero and we can assume the first handle generated will have been dropped by + // then. + private val counter = java.util.concurrent.atomic.AtomicInteger(0) + + val size: Int + get() = map.size + + fun insert(obj: T): USize { + val handle = USize(counter.getAndAdd(1).toLong()) + map.put(handle, obj) + return handle + } + + fun get(handle: USize): T? { + return map.get(handle) + } + + fun remove(handle: USize): T? { + return map.remove(handle) + } +} + +// FFI type for Rust future continuations +internal interface UniFffiRustFutureContinuationCallbackType : com.sun.jna.Callback { + fun callback(continuationHandle: USize, pollResult: Byte); +} + +// Contains loading, initialization code, +// and the FFI Function declarations in a com.sun.jna.Library. +@Synchronized +private fun findLibraryName(componentName: String): String { + val libOverride = System.getProperty("uniffi.component.$componentName.libraryOverride") + if (libOverride != null) { + return libOverride + } + return "matrix_sdk_ffi" +} + +private inline fun loadIndirect( + componentName: String +): Lib { + return Native.load(findLibraryName(componentName), Lib::class.java) +} + +// A JNA Library to expose the extern-C FFI definitions. +// This is an implementation detail which will be called internally by the public API. + +internal interface UniffiLib : Library { + companion object { + internal val INSTANCE: UniffiLib by lazy { + loadIndirect(componentName = "matrix_sdk") + .also { lib: UniffiLib -> + uniffiCheckContractApiVersion(lib) + uniffiCheckApiChecksums(lib) + } + } + + } + + fun ffi_matrix_sdk_rustbuffer_alloc(`size`: Int,uniffi_out_err: UniffiRustCallStatus, + ): RustBuffer.ByValue + fun ffi_matrix_sdk_rustbuffer_from_bytes(`bytes`: ForeignBytes.ByValue,uniffi_out_err: UniffiRustCallStatus, + ): RustBuffer.ByValue + fun ffi_matrix_sdk_rustbuffer_free(`buf`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, + ): Unit + fun ffi_matrix_sdk_rustbuffer_reserve(`buf`: RustBuffer.ByValue,`additional`: Int,uniffi_out_err: UniffiRustCallStatus, + ): RustBuffer.ByValue + fun ffi_matrix_sdk_rust_future_poll_u8(`handle`: Pointer,`callback`: UniFffiRustFutureContinuationCallbackType,`callbackData`: USize, + ): Unit + fun ffi_matrix_sdk_rust_future_cancel_u8(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_rust_future_free_u8(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_rust_future_complete_u8(`handle`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Byte + fun ffi_matrix_sdk_rust_future_poll_i8(`handle`: Pointer,`callback`: UniFffiRustFutureContinuationCallbackType,`callbackData`: USize, + ): Unit + fun ffi_matrix_sdk_rust_future_cancel_i8(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_rust_future_free_i8(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_rust_future_complete_i8(`handle`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Byte + fun ffi_matrix_sdk_rust_future_poll_u16(`handle`: Pointer,`callback`: UniFffiRustFutureContinuationCallbackType,`callbackData`: USize, + ): Unit + fun ffi_matrix_sdk_rust_future_cancel_u16(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_rust_future_free_u16(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_rust_future_complete_u16(`handle`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Short + fun ffi_matrix_sdk_rust_future_poll_i16(`handle`: Pointer,`callback`: UniFffiRustFutureContinuationCallbackType,`callbackData`: USize, + ): Unit + fun ffi_matrix_sdk_rust_future_cancel_i16(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_rust_future_free_i16(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_rust_future_complete_i16(`handle`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Short + fun ffi_matrix_sdk_rust_future_poll_u32(`handle`: Pointer,`callback`: UniFffiRustFutureContinuationCallbackType,`callbackData`: USize, + ): Unit + fun ffi_matrix_sdk_rust_future_cancel_u32(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_rust_future_free_u32(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_rust_future_complete_u32(`handle`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Int + fun ffi_matrix_sdk_rust_future_poll_i32(`handle`: Pointer,`callback`: UniFffiRustFutureContinuationCallbackType,`callbackData`: USize, + ): Unit + fun ffi_matrix_sdk_rust_future_cancel_i32(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_rust_future_free_i32(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_rust_future_complete_i32(`handle`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Int + fun ffi_matrix_sdk_rust_future_poll_u64(`handle`: Pointer,`callback`: UniFffiRustFutureContinuationCallbackType,`callbackData`: USize, + ): Unit + fun ffi_matrix_sdk_rust_future_cancel_u64(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_rust_future_free_u64(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_rust_future_complete_u64(`handle`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Long + fun ffi_matrix_sdk_rust_future_poll_i64(`handle`: Pointer,`callback`: UniFffiRustFutureContinuationCallbackType,`callbackData`: USize, + ): Unit + fun ffi_matrix_sdk_rust_future_cancel_i64(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_rust_future_free_i64(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_rust_future_complete_i64(`handle`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Long + fun ffi_matrix_sdk_rust_future_poll_f32(`handle`: Pointer,`callback`: UniFffiRustFutureContinuationCallbackType,`callbackData`: USize, + ): Unit + fun ffi_matrix_sdk_rust_future_cancel_f32(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_rust_future_free_f32(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_rust_future_complete_f32(`handle`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Float + fun ffi_matrix_sdk_rust_future_poll_f64(`handle`: Pointer,`callback`: UniFffiRustFutureContinuationCallbackType,`callbackData`: USize, + ): Unit + fun ffi_matrix_sdk_rust_future_cancel_f64(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_rust_future_free_f64(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_rust_future_complete_f64(`handle`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Double + fun ffi_matrix_sdk_rust_future_poll_pointer(`handle`: Pointer,`callback`: UniFffiRustFutureContinuationCallbackType,`callbackData`: USize, + ): Unit + fun ffi_matrix_sdk_rust_future_cancel_pointer(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_rust_future_free_pointer(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_rust_future_complete_pointer(`handle`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Pointer + fun ffi_matrix_sdk_rust_future_poll_rust_buffer(`handle`: Pointer,`callback`: UniFffiRustFutureContinuationCallbackType,`callbackData`: USize, + ): Unit + fun ffi_matrix_sdk_rust_future_cancel_rust_buffer(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_rust_future_free_rust_buffer(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_rust_future_complete_rust_buffer(`handle`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): RustBuffer.ByValue + fun ffi_matrix_sdk_rust_future_poll_void(`handle`: Pointer,`callback`: UniFffiRustFutureContinuationCallbackType,`callbackData`: USize, + ): Unit + fun ffi_matrix_sdk_rust_future_cancel_void(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_rust_future_free_void(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_rust_future_complete_void(`handle`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Unit + fun ffi_matrix_sdk_uniffi_contract_version( + ): Int + +} + +private fun uniffiCheckContractApiVersion(lib: UniffiLib) { + // Get the bindings contract version from our ComponentInterface + val bindings_contract_version = 25 + // Get the scaffolding contract version by calling the into the dylib + val scaffolding_contract_version = lib.ffi_matrix_sdk_uniffi_contract_version() + if (bindings_contract_version != scaffolding_contract_version) { + throw RuntimeException("UniFFI contract version mismatch: try cleaning and rebuilding your project") + } +} + +@Suppress("UNUSED_PARAMETER") +private fun uniffiCheckApiChecksums(lib: UniffiLib) { +} + +// Async support + +// Public interface members begin here. + + +// Interface implemented by anything that can contain an object reference. +// +// Such types expose a `destroy()` method that must be called to cleanly +// dispose of the contained objects. Failure to call this method may result +// in memory leaks. +// +// The easiest way to ensure this method is called is to use the `.use` +// helper method to execute a block and destroy the object at the end. +interface Disposable { + fun destroy() + companion object { + fun destroy(vararg args: Any?) { + args.filterIsInstance() + .forEach(Disposable::destroy) + } + } +} + +inline fun T.use(block: (T) -> R) = + try { + block(this) + } finally { + try { + // N.B. our implementation is on the nullable type `Disposable?`. + this?.destroy() + } catch (e: Throwable) { + // swallow + } + } + +public object FfiConverterString: FfiConverter { + // Note: we don't inherit from FfiConverterRustBuffer, because we use a + // special encoding when lowering/lifting. We can use `RustBuffer.len` to + // store our length and avoid writing it out to the buffer. + override fun lift(value: RustBuffer.ByValue): String { + try { + val byteArr = ByteArray(value.len) + value.asByteBuffer()!!.get(byteArr) + return byteArr.toString(Charsets.UTF_8) + } finally { + RustBuffer.free(value) + } + } + + override fun read(buf: ByteBuffer): String { + val len = buf.getInt() + val byteArr = ByteArray(len) + buf.get(byteArr) + return byteArr.toString(Charsets.UTF_8) + } + + fun toUtf8(value: String): ByteBuffer { + // Make sure we don't have invalid UTF-16, check for lone surrogates. + return Charsets.UTF_8.newEncoder().run { + onMalformedInput(CodingErrorAction.REPORT) + encode(CharBuffer.wrap(value)) + } + } + + override fun lower(value: String): RustBuffer.ByValue { + val byteBuf = toUtf8(value) + // Ideally we'd pass these bytes to `ffi_bytebuffer_from_bytes`, but doing so would require us + // to copy them into a JNA `Memory`. So we might as well directly copy them into a `RustBuffer`. + val rbuf = RustBuffer.alloc(byteBuf.limit()) + rbuf.asByteBuffer()!!.put(byteBuf) + return rbuf + } + + // We aren't sure exactly how many bytes our string will be once it's UTF-8 + // encoded. Allocate 3 bytes per UTF-16 code unit which will always be + // enough. + override fun allocationSize(value: String): Int { + val sizeForLength = 4 + val sizeForString = value.length * 3 + return sizeForLength + sizeForString + } + + override fun write(value: String, buf: ByteBuffer) { + val byteBuf = toUtf8(value) + buf.putInt(byteBuf.limit()) + buf.put(byteBuf) + } +} + + + +/** + * The role of a member in a room. + */ +enum class RoomMemberRole { + + /** + * The member is an administrator. + */ + ADMINISTRATOR, + /** + * The member is a moderator. + */ + MODERATOR, + /** + * The member is a regular user. + */ + USER; + companion object +} + +public object FfiConverterTypeRoomMemberRole: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + RoomMemberRole.values()[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: RoomMemberRole) = 4 + + override fun write(value: RoomMemberRole, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + diff --git a/sdk/sdk-android/src/main/kotlin/uniffi/matrix_sdk_base/matrix_sdk_base.kt b/sdk/sdk-android/src/main/kotlin/uniffi/matrix_sdk_base/matrix_sdk_base.kt new file mode 100644 index 0000000..3c8f98d --- /dev/null +++ b/sdk/sdk-android/src/main/kotlin/uniffi/matrix_sdk_base/matrix_sdk_base.kt @@ -0,0 +1,655 @@ +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! + +@file:Suppress("NAME_SHADOWING") + +package uniffi.matrix_sdk_base; + +// Common helper code. +// +// Ideally this would live in a separate .kt file where it can be unittested etc +// in isolation, and perhaps even published as a re-useable package. +// +// However, it's important that the details of how this helper code works (e.g. the +// way that different builtin types are passed across the FFI) exactly match what's +// expected by the Rust code on the other side of the interface. In practice right +// now that means coming from the exact some version of `uniffi` that was used to +// compile the Rust component. The easiest way to ensure this is to bundle the Kotlin +// helpers directly inline like we're doing here. + +import com.sun.jna.Library +import com.sun.jna.IntegerType +import com.sun.jna.Native +import com.sun.jna.Pointer +import com.sun.jna.Structure +import com.sun.jna.Callback +import com.sun.jna.ptr.* +import java.nio.ByteBuffer +import java.nio.ByteOrder +import java.nio.CharBuffer +import java.nio.charset.CodingErrorAction +import java.util.concurrent.ConcurrentHashMap + +// This is a helper for safely working with byte buffers returned from the Rust code. +// A rust-owned buffer is represented by its capacity, its current length, and a +// pointer to the underlying data. + +@Structure.FieldOrder("capacity", "len", "data") +open class RustBuffer : Structure() { + @JvmField var capacity: Int = 0 + @JvmField var len: Int = 0 + @JvmField var data: Pointer? = null + + class ByValue: RustBuffer(), Structure.ByValue + class ByReference: RustBuffer(), Structure.ByReference + + companion object { + internal fun alloc(size: Int = 0) = uniffiRustCall() { status -> + UniffiLib.INSTANCE.ffi_matrix_sdk_base_rustbuffer_alloc(size, status) + }.also { + if(it.data == null) { + throw RuntimeException("RustBuffer.alloc() returned null data pointer (size=${size})") + } + } + + internal fun create(capacity: Int, len: Int, data: Pointer?): RustBuffer.ByValue { + var buf = RustBuffer.ByValue() + buf.capacity = capacity + buf.len = len + buf.data = data + return buf + } + + internal fun free(buf: RustBuffer.ByValue) = uniffiRustCall() { status -> + UniffiLib.INSTANCE.ffi_matrix_sdk_base_rustbuffer_free(buf, status) + } + } + + @Suppress("TooGenericExceptionThrown") + fun asByteBuffer() = + this.data?.getByteBuffer(0, this.len.toLong())?.also { + it.order(ByteOrder.BIG_ENDIAN) + } +} + +/** + * The equivalent of the `*mut RustBuffer` type. + * Required for callbacks taking in an out pointer. + * + * Size is the sum of all values in the struct. + */ +class RustBufferByReference : ByReference(16) { + /** + * Set the pointed-to `RustBuffer` to the given value. + */ + fun setValue(value: RustBuffer.ByValue) { + // NOTE: The offsets are as they are in the C-like struct. + val pointer = getPointer() + pointer.setInt(0, value.capacity) + pointer.setInt(4, value.len) + pointer.setPointer(8, value.data) + } + + /** + * Get a `RustBuffer.ByValue` from this reference. + */ + fun getValue(): RustBuffer.ByValue { + val pointer = getPointer() + val value = RustBuffer.ByValue() + value.writeField("capacity", pointer.getInt(0)) + value.writeField("len", pointer.getInt(4)) + value.writeField("data", pointer.getPointer(8)) + + return value + } +} + +// This is a helper for safely passing byte references into the rust code. +// It's not actually used at the moment, because there aren't many things that you +// can take a direct pointer to in the JVM, and if we're going to copy something +// then we might as well copy it into a `RustBuffer`. But it's here for API +// completeness. + +@Structure.FieldOrder("len", "data") +open class ForeignBytes : Structure() { + @JvmField var len: Int = 0 + @JvmField var data: Pointer? = null + + class ByValue : ForeignBytes(), Structure.ByValue +} +// The FfiConverter interface handles converter types to and from the FFI +// +// All implementing objects should be public to support external types. When a +// type is external we need to import it's FfiConverter. +public interface FfiConverter { + // Convert an FFI type to a Kotlin type + fun lift(value: FfiType): KotlinType + + // Convert an Kotlin type to an FFI type + fun lower(value: KotlinType): FfiType + + // Read a Kotlin type from a `ByteBuffer` + fun read(buf: ByteBuffer): KotlinType + + // Calculate bytes to allocate when creating a `RustBuffer` + // + // This must return at least as many bytes as the write() function will + // write. It can return more bytes than needed, for example when writing + // Strings we can't know the exact bytes needed until we the UTF-8 + // encoding, so we pessimistically allocate the largest size possible (3 + // bytes per codepoint). Allocating extra bytes is not really a big deal + // because the `RustBuffer` is short-lived. + fun allocationSize(value: KotlinType): Int + + // Write a Kotlin type to a `ByteBuffer` + fun write(value: KotlinType, buf: ByteBuffer) + + // Lower a value into a `RustBuffer` + // + // This method lowers a value into a `RustBuffer` rather than the normal + // FfiType. It's used by the callback interface code. Callback interface + // returns are always serialized into a `RustBuffer` regardless of their + // normal FFI type. + fun lowerIntoRustBuffer(value: KotlinType): RustBuffer.ByValue { + val rbuf = RustBuffer.alloc(allocationSize(value)) + try { + val bbuf = rbuf.data!!.getByteBuffer(0, rbuf.capacity.toLong()).also { + it.order(ByteOrder.BIG_ENDIAN) + } + write(value, bbuf) + rbuf.writeField("len", bbuf.position()) + return rbuf + } catch (e: Throwable) { + RustBuffer.free(rbuf) + throw e + } + } + + // Lift a value from a `RustBuffer`. + // + // This here mostly because of the symmetry with `lowerIntoRustBuffer()`. + // It's currently only used by the `FfiConverterRustBuffer` class below. + fun liftFromRustBuffer(rbuf: RustBuffer.ByValue): KotlinType { + val byteBuf = rbuf.asByteBuffer()!! + try { + val item = read(byteBuf) + if (byteBuf.hasRemaining()) { + throw RuntimeException("junk remaining in buffer after lifting, something is very wrong!!") + } + return item + } finally { + RustBuffer.free(rbuf) + } + } +} + +// FfiConverter that uses `RustBuffer` as the FfiType +public interface FfiConverterRustBuffer: FfiConverter { + override fun lift(value: RustBuffer.ByValue) = liftFromRustBuffer(value) + override fun lower(value: KotlinType) = lowerIntoRustBuffer(value) +} +// A handful of classes and functions to support the generated data structures. +// This would be a good candidate for isolating in its own ffi-support lib. +// Error runtime. +@Structure.FieldOrder("code", "error_buf") +internal open class UniffiRustCallStatus : Structure() { + @JvmField var code: Byte = 0 + @JvmField var error_buf: RustBuffer.ByValue = RustBuffer.ByValue() + + class ByValue: UniffiRustCallStatus(), Structure.ByValue + + fun isSuccess(): Boolean { + return code == 0.toByte() + } + + fun isError(): Boolean { + return code == 1.toByte() + } + + fun isPanic(): Boolean { + return code == 2.toByte() + } +} + +class InternalException(message: String) : Exception(message) + +// Each top-level error class has a companion object that can lift the error from the call status's rust buffer +interface UniffiRustCallStatusErrorHandler { + fun lift(error_buf: RustBuffer.ByValue): E; +} + +// Helpers for calling Rust +// In practice we usually need to be synchronized to call this safely, so it doesn't +// synchronize itself + +// Call a rust function that returns a Result<>. Pass in the Error class companion that corresponds to the Err +private inline fun uniffiRustCallWithError(errorHandler: UniffiRustCallStatusErrorHandler, callback: (UniffiRustCallStatus) -> U): U { + var status = UniffiRustCallStatus(); + val return_value = callback(status) + uniffiCheckCallStatus(errorHandler, status) + return return_value +} + +// Check UniffiRustCallStatus and throw an error if the call wasn't successful +private fun uniffiCheckCallStatus(errorHandler: UniffiRustCallStatusErrorHandler, status: UniffiRustCallStatus) { + if (status.isSuccess()) { + return + } else if (status.isError()) { + throw errorHandler.lift(status.error_buf) + } else if (status.isPanic()) { + // when the rust code sees a panic, it tries to construct a rustbuffer + // with the message. but if that code panics, then it just sends back + // an empty buffer. + if (status.error_buf.len > 0) { + throw InternalException(FfiConverterString.lift(status.error_buf)) + } else { + throw InternalException("Rust panic") + } + } else { + throw InternalException("Unknown rust call status: $status.code") + } +} + +// UniffiRustCallStatusErrorHandler implementation for times when we don't expect a CALL_ERROR +object UniffiNullRustCallStatusErrorHandler: UniffiRustCallStatusErrorHandler { + override fun lift(error_buf: RustBuffer.ByValue): InternalException { + RustBuffer.free(error_buf) + return InternalException("Unexpected CALL_ERROR") + } +} + +// Call a rust function that returns a plain value +private inline fun uniffiRustCall(callback: (UniffiRustCallStatus) -> U): U { + return uniffiRustCallWithError(UniffiNullRustCallStatusErrorHandler, callback); +} + +// IntegerType that matches Rust's `usize` / C's `size_t` +public class USize(value: Long = 0) : IntegerType(Native.SIZE_T_SIZE, value, true) { + // This is needed to fill in the gaps of IntegerType's implementation of Number for Kotlin. + override fun toByte() = toInt().toByte() + // Needed until https://youtrack.jetbrains.com/issue/KT-47902 is fixed. + @Deprecated("`toInt().toChar()` is deprecated") + override fun toChar() = toInt().toChar() + override fun toShort() = toInt().toShort() + + fun writeToBuffer(buf: ByteBuffer) { + // Make sure we always write usize integers using native byte-order, since they may be + // casted to pointer values + buf.order(ByteOrder.nativeOrder()) + try { + when (Native.SIZE_T_SIZE) { + 4 -> buf.putInt(toInt()) + 8 -> buf.putLong(toLong()) + else -> throw RuntimeException("Invalid SIZE_T_SIZE: ${Native.SIZE_T_SIZE}") + } + } finally { + buf.order(ByteOrder.BIG_ENDIAN) + } + } + + companion object { + val size: Int + get() = Native.SIZE_T_SIZE + + fun readFromBuffer(buf: ByteBuffer) : USize { + // Make sure we always read usize integers using native byte-order, since they may be + // casted from pointer values + buf.order(ByteOrder.nativeOrder()) + try { + return when (Native.SIZE_T_SIZE) { + 4 -> USize(buf.getInt().toLong()) + 8 -> USize(buf.getLong()) + else -> throw RuntimeException("Invalid SIZE_T_SIZE: ${Native.SIZE_T_SIZE}") + } + } finally { + buf.order(ByteOrder.BIG_ENDIAN) + } + } + } +} + + +// Map handles to objects +// +// This is used when the Rust code expects an opaque pointer to represent some foreign object. +// Normally we would pass a pointer to the object, but JNA doesn't support getting a pointer from an +// object reference , nor does it support leaking a reference to Rust. +// +// Instead, this class maps USize values to objects so that we can pass a pointer-sized type to +// Rust when it needs an opaque pointer. +// +// TODO: refactor callbacks to use this class +internal class UniFfiHandleMap { + private val map = ConcurrentHashMap() + // Use AtomicInteger for our counter, since we may be on a 32-bit system. 4 billion possible + // values seems like enough. If somehow we generate 4 billion handles, then this will wrap + // around back to zero and we can assume the first handle generated will have been dropped by + // then. + private val counter = java.util.concurrent.atomic.AtomicInteger(0) + + val size: Int + get() = map.size + + fun insert(obj: T): USize { + val handle = USize(counter.getAndAdd(1).toLong()) + map.put(handle, obj) + return handle + } + + fun get(handle: USize): T? { + return map.get(handle) + } + + fun remove(handle: USize): T? { + return map.remove(handle) + } +} + +// FFI type for Rust future continuations +internal interface UniFffiRustFutureContinuationCallbackType : com.sun.jna.Callback { + fun callback(continuationHandle: USize, pollResult: Byte); +} + +// Contains loading, initialization code, +// and the FFI Function declarations in a com.sun.jna.Library. +@Synchronized +private fun findLibraryName(componentName: String): String { + val libOverride = System.getProperty("uniffi.component.$componentName.libraryOverride") + if (libOverride != null) { + return libOverride + } + return "matrix_sdk_ffi" +} + +private inline fun loadIndirect( + componentName: String +): Lib { + return Native.load(findLibraryName(componentName), Lib::class.java) +} + +// A JNA Library to expose the extern-C FFI definitions. +// This is an implementation detail which will be called internally by the public API. + +internal interface UniffiLib : Library { + companion object { + internal val INSTANCE: UniffiLib by lazy { + loadIndirect(componentName = "matrix_sdk_base") + .also { lib: UniffiLib -> + uniffiCheckContractApiVersion(lib) + uniffiCheckApiChecksums(lib) + } + } + + } + + fun ffi_matrix_sdk_base_rustbuffer_alloc(`size`: Int,uniffi_out_err: UniffiRustCallStatus, + ): RustBuffer.ByValue + fun ffi_matrix_sdk_base_rustbuffer_from_bytes(`bytes`: ForeignBytes.ByValue,uniffi_out_err: UniffiRustCallStatus, + ): RustBuffer.ByValue + fun ffi_matrix_sdk_base_rustbuffer_free(`buf`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, + ): Unit + fun ffi_matrix_sdk_base_rustbuffer_reserve(`buf`: RustBuffer.ByValue,`additional`: Int,uniffi_out_err: UniffiRustCallStatus, + ): RustBuffer.ByValue + fun ffi_matrix_sdk_base_rust_future_poll_u8(`handle`: Pointer,`callback`: UniFffiRustFutureContinuationCallbackType,`callbackData`: USize, + ): Unit + fun ffi_matrix_sdk_base_rust_future_cancel_u8(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_base_rust_future_free_u8(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_base_rust_future_complete_u8(`handle`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Byte + fun ffi_matrix_sdk_base_rust_future_poll_i8(`handle`: Pointer,`callback`: UniFffiRustFutureContinuationCallbackType,`callbackData`: USize, + ): Unit + fun ffi_matrix_sdk_base_rust_future_cancel_i8(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_base_rust_future_free_i8(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_base_rust_future_complete_i8(`handle`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Byte + fun ffi_matrix_sdk_base_rust_future_poll_u16(`handle`: Pointer,`callback`: UniFffiRustFutureContinuationCallbackType,`callbackData`: USize, + ): Unit + fun ffi_matrix_sdk_base_rust_future_cancel_u16(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_base_rust_future_free_u16(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_base_rust_future_complete_u16(`handle`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Short + fun ffi_matrix_sdk_base_rust_future_poll_i16(`handle`: Pointer,`callback`: UniFffiRustFutureContinuationCallbackType,`callbackData`: USize, + ): Unit + fun ffi_matrix_sdk_base_rust_future_cancel_i16(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_base_rust_future_free_i16(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_base_rust_future_complete_i16(`handle`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Short + fun ffi_matrix_sdk_base_rust_future_poll_u32(`handle`: Pointer,`callback`: UniFffiRustFutureContinuationCallbackType,`callbackData`: USize, + ): Unit + fun ffi_matrix_sdk_base_rust_future_cancel_u32(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_base_rust_future_free_u32(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_base_rust_future_complete_u32(`handle`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Int + fun ffi_matrix_sdk_base_rust_future_poll_i32(`handle`: Pointer,`callback`: UniFffiRustFutureContinuationCallbackType,`callbackData`: USize, + ): Unit + fun ffi_matrix_sdk_base_rust_future_cancel_i32(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_base_rust_future_free_i32(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_base_rust_future_complete_i32(`handle`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Int + fun ffi_matrix_sdk_base_rust_future_poll_u64(`handle`: Pointer,`callback`: UniFffiRustFutureContinuationCallbackType,`callbackData`: USize, + ): Unit + fun ffi_matrix_sdk_base_rust_future_cancel_u64(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_base_rust_future_free_u64(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_base_rust_future_complete_u64(`handle`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Long + fun ffi_matrix_sdk_base_rust_future_poll_i64(`handle`: Pointer,`callback`: UniFffiRustFutureContinuationCallbackType,`callbackData`: USize, + ): Unit + fun ffi_matrix_sdk_base_rust_future_cancel_i64(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_base_rust_future_free_i64(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_base_rust_future_complete_i64(`handle`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Long + fun ffi_matrix_sdk_base_rust_future_poll_f32(`handle`: Pointer,`callback`: UniFffiRustFutureContinuationCallbackType,`callbackData`: USize, + ): Unit + fun ffi_matrix_sdk_base_rust_future_cancel_f32(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_base_rust_future_free_f32(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_base_rust_future_complete_f32(`handle`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Float + fun ffi_matrix_sdk_base_rust_future_poll_f64(`handle`: Pointer,`callback`: UniFffiRustFutureContinuationCallbackType,`callbackData`: USize, + ): Unit + fun ffi_matrix_sdk_base_rust_future_cancel_f64(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_base_rust_future_free_f64(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_base_rust_future_complete_f64(`handle`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Double + fun ffi_matrix_sdk_base_rust_future_poll_pointer(`handle`: Pointer,`callback`: UniFffiRustFutureContinuationCallbackType,`callbackData`: USize, + ): Unit + fun ffi_matrix_sdk_base_rust_future_cancel_pointer(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_base_rust_future_free_pointer(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_base_rust_future_complete_pointer(`handle`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Pointer + fun ffi_matrix_sdk_base_rust_future_poll_rust_buffer(`handle`: Pointer,`callback`: UniFffiRustFutureContinuationCallbackType,`callbackData`: USize, + ): Unit + fun ffi_matrix_sdk_base_rust_future_cancel_rust_buffer(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_base_rust_future_free_rust_buffer(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_base_rust_future_complete_rust_buffer(`handle`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): RustBuffer.ByValue + fun ffi_matrix_sdk_base_rust_future_poll_void(`handle`: Pointer,`callback`: UniFffiRustFutureContinuationCallbackType,`callbackData`: USize, + ): Unit + fun ffi_matrix_sdk_base_rust_future_cancel_void(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_base_rust_future_free_void(`handle`: Pointer, + ): Unit + fun ffi_matrix_sdk_base_rust_future_complete_void(`handle`: Pointer,uniffi_out_err: UniffiRustCallStatus, + ): Unit + fun ffi_matrix_sdk_base_uniffi_contract_version( + ): Int + +} + +private fun uniffiCheckContractApiVersion(lib: UniffiLib) { + // Get the bindings contract version from our ComponentInterface + val bindings_contract_version = 25 + // Get the scaffolding contract version by calling the into the dylib + val scaffolding_contract_version = lib.ffi_matrix_sdk_base_uniffi_contract_version() + if (bindings_contract_version != scaffolding_contract_version) { + throw RuntimeException("UniFFI contract version mismatch: try cleaning and rebuilding your project") + } +} + +@Suppress("UNUSED_PARAMETER") +private fun uniffiCheckApiChecksums(lib: UniffiLib) { +} + +// Async support + +// Public interface members begin here. + + +// Interface implemented by anything that can contain an object reference. +// +// Such types expose a `destroy()` method that must be called to cleanly +// dispose of the contained objects. Failure to call this method may result +// in memory leaks. +// +// The easiest way to ensure this method is called is to use the `.use` +// helper method to execute a block and destroy the object at the end. +interface Disposable { + fun destroy() + companion object { + fun destroy(vararg args: Any?) { + args.filterIsInstance() + .forEach(Disposable::destroy) + } + } +} + +inline fun T.use(block: (T) -> R) = + try { + block(this) + } finally { + try { + // N.B. our implementation is on the nullable type `Disposable?`. + this?.destroy() + } catch (e: Throwable) { + // swallow + } + } + +public object FfiConverterBoolean: FfiConverter { + override fun lift(value: Byte): Boolean { + return value.toInt() != 0 + } + + override fun read(buf: ByteBuffer): Boolean { + return lift(buf.get()) + } + + override fun lower(value: Boolean): Byte { + return if (value) 1.toByte() else 0.toByte() + } + + override fun allocationSize(value: Boolean) = 1 + + override fun write(value: Boolean, buf: ByteBuffer) { + buf.put(lower(value)) + } +} + +public object FfiConverterString: FfiConverter { + // Note: we don't inherit from FfiConverterRustBuffer, because we use a + // special encoding when lowering/lifting. We can use `RustBuffer.len` to + // store our length and avoid writing it out to the buffer. + override fun lift(value: RustBuffer.ByValue): String { + try { + val byteArr = ByteArray(value.len) + value.asByteBuffer()!!.get(byteArr) + return byteArr.toString(Charsets.UTF_8) + } finally { + RustBuffer.free(value) + } + } + + override fun read(buf: ByteBuffer): String { + val len = buf.getInt() + val byteArr = ByteArray(len) + buf.get(byteArr) + return byteArr.toString(Charsets.UTF_8) + } + + fun toUtf8(value: String): ByteBuffer { + // Make sure we don't have invalid UTF-16, check for lone surrogates. + return Charsets.UTF_8.newEncoder().run { + onMalformedInput(CodingErrorAction.REPORT) + encode(CharBuffer.wrap(value)) + } + } + + override fun lower(value: String): RustBuffer.ByValue { + val byteBuf = toUtf8(value) + // Ideally we'd pass these bytes to `ffi_bytebuffer_from_bytes`, but doing so would require us + // to copy them into a JNA `Memory`. So we might as well directly copy them into a `RustBuffer`. + val rbuf = RustBuffer.alloc(byteBuf.limit()) + rbuf.asByteBuffer()!!.put(byteBuf) + return rbuf + } + + // We aren't sure exactly how many bytes our string will be once it's UTF-8 + // encoded. Allocate 3 bytes per UTF-16 code unit which will always be + // enough. + override fun allocationSize(value: String): Int { + val sizeForLength = 4 + val sizeForString = value.length * 3 + return sizeForLength + sizeForString + } + + override fun write(value: String, buf: ByteBuffer) { + val byteBuf = toUtf8(value) + buf.putInt(byteBuf.limit()) + buf.put(byteBuf) + } +} + + + +/** + * Holds information computed from the room account data `m.tag` events. + */ +data class RoomNotableTags ( + /** + * Whether or not the room is marked as favorite. + */ + var `isFavorite`: Boolean +) { + + companion object +} + +public object FfiConverterTypeRoomNotableTags: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): RoomNotableTags { + return RoomNotableTags( + FfiConverterBoolean.read(buf), + ) + } + + override fun allocationSize(value: RoomNotableTags) = ( + FfiConverterBoolean.allocationSize(value.`isFavorite`) + ) + + override fun write(value: RoomNotableTags, buf: ByteBuffer) { + FfiConverterBoolean.write(value.`isFavorite`, buf) + } +} +