├── sdk ├── sdk-jvm │ ├── .gitignore │ └── build.gradle └── sdk-android │ ├── .gitignore │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ ├── build.gradle │ └── src │ └── main │ └── kotlin │ └── uniffi │ ├── matrix_sdk_common │ └── matrix_sdk_common.kt │ └── matrix_sdk_ui │ └── matrix_sdk_ui.kt ├── crypto ├── crypto-android │ ├── .gitignore │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ ├── build.gradle │ └── src │ │ └── main │ │ └── kotlin │ │ └── uniffi │ │ └── matrix_sdk_common │ │ └── matrix_sdk_common.kt └── crypto-jvm │ ├── .gitignore │ └── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── renovate.json ├── SECURITY.md ├── .gitignore ├── .github ├── ISSUE_TEMPLATE │ ├── config.yaml │ ├── feature_request.md │ └── bug_report.md └── workflows │ ├── release_sdk_parallel.yml │ └── release_crypto.yml ├── settings.gradle ├── scripts ├── publish-root.gradle ├── build-aar.sh ├── publish-module.gradle ├── build-rust-for-target.sh ├── build.sh ├── build-rust-for-target.py └── publish_release.py ├── gradle.properties ├── CONTRIBUTING.md ├── README.md ├── gradlew.bat └── gradlew /sdk/sdk-jvm/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /sdk/sdk-android/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /crypto/crypto-android/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /crypto/crypto-jvm/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /sdk/sdk-android/consumer-rules.pro: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /crypto/crypto-android/consumer-rules.pro: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matrix-org/matrix-rust-components-kotlin/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended" 5 | ], 6 | "prHourlyLimit": 20 7 | } 8 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Reporting a Vulnerability 2 | 3 | **If you've found a security vulnerability, please report it to security@matrix.org** 4 | 5 | For more information on our security disclosure policy, visit https://www.matrix.org/security-disclosure-policy/ 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | .idea/ 17 | 18 | *.so 19 | -------------------------------------------------------------------------------- /sdk/sdk-jvm/build.gradle: -------------------------------------------------------------------------------- 1 | import Dependencies 2 | 3 | plugins { 4 | id 'java-library' 5 | id 'org.jetbrains.kotlin.jvm' 6 | } 7 | 8 | java { 9 | sourceCompatibility = JavaVersion.VERSION_1_7 10 | targetCompatibility = JavaVersion.VERSION_1_7 11 | } 12 | 13 | dependencies { 14 | implementation Dependencies.jna 15 | } -------------------------------------------------------------------------------- /crypto/crypto-jvm/build.gradle: -------------------------------------------------------------------------------- 1 | import Dependencies 2 | 3 | plugins { 4 | id 'java-library' 5 | id 'org.jetbrains.kotlin.jvm' 6 | } 7 | 8 | java { 9 | sourceCompatibility = JavaVersion.VERSION_1_7 10 | targetCompatibility = JavaVersion.VERSION_1_7 11 | } 12 | 13 | dependencies { 14 | implementation Dependencies.jna 15 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yaml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: Matrix Community Support 4 | url: "https://matrix.to/#/#matrix:matrix.org" 5 | about: General support questions can be asked here. 6 | - name: Matrix Security Policy 7 | url: https://www.matrix.org/security-disclosure-policy/ 8 | about: Learn more about our security disclosure policy. 9 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionSha256Sum=7197a12f450794931532469d4ff21a59ea2c1cd59a3ec3f89c035c3c420a6999 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip 5 | networkTimeout=10000 6 | validateDistributionUrl=true 7 | zipStoreBase=GRADLE_USER_HOME 8 | zipStorePath=wrapper/dists 9 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | google() 5 | mavenCentral() 6 | } 7 | } 8 | 9 | dependencyResolutionManagement { 10 | repositories { 11 | google() 12 | mavenCentral() 13 | flatDir { 14 | dirs 'libs' 15 | } 16 | } 17 | } 18 | rootProject.name = "matrix-rust-components-kotlin" 19 | include ':sdk:sdk-android' 20 | include ':sdk:sdk-jvm' 21 | include ':crypto:crypto-android' 22 | include ':crypto:crypto-jvm' 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /sdk/sdk-android/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /crypto/crypto-android/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /scripts/publish-root.gradle: -------------------------------------------------------------------------------- 1 | ext["signing.keyId"] = '' 2 | ext["signing.password"] = '' 3 | ext["signing.key"] = '' 4 | ext["ossrhUsername"] = '' 5 | ext["ossrhPassword"] = '' 6 | ext["sonatypeStagingProfileId"] = '' 7 | 8 | File secretPropsFile = project.rootProject.file('local.properties') 9 | if (secretPropsFile.exists()) { 10 | // Read local.properties file first if it exists 11 | Properties p = new Properties() 12 | new FileInputStream(secretPropsFile).withCloseable { is -> p.load(is) } 13 | p.each { name, value -> ext[name] = value } 14 | } else { 15 | // Use system environment variables 16 | ext["ossrhUsername"] = System.getenv('OSSRH_USERNAME') 17 | ext["ossrhPassword"] = System.getenv('OSSRH_PASSWORD') 18 | ext["sonatypeStagingProfileId"] = System.getenv('SONATYPE_STAGING_PROFILE_ID') 19 | ext["signing.keyId"] = System.getenv('SIGNING_KEY_ID') 20 | ext["signing.password"] = System.getenv('SIGNING_PASSWORD') 21 | ext["signing.key"] = System.getenv('SIGNING_KEY') 22 | } 23 | 24 | nexusPublishing { 25 | repositories { 26 | sonatype { 27 | stagingProfileId = sonatypeStagingProfileId 28 | username = ossrhUsername 29 | password = ossrhPassword 30 | nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/")) 31 | snapshotRepositoryUrl.set(uri("https://central.sonatype.com/repository/maven-snapshots/")) 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /crypto/crypto-android/build.gradle: -------------------------------------------------------------------------------- 1 | import Dependencies 2 | 3 | plugins { 4 | id 'com.android.library' 5 | id 'org.jetbrains.kotlin.android' 6 | } 7 | 8 | ext { 9 | PUBLISH_GROUP_ID = ConfigurationData.publishGroupId 10 | PUBLISH_ARTIFACT_ID = 'crypto-android' 11 | PUBLISH_VERSION = ConfigurationData.versionNameCrypto 12 | PUBLISH_DESCRIPTION = 'Android Bindings to the Matrix Rust Crypto SDK' 13 | } 14 | 15 | apply from: "${rootDir}/scripts/publish-module.gradle" 16 | 17 | android { 18 | namespace 'org.matrix.rustcomponents.sdk.crypto' 19 | 20 | compileSdk ConfigurationData.compileSdk 21 | 22 | defaultConfig { 23 | minSdk ConfigurationData.minSdk 24 | targetSdk ConfigurationData.targetSdk 25 | versionName ConfigurationData.versionNameCrypto 26 | 27 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 28 | consumerProguardFiles "consumer-rules.pro" 29 | } 30 | 31 | buildTypes { 32 | release { 33 | minifyEnabled false 34 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 35 | } 36 | } 37 | compileOptions { 38 | sourceCompatibility JavaVersion.VERSION_1_8 39 | targetCompatibility JavaVersion.VERSION_1_8 40 | } 41 | kotlinOptions { 42 | jvmTarget = '1.8' 43 | } 44 | } 45 | 46 | dependencies { 47 | implementation Dependencies.jna 48 | testImplementation Dependencies.junit 49 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app"s APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official 22 | # Enables namespacing of each library's R class so that its R class includes only the 23 | # resources declared in the library itself and none from the library's dependencies, 24 | # thereby reducing the size of the R class for that library 25 | android.nonTransitiveRClass=true 26 | -------------------------------------------------------------------------------- /sdk/sdk-android/build.gradle: -------------------------------------------------------------------------------- 1 | import Dependencies 2 | 3 | plugins { 4 | id 'com.android.library' 5 | id 'org.jetbrains.kotlin.android' 6 | } 7 | 8 | ext { 9 | PUBLISH_GROUP_ID = ConfigurationData.publishGroupId 10 | PUBLISH_ARTIFACT_ID = 'sdk-android' 11 | PUBLISH_VERSION = ConfigurationData.versionNameSdk 12 | PUBLISH_DESCRIPTION = 'Android Bindings to the Matrix Rust SDK' 13 | } 14 | 15 | apply from: "${rootDir}/scripts/publish-module.gradle" 16 | 17 | android { 18 | 19 | namespace 'org.matrix.rustcomponents.sdk' 20 | 21 | compileSdk ConfigurationData.compileSdk 22 | 23 | defaultConfig { 24 | minSdk ConfigurationData.minSdk 25 | targetSdk ConfigurationData.targetSdk 26 | versionName ConfigurationData.versionNameSdk 27 | 28 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 29 | consumerProguardFiles "consumer-rules.pro" 30 | } 31 | 32 | buildTypes { 33 | release { 34 | minifyEnabled false 35 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 36 | } 37 | } 38 | compileOptions { 39 | sourceCompatibility JavaVersion.VERSION_1_8 40 | targetCompatibility JavaVersion.VERSION_1_8 41 | } 42 | kotlinOptions { 43 | jvmTarget = '1.8' 44 | } 45 | } 46 | 47 | dependencies { 48 | implementation Dependencies.jna 49 | implementation Dependencies.coroutines 50 | implementation Dependencies.annotations 51 | testImplementation Dependencies.junit 52 | } 53 | -------------------------------------------------------------------------------- /scripts/build-aar.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | is_release='false' 5 | gradle_module='sdk' 6 | output='' 7 | 8 | helpFunction() { 9 | echo "" 10 | echo "Usage: $0 -r -m sdk" 11 | echo -e "\t-o Optional output path with the expected name of the aar file" 12 | echo -e "\t-r Flag to build in release mode" 13 | echo -e "\t-m Option to select the gradle module to build. Default is sdk" 14 | exit 1 15 | } 16 | 17 | while getopts ':rm:o:' 'opt'; do 18 | case ${opt} in 19 | 'r') is_release='true' ;; 20 | 'm') gradle_module="$OPTARG" ;; 21 | 'o') output="$OPTARG" ;; 22 | ?) helpFunction ;; 23 | esac 24 | done 25 | 26 | moveFunction() { 27 | if [ -z "$output" ]; then 28 | echo "No output path provided, keep the generated path" 29 | else 30 | mv "$1" "$output" 31 | fi 32 | } 33 | 34 | ## For now, cargo ndk includes all generated so files from the target directory, so makes sure it just includes the one we need. 35 | echo "Clean .so files" 36 | if [ "$gradle_module" = "crypto" ]; then 37 | find crypto/crypto-android/src/main/jniLibs -type f ! -name 'libmatrix_sdk_crypto_ffi.so' -delete 38 | else 39 | find sdk/sdk-android/src/main/jniLibs -type f ! -name 'libmatrix_sdk_ffi.so' -delete 40 | fi 41 | 42 | if ${is_release}; then 43 | if [ "$gradle_module" = "sdk" ]; then 44 | ./gradlew :sdk:sdk-android:assembleRelease 45 | moveFunction "sdk/sdk-android/build/outputs/aar/sdk-android-release.aar" 46 | else 47 | ./gradlew :crypto:crypto-android:assembleRelease 48 | moveFunction "crypto/crypto-android/build/outputs/aar/crypto-android-release.aar" 49 | fi 50 | else 51 | if [ "$gradle_module" = "sdk" ]; then 52 | ./gradlew :sdk:sdk-android:assembleDebug 53 | moveFunction "sdk/sdk-android/build/outputs/aar/sdk-android-debug.aar" 54 | else 55 | ./gradlew :crypto:crypto-android:assembleDebug 56 | moveFunction "crypto/crypto-android/build/outputs/aar/crypto-android-debug.aar" 57 | fi 58 | fi 59 | -------------------------------------------------------------------------------- /scripts/publish-module.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'maven-publish' 2 | apply plugin: 'signing' 3 | 4 | group = PUBLISH_GROUP_ID 5 | 6 | afterEvaluate { 7 | publishing { 8 | publications { 9 | release(MavenPublication) { 10 | groupId PUBLISH_GROUP_ID 11 | artifactId PUBLISH_ARTIFACT_ID 12 | version PUBLISH_VERSION 13 | 14 | if (project.plugins.findPlugin("com.android.library")) { 15 | from components.release 16 | } else { 17 | from components.java 18 | } 19 | 20 | pom { 21 | name = PUBLISH_ARTIFACT_ID 22 | description = PUBLISH_DESCRIPTION 23 | url = 'https://github.com/matrix-org/matrix-rust-components-kotlin' 24 | licenses { 25 | license { 26 | name = 'The Apache Software License, Version 2.0' 27 | url = 'https://www.apache.org/licenses/LICENSE-2.0.txt' 28 | } 29 | } 30 | developers { 31 | developer { 32 | id = 'matrixdev' 33 | name = 'matrixdev' 34 | email = 'android@element.io' 35 | } 36 | } 37 | 38 | scm { 39 | connection = 'scm:git:git://github.com/matrix-org/matrix-rust-components-kotlin.git' 40 | developerConnection = 'scm:git:ssh://git@github.com/matrix-org/matrix-rust-components-kotlin.git' 41 | url = 'https://github.com/matrix-org/matrix-rust-components-kotlin' 42 | } 43 | } 44 | } 45 | } 46 | } 47 | } 48 | 49 | signing { 50 | useInMemoryPgpKeys( 51 | rootProject.ext["signing.keyId"], 52 | rootProject.ext["signing.key"], 53 | rootProject.ext["signing.password"], 54 | ) 55 | sign publishing.publications 56 | } -------------------------------------------------------------------------------- /scripts/build-rust-for-target.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | helpFunction() { 5 | echo "" 6 | echo "Usage: $0 -r -p /Documents/dev/matrix-rust-sdk -m sdk" 7 | echo -e "\t-p Local path to the rust-sdk repository" 8 | echo -e "\t-o Optional output path with the expected name of the aar file" 9 | echo -e "\t-r Flag to build in release mode" 10 | echo -e "\t-m Option to select the gradle module to build. Default is sdk" 11 | echo -e "\t-t Option to to select an android target to build against." 12 | exit 1 13 | } 14 | 15 | scripts_dir=$( 16 | cd "$(dirname "${BASH_SOURCE[0]}")" || exit 17 | pwd -P 18 | ) 19 | 20 | is_release='false' 21 | gradle_module='sdk' 22 | only_target='' 23 | output='' 24 | 25 | while getopts ':rp:m:t:o:' 'opt'; do 26 | case ${opt} in 27 | 'r') is_release='true' ;; 28 | 'p') sdk_path="$OPTARG" ;; 29 | 'm') gradle_module="$OPTARG" ;; 30 | 't') only_target="$OPTARG" ;; 31 | 'o') output="$OPTARG" ;; 32 | ?) helpFunction ;; 33 | esac 34 | done 35 | 36 | if [ -z "$sdk_path" ]; then 37 | echo "sdk_path is empty, please provide one" 38 | helpFunction 39 | fi 40 | 41 | if [ -z "$only_target" ]; then 42 | helpFunction 43 | else 44 | target_command=("--only-target" "$only_target") 45 | fi 46 | 47 | if [ "$gradle_module" = "crypto" ]; then 48 | ## NDK is needed for https://crates.io/crates/olm-sys 49 | if [ -z "$ANDROID_NDK" ]; then 50 | echo "please set the ANDROID_NDK environment variable to your Android NDK installation" 51 | exit 1 52 | fi 53 | src_dir="$scripts_dir/../crypto/crypto-android/src/main" 54 | package="crypto-sdk" 55 | else 56 | src_dir="$scripts_dir/../sdk/sdk-android/src/main" 57 | package="full-sdk" 58 | fi 59 | 60 | if ${is_release}; then 61 | profile="release" 62 | else 63 | profile="reldbg" 64 | fi 65 | 66 | echo "Launching build script with following params:" 67 | echo "sdk_path = $sdk_path" 68 | echo "profile = $profile" 69 | echo "gradle_module = $gradle_module" 70 | echo "src-dir = $src_dir" 71 | 72 | pushd "$sdk_path" || exit 1 73 | 74 | cargo xtask kotlin build-android-library --profile "$profile" "${target_command[@]}" --src-dir "$src_dir" --package "$package" 75 | 76 | pushd "$scripts_dir/.." || exit 1 77 | 78 | shift $((OPTIND - 1)) 79 | 80 | moveFunction() { 81 | if [ -z "$output" ]; then 82 | echo "No output path provided, keep the generated path" 83 | else 84 | mv "$1" "$output" 85 | fi 86 | } 87 | 88 | ## For now, cargo ndk includes all generated so files from the target directory, so makes sure it just includes the one we need. 89 | echo "Clean .so files" 90 | if [ "$gradle_module" = "crypto" ]; then 91 | find crypto/crypto-android/src/main/jniLibs -type f ! -name 'libmatrix_sdk_crypto_ffi.so' -delete 92 | else 93 | find sdk/sdk-android/src/main/jniLibs -type f ! -name 'libmatrix_sdk_ffi.so' -delete 94 | fi -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Matrix rust components kotlin 2 | 3 | Thank you for taking the time to contribute to Matrix! 4 | 5 | This is the repository for Matrix rust components kotlin, a repository is used for distributing kotlin releases of the Matrix Rust SDK. 6 | 7 | ## Sign off 8 | 9 | We ask that everybody who contributes to this project signs off their contributions, as explained below. 10 | 11 | We follow a simple 'inbound=outbound' model for contributions: the act of submitting an 'inbound' contribution means that the contributor agrees to license their contribution under the same terms as the project's overall 'outbound' license - in our case, this is Apache Software License v2 (see [LICENSE](./LICENSE)). 12 | 13 | In order to have a concrete record that your contribution is intentional and you agree to license it under the same terms as the project's license, we've adopted the same lightweight approach used by the [Linux Kernel](https://www.kernel.org/doc/html/latest/process/submitting-patches.html), [Docker](https://github.com/docker/docker/blob/master/CONTRIBUTING.md), and many other projects: the [Developer Certificate of Origin](https://developercertificate.org/) (DCO). This is a simple declaration that you wrote the contribution or otherwise have the right to contribute it to Matrix: 14 | 15 | ``` 16 | Developer Certificate of Origin 17 | Version 1.1 18 | 19 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 20 | 660 York Street, Suite 102, 21 | San Francisco, CA 94110 USA 22 | 23 | Everyone is permitted to copy and distribute verbatim copies of this 24 | license document, but changing it is not allowed. 25 | 26 | Developer's Certificate of Origin 1.1 27 | 28 | By making a contribution to this project, I certify that: 29 | 30 | (a) The contribution was created in whole or in part by me and I 31 | have the right to submit it under the open source license 32 | indicated in the file; or 33 | 34 | (b) The contribution is based upon previous work that, to the best 35 | of my knowledge, is covered under an appropriate open source 36 | license and I have the right under that license to submit that 37 | work with modifications, whether created in whole or in part 38 | by me, under the same open source license (unless I am 39 | permitted to submit under a different license), as indicated 40 | in the file; or 41 | 42 | (c) The contribution was provided directly to me by some other 43 | person who certified (a), (b) or (c) and I have not modified 44 | it. 45 | 46 | (d) I understand and agree that this project and the contribution 47 | are public and that a record of the contribution (including all 48 | personal information I submit with it, including my sign-off) is 49 | maintained indefinitely and may be redistributed consistent with 50 | this project or the open source license(s) involved. 51 | ``` 52 | 53 | If you agree to this for your contribution, then all that's needed is to include the line in your commit or pull request comment: 54 | 55 | ``` 56 | Signed-off-by: Your Name 57 | ``` 58 | 59 | Git allows you to add this signoff automatically when using the `-s` flag to `git commit`, which uses the name and email set in your `user.name` and `user.email` git configs. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Matrix rust components kotlin 2 | 3 | This repository is used for distributing kotlin releases of the Matrix Rust SDK. It'll provide the corresponding aar and also publish them on maven. 4 | 5 | ## Releasing 6 | 7 | There is a ['Release SDK Library (parallel)'](https://github.com/matrix-org/matrix-rust-components-kotlin/actions/workflows/release_sdk_parallel.yml) Github Actions workflow you can run with a parameter for the SDK branch or SHA - tags don't work correctly at the moment - and the new version name to release. 8 | There is also a 'Release Crypto Library' one that does the same for the crypto library. 9 | 10 | If you want to do it manually instead: 11 | 12 | You need to set GITHUB_API_TOKEN in your env to let the script be able to commit and push, with this configuration: 13 | - Content: Read and Write; 14 | - Metadata: Read only. 15 | 16 | Make sure to also have setup the maven credentials and gpg key in your [env](scripts/publish-root.gradle) 17 | 18 | Whenever a new release of the underlying components is available, we need to tag a new release in this repo to make them available. 19 | This is done with the release script found in the scripts directory. It'll also push the release to the maven repository. 20 | 21 | Usage : 22 | ``` 23 | # To build the SDK/crypto library binaries from the matrix-rust-sdk repo: 24 | ./scripts/build.sh -p -m -r 25 | # To release the built SDK/crypto library binaries to maven: 26 | python3 ./scripts/publish_release.py --version --linkable-ref --module 27 | ``` 28 | 29 | ## Testing locally 30 | As the package vendors a pre-built binary of the SDK, all local development is done via the SDK's repo instead of this one. 31 | You can use the build script to generate the AAR file for testing. Be sure to have checked out the matrix-rust-sdk first. 32 | 33 | 34 | The `-t` argument needs a valid architecture to build. For Android, these are: 35 | - aarch64-linux-android 36 | - armv7-linux-androideabi 37 | - i686-linux-android 38 | - x86_64-linux-android 39 | 40 | Alternatively, to build only the host's architecture, you can use the `-l` argument. 41 | 42 | Usage: 43 | 44 | To build the main crate (eg, for Element-X): 45 | ``` 46 | ./scripts/build.sh -p -m sdk -l 47 | ``` 48 | 49 | Or: 50 | ``` 51 | ./scripts/build.sh -p -m sdk -t 52 | ``` 53 | 54 | To build just the crypto crate (eg, for Element Android classic), use this instead: 55 | ``` 56 | ./scripts/build.sh -p -m crypto -l 57 | ``` 58 | 59 | Other useful flags: 60 | 61 | - `-o OUTPUT_DIR`: Moves the generated AAR file to the dir `OUTPUT_DIR`. 62 | - `-r`: Produces a release build instead of a development one. 63 | 64 | You should then import this AAR in your project. 65 | 66 | ## Prerequisites 67 | 68 | * Android NDK 69 | * the Rust toolchain 70 | * cargo-ndk `cargo install cargo-ndk` 71 | * protoc `brew install protobuf` or downloading [here](https://github.com/protocolbuffers/protobuf/releases) 72 | * android targets (e.g. `rustup target add aarch64-linux-android armv7-linux-androideabi x86_64-linux-android i686-linux-android`) 73 | 74 | 75 | ## License 76 | 77 | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0) 78 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH= 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | helpFunction() { 5 | echo "" 6 | echo "Usage: $0 -r -p /Documents/dev/matrix-rust-sdk -m sdk" 7 | echo -e "\t-p Local path to the rust-sdk repository" 8 | echo -e "\t-o Optional output path with the expected name of the aar file" 9 | echo -e "\t-r Flag to build in release mode" 10 | echo -e "\t-m Option to select the gradle module to build. Default is sdk" 11 | echo -e "\t-t Select a target architecture to build for. Default will build for all known Android targets." 12 | echo -e "\t-l Build for the local architecture. Incompatible with '-t'." 13 | exit 1 14 | } 15 | 16 | scripts_dir=$( 17 | cd "$(dirname "${BASH_SOURCE[0]}")" || exit 18 | pwd -P 19 | ) 20 | 21 | is_release='false' 22 | gradle_module='sdk' 23 | only_target='' 24 | local_target='' 25 | output='' 26 | 27 | while getopts ':rp:m:t:lo:' 'opt'; do 28 | case ${opt} in 29 | 'r') is_release='true' ;; 30 | 'p') sdk_path="$OPTARG" ;; 31 | 'm') gradle_module="$OPTARG" ;; 32 | 't') only_target="$OPTARG" ;; 33 | 'l') local_target='true' ;; 34 | 'o') output="$OPTARG" ;; 35 | ?) helpFunction ;; 36 | esac 37 | done 38 | 39 | if [ -z "$sdk_path" ]; then 40 | echo "sdk_path is empty, please provide one" 41 | helpFunction 42 | fi 43 | 44 | if [ -n "$local_target" ]; then 45 | if [ -n "$only_target" ]; then 46 | echo "Cannot specifiy both '-l' and '-t'." >&2 47 | exit 1 48 | fi 49 | 50 | only_target="$(uname -m)-linux-android" 51 | # On ARM MacOS, `uname -m` returns arm64, but the toolchain is called aarch64 52 | only_target="${only_target/arm64/aarch64}" 53 | fi 54 | 55 | if [ -z "$only_target" ]; then 56 | echo "no target provided, build for all targets" 57 | target_command=() 58 | else 59 | target_command=("--only-target" "$only_target") 60 | fi 61 | 62 | if ${is_release}; then 63 | profile="release" 64 | else 65 | profile="reldbg" 66 | fi 67 | 68 | if [ "$gradle_module" = "crypto" ]; then 69 | ## NDK is needed for https://crates.io/crates/olm-sys 70 | if [ -z "$ANDROID_NDK" && -z "$ANDROID_HOME" ]; then 71 | echo "please set the ANDROID_NDK environment variable to your Android NDK installation" 72 | exit 1 73 | fi 74 | src_dir="$scripts_dir/../crypto/crypto-android/src/main" 75 | package="crypto-sdk" 76 | else 77 | src_dir="$scripts_dir/../sdk/sdk-android/src/main" 78 | package="full-sdk" 79 | fi 80 | 81 | echo "Launching build script with following params:" 82 | echo "sdk_path = $sdk_path" 83 | echo "profile = $profile" 84 | echo "gradle_module = $gradle_module" 85 | echo "src-dir = $src_dir" 86 | 87 | pushd "$sdk_path" || exit 1 88 | 89 | cargo xtask kotlin build-android-library --profile "$profile" "${target_command[@]}" --src-dir "$src_dir" --package "$package" 90 | 91 | pushd "$scripts_dir/.." || exit 1 92 | 93 | shift $((OPTIND - 1)) 94 | 95 | moveFunction() { 96 | if [ -z "$output" ]; then 97 | echo -e "\nSUCCESS: Output AAR file is '$1'" 98 | else 99 | mv "$1" "$output" 100 | echo -e "\nSUCCESS: Output AAR file is '$output'" 101 | fi 102 | } 103 | 104 | ## For now, cargo ndk includes all generated so files from the target directory, so makes sure it just includes the one we need. 105 | echo "Clean .so files" 106 | if [ "$gradle_module" = "crypto" ]; then 107 | find crypto/crypto-android/src/main/jniLibs -type f ! -name 'libmatrix_sdk_crypto_ffi.so' -delete 108 | else 109 | find sdk/sdk-android/src/main/jniLibs -type f ! -name 'libmatrix_sdk_ffi.so' -delete 110 | fi 111 | 112 | if ${is_release}; then 113 | if [ "$gradle_module" = "sdk" ]; then 114 | ./gradlew :sdk:sdk-android:assembleRelease 115 | moveFunction "sdk/sdk-android/build/outputs/aar/sdk-android-release.aar" 116 | else 117 | ./gradlew :crypto:crypto-android:assembleRelease 118 | moveFunction "crypto/crypto-android/build/outputs/aar/crypto-android-release.aar" 119 | fi 120 | else 121 | if [ "$gradle_module" = "sdk" ]; then 122 | ./gradlew :sdk:sdk-android:assembleDebug 123 | moveFunction "sdk/sdk-android/build/outputs/aar/sdk-android-debug.aar" 124 | else 125 | ./gradlew :crypto:crypto-android:assembleDebug 126 | moveFunction "crypto/crypto-android/build/outputs/aar/crypto-android-debug.aar" 127 | fi 128 | fi 129 | -------------------------------------------------------------------------------- /scripts/build-rust-for-target.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import argparse 4 | import os 5 | import re 6 | import subprocess 7 | from enum import Enum, auto 8 | from tempfile import TemporaryDirectory 9 | 10 | class Module(Enum): 11 | SDK = auto() 12 | CRYPTO = auto() 13 | 14 | def module_type(value): 15 | try: 16 | return Module[value.upper()] 17 | except KeyError: 18 | raise argparse.ArgumentTypeError( 19 | f"Invalid module choice: {value}. Available options: SDK, CRYPTO") 20 | 21 | 22 | def get_build_version_file_path(module: Module, project_root: str) -> str: 23 | if module == Module.SDK: 24 | return os.path.join(project_root, 'buildSrc/src/main/kotlin', 'BuildVersionsSDK.kt') 25 | elif module == Module.CRYPTO: 26 | return os.path.join(project_root, 'buildSrc/src/main/kotlin', 'BuildVersionsCrypto.kt') 27 | else: 28 | raise ValueError(f"Unknown module: {module}") 29 | 30 | 31 | def read_version_numbers_from_kotlin_file(file_path): 32 | with open(file_path, "r") as file: 33 | content = file.read() 34 | 35 | major_version = int(re.search(r"majorVersion\s*=\s*(\d+)", content).group(1)) 36 | minor_version = int(re.search(r"minorVersion\s*=\s*(\d+)", content).group(1)) 37 | patch_version = int(re.search(r"patchVersion\s*=\s*(\d+)", content).group(1)) 38 | 39 | return major_version, minor_version, patch_version 40 | 41 | 42 | def clone_repo_and_checkout_ref(directory, git_url, ref): 43 | # Clone the repo 44 | subprocess.run( 45 | ["git", "clone", git_url, directory], 46 | check=True, 47 | text=True, 48 | ) 49 | # Checkout the specified ref (commit hash, tag, or branch) 50 | subprocess.run( 51 | ["git", "checkout", ref], 52 | cwd=directory, 53 | check=True, 54 | text=True, 55 | ) 56 | 57 | def is_provided_version_higher(major: int, minor: int, patch: int, provided_version: str) -> bool: 58 | provided_major, provided_minor, provided_patch = map(int, provided_version.split('.')) 59 | if provided_major > major: 60 | return True 61 | elif provided_major == major: 62 | if provided_minor > minor: 63 | return True 64 | elif provided_minor == minor: 65 | return provided_patch > patch 66 | return False 67 | 68 | 69 | def execute_build_script(script_directory: str, sdk_path: str, module: Module, target: str): 70 | print("Execute build script...") 71 | build_script_path = os.path.join(script_directory, "build-rust-for-target.sh") 72 | subprocess.run( 73 | ["/bin/bash", build_script_path, "-p", sdk_path, "-m", module.name.lower(), "-t", target, "-r"], 74 | check=True, 75 | text=True 76 | ) 77 | print("Finish executing build script with success") 78 | 79 | parser = argparse.ArgumentParser() 80 | parser.add_argument("-m", "--module", type=module_type, required=True, 81 | help="Choose a module (SDK or CRYPTO)") 82 | parser.add_argument("-v", "--version", type=str, required=True, 83 | help="Version as a string (e.g. '1.0.0')") 84 | parser.add_argument("-t", "--target", type=str, required=True, 85 | help="Choose a target (\"aarch64-linux-android\", \"armv7-linux-androideabi\", \"i686-linux-android\", \"x86_64-linux-android\")") 86 | parser.add_argument("-r", "--ref", type=str, required=True, 87 | help="Ref to the git matrix-rust-sdk (branch name, commit or tag)") 88 | parser.add_argument("-p", "--path-to-sdk", type=str, required=False, 89 | help="Choose a module (SDK or CRYPTO)") 90 | parser.add_argument("-s", "--skip-clone", action="store_true", required=False, 91 | help="Skip cloning the Rust SDK repository") 92 | 93 | args = parser.parse_args() 94 | 95 | current_dir = os.path.dirname(os.path.abspath(__file__)) 96 | project_root = os.path.dirname(current_dir).rstrip(os.sep) 97 | sdk_git_url = "https://github.com/matrix-org/matrix-rust-sdk.git" 98 | 99 | if args.path_to_sdk: 100 | sdk_path = args.path_to_sdk 101 | else: 102 | sdk_path = TemporaryDirectory().name 103 | 104 | skip_clone = args.skip_clone 105 | 106 | print(f"Project Root Directory: {project_root}") 107 | print(f"Selected module: {args.module}") 108 | print(f"Version: {args.version}") 109 | print(f"SDK git ref: {args.ref}") 110 | 111 | build_version_file_path = get_build_version_file_path(args.module, project_root) 112 | major, minor, patch = read_version_numbers_from_kotlin_file(build_version_file_path) 113 | if is_provided_version_higher(major, minor, patch, args.version): 114 | print( 115 | f"The provided version ({args.version}) is higher than the previous version ({major}.{minor}.{patch}) so we can start the release process") 116 | else: 117 | print( 118 | f"The provided version ({args.version}) is not higher than the previous version ({major}.{minor}.{patch}) so bump the version before retrying.") 119 | exit(0) 120 | 121 | if skip_clone is False: 122 | clone_repo_and_checkout_ref(sdk_path, sdk_git_url, args.ref) 123 | 124 | execute_build_script(current_dir, sdk_path, args.module, args.target) 125 | 126 | # Export Rust SDK path for next steps, if running in GitHub Actions 127 | env_file_path = os.getenv('GITHUB_ENV') 128 | if os.path.exists(env_file_path): 129 | with open(env_file_path, "a") as file: 130 | file.write(f"RUST_SDK_PATH={sdk_path}") -------------------------------------------------------------------------------- /.github/workflows/release_sdk_parallel.yml: -------------------------------------------------------------------------------- 1 | name: Release SDK Library (parallel) 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | rust-checkout-ref: 7 | description: 'The branch, tag or SHA to checkout on the rust sdk.' 8 | required: true 9 | default: 'main' 10 | sdk-version: 11 | description: 'The new version for the sdk library.' 12 | required: true 13 | 14 | jobs: 15 | build_targets: 16 | strategy: 17 | matrix: 18 | target: [ "aarch64-linux-android", "armv7-linux-androideabi", "i686-linux-android", "x86_64-linux-android" ] 19 | name: "Build Rust target: ${{ matrix.target }}" 20 | runs-on: ubuntu-24.04 21 | env: 22 | NDK_VERSION: 28.2.13676358 23 | outputs: 24 | linkable_ref: ${{ steps.set_linkable_ref.outputs.linkable_ref }} 25 | 26 | concurrency: 27 | group: ${{ github.ref }}-${{ github.job }}-${{ matrix.target }} 28 | cancel-in-progress: true 29 | 30 | steps: 31 | - name: Checkout this repo 32 | uses: actions/checkout@v4 33 | 34 | - name: Configure git user 35 | run: | 36 | git config user.name github-actions 37 | git config user.email github-actions@github.com 38 | 39 | - uses: Swatinem/rust-cache@v2 40 | with: 41 | save-if: ${{ github.ref == 'refs/heads/main' || github.ref == 'main' }} 42 | cache-on-failure: true 43 | 44 | - name: Set up JDK 17 45 | uses: actions/setup-java@v4 46 | with: 47 | java-version: '17' 48 | distribution: 'temurin' # See 'Supported distributions' for available options 49 | 50 | # Note: the install android SDK step resets the `ANDROID_HOME` variable to a new folder with an update SDK but no NDK, 51 | # so we need to set this NDK_PATH before that happens 52 | - name: Configure android ndk 53 | run: | 54 | NDK_PATH=$ANDROID_HOME/ndk/$NDK_VERSION 55 | echo $NDK_PATH 56 | if [ -d "$NDK_PATH" ]; then 57 | echo "ANDROID_NDK_HOME=$NDK_PATH" >> $GITHUB_ENV 58 | echo "Using ndk $NDK_PATH" 59 | else 60 | echo "NDK_PATH not found, abort." 61 | exit 1 62 | fi 63 | 64 | - name: Install android sdk 65 | uses: malinskiy/action-android/install-sdk@release/0.1.4 66 | 67 | - name: Install Rust 68 | uses: dtolnay/rust-toolchain@stable 69 | 70 | - name: Install Protoc 71 | uses: arduino/setup-protoc@v1 72 | with: 73 | repo-token: ${{ secrets.GITHUB_TOKEN }} 74 | 75 | - name: Add Rust targets 76 | run: | 77 | rustup target add x86_64-linux-android 78 | rustup target add aarch64-linux-android 79 | rustup target add armv7-linux-androideabi 80 | rustup target add i686-linux-android 81 | 82 | - name: Install cargo-ndk 83 | continue-on-error: true 84 | run: cargo install cargo-ndk 85 | 86 | - name: Set up Python 3 87 | uses: actions/setup-python@v5 88 | with: 89 | python-version: '3.x' 90 | 91 | - name: Install python dependencies 92 | run: | 93 | python -m pip install --upgrade pip 94 | pip install argparse 95 | pip install requests 96 | 97 | - name: Run build script 98 | run: | 99 | python3 ./scripts/build-rust-for-target.py --module SDK --version ${{ github.event.inputs.sdk-version }} --ref ${{ github.event.inputs.rust-checkout-ref }} --target ${{ matrix.target }} 100 | 101 | - name: Set linkable git ref 102 | id: set_linkable_ref 103 | run: | 104 | pushd ${{ env.RUST_SDK_PATH }} 105 | COMMIT_HASH=$(git rev-parse --verify ${{ github.event.inputs.rust-checkout-ref }}) 106 | echo linkable_ref=$COMMIT_HASH >> $GITHUB_OUTPUT 107 | echo "Using commit hash $COMMIT_HASH" 108 | popd 109 | 110 | - name: Upload target artifacts 111 | if: success() || failure() 112 | uses: actions/upload-artifact@v4 113 | with: 114 | name: targets-${{ matrix.target }} 115 | if-no-files-found: error 116 | path: ./sdk/sdk-android/src/main/jniLibs/*/libmatrix_sdk_ffi.so 117 | retention-days: 7 118 | 119 | - name: Upload FFI bindings 120 | # The FFI bindings will be identical for the 4 architectures, so upload as artifact 121 | # only once. 122 | if: (success() || failure()) && matrix.target == 'x86_64-linux-android' 123 | uses: actions/upload-artifact@v4 124 | with: 125 | name: ffi-bindings 126 | if-no-files-found: error 127 | path: ./sdk/sdk-android/src/main/kotlin/ 128 | retention-days: 7 129 | 130 | release_library: 131 | name: "Release SDK Library" 132 | needs: build_targets 133 | runs-on: ubuntu-24.04 134 | 135 | concurrency: 136 | group: ${{ github.ref }}-${{ github.job }} 137 | cancel-in-progress: true 138 | 139 | steps: 140 | - name: Checkout this repo 141 | uses: actions/checkout@v4 142 | 143 | - name: Configure git user 144 | run: | 145 | git config user.name github-actions 146 | git config user.email github-actions@github.com 147 | 148 | - name: Download target artifacts to their right folders 149 | uses: actions/download-artifact@v4 150 | with: 151 | pattern: targets-* 152 | merge-multiple: true 153 | path: sdk/sdk-android/src/main/jniLibs/ 154 | 155 | - name: Download FFI bindings to their package 156 | uses: actions/download-artifact@v4 157 | with: 158 | name: ffi-bindings 159 | path: sdk/sdk-android/src/main/kotlin/ 160 | 161 | - name: Set up JDK 17 162 | uses: actions/setup-java@v4 163 | with: 164 | java-version: '17' 165 | distribution: 'temurin' # See 'Supported distributions' for available options 166 | 167 | - name: Install android sdk 168 | uses: malinskiy/action-android/install-sdk@release/0.1.4 169 | 170 | - name: Set up Python 3 171 | uses: actions/setup-python@v5 172 | with: 173 | python-version: '3.x' 174 | 175 | - name: Install python dependencies 176 | run: | 177 | python -m pip install --upgrade pip 178 | pip install argparse 179 | pip install requests 180 | 181 | - name: Run release script 182 | env: 183 | OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} 184 | OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} 185 | SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }} 186 | SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} 187 | SIGNING_KEY: ${{ secrets.SIGNING_KEY }} 188 | SONATYPE_STAGING_PROFILE_ID: ${{ secrets.SONATYPE_STAGING_PROFILE_ID }} 189 | GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} 190 | run: | 191 | python3 ./scripts/publish_release.py --module SDK --version ${{ github.event.inputs.sdk-version }} --linkable-ref ${{ needs.build_targets.outputs.linkable_ref }} 192 | 193 | - name: Upload AAR results 194 | if: success() || failure() 195 | uses: actions/upload-artifact@v4 196 | with: 197 | name: sdk-android-release 198 | if-no-files-found: error 199 | path: ./sdk/sdk-android/build/**/*.aar 200 | retention-days: 7 201 | -------------------------------------------------------------------------------- /.github/workflows/release_crypto.yml: -------------------------------------------------------------------------------- 1 | name: Release Crypto Library (parallel) 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | rust-checkout-ref: 7 | description: 'The branch, tag or SHA to checkout on the rust sdk.' 8 | required: true 9 | default: 'main' 10 | sdk-version: 11 | description: 'The new version for the crypto library.' 12 | required: true 13 | 14 | jobs: 15 | build_targets: 16 | strategy: 17 | matrix: 18 | target: [ "aarch64-linux-android", "armv7-linux-androideabi", "i686-linux-android", "x86_64-linux-android" ] 19 | name: "Build Rust target: ${{ matrix.target }}" 20 | runs-on: ubuntu-24.04 21 | env: 22 | NDK_VERSION: 28.2.13676358 23 | outputs: 24 | linkable_ref: ${{ steps.set_linkable_ref.outputs.linkable_ref }} 25 | 26 | concurrency: 27 | group: ${{ github.ref }}-${{ github.job }}-${{ matrix.target }} 28 | cancel-in-progress: true 29 | 30 | steps: 31 | - name: Checkout this repo 32 | uses: actions/checkout@v4 33 | 34 | - name: Configure git user 35 | run: | 36 | git config user.name github-actions 37 | git config user.email github-actions@github.com 38 | 39 | - uses: Swatinem/rust-cache@v2 40 | with: 41 | save-if: ${{ github.ref == 'refs/heads/main' || github.ref == 'main' }} 42 | cache-on-failure: true 43 | 44 | - name: Set up JDK 17 45 | uses: actions/setup-java@v4 46 | with: 47 | java-version: '17' 48 | distribution: 'temurin' # See 'Supported distributions' for available options 49 | 50 | # Note: the install android SDK step resets the `ANDROID_HOME` variable to a new folder with an update SDK but no NDK, 51 | # so we need to set this NDK_PATH before that happens 52 | - name: Configure android ndk 53 | run: | 54 | NDK_PATH=$ANDROID_HOME/ndk/$NDK_VERSION 55 | echo $NDK_PATH 56 | if [ -d "$NDK_PATH" ]; then 57 | echo "ANDROID_NDK_HOME=$NDK_PATH" >> $GITHUB_ENV 58 | echo "Using ndk $NDK_PATH" 59 | else 60 | echo "NDK_PATH not found, abort." 61 | exit 1 62 | fi 63 | 64 | - name: Install android sdk 65 | uses: malinskiy/action-android/install-sdk@release/0.1.4 66 | 67 | - name: Install Rust 68 | uses: dtolnay/rust-toolchain@stable 69 | 70 | - name: Install Protoc 71 | uses: arduino/setup-protoc@v1 72 | with: 73 | repo-token: ${{ secrets.GITHUB_TOKEN }} 74 | 75 | - name: Add Rust targets 76 | run: | 77 | rustup target add x86_64-linux-android 78 | rustup target add aarch64-linux-android 79 | rustup target add armv7-linux-androideabi 80 | rustup target add i686-linux-android 81 | 82 | - name: Install cargo-ndk 83 | continue-on-error: true 84 | run: cargo install cargo-ndk 85 | 86 | - name: Set up Python 3 87 | uses: actions/setup-python@v5 88 | with: 89 | python-version: '3.x' 90 | 91 | - name: Install python dependencies 92 | run: | 93 | python -m pip install --upgrade pip 94 | pip install argparse 95 | pip install requests 96 | 97 | - name: Run build script 98 | run: | 99 | python3 ./scripts/build-rust-for-target.py --module CRYPTO --version ${{ github.event.inputs.sdk-version }} --ref ${{ github.event.inputs.rust-checkout-ref }} --target ${{ matrix.target }} 100 | 101 | - name: Set linkable git ref 102 | id: set_linkable_ref 103 | run: | 104 | pushd ${{ env.RUST_SDK_PATH }} 105 | COMMIT_HASH=$(git rev-parse --verify ${{ github.event.inputs.rust-checkout-ref }}) 106 | echo linkable_ref=$COMMIT_HASH >> $GITHUB_OUTPUT 107 | echo "Using commit hash $COMMIT_HASH" 108 | popd 109 | 110 | - name: Upload target artifacts 111 | if: success() || failure() 112 | uses: actions/upload-artifact@v4 113 | with: 114 | name: targets-${{ matrix.target }} 115 | if-no-files-found: error 116 | path: ./crypto/crypto-android/src/main/jniLibs/*/libmatrix_sdk_crypto_ffi.so 117 | retention-days: 7 118 | 119 | - name: Upload FFI bindings 120 | # The FFI bindings will be identical for the 4 architectures, so upload as artifact 121 | # only once. 122 | if: (success() || failure()) && matrix.target == 'x86_64-linux-android' 123 | uses: actions/upload-artifact@v4 124 | with: 125 | name: ffi-bindings 126 | if-no-files-found: error 127 | path: ./crypto/crypto-android/src/main/kotlin/ 128 | retention-days: 7 129 | 130 | release_library: 131 | name: "Release SDK Library" 132 | needs: build_targets 133 | runs-on: ubuntu-24.04 134 | 135 | concurrency: 136 | group: ${{ github.ref }}-${{ github.job }} 137 | cancel-in-progress: true 138 | 139 | steps: 140 | - name: Checkout this repo 141 | uses: actions/checkout@v4 142 | 143 | - name: Configure git user 144 | run: | 145 | git config user.name github-actions 146 | git config user.email github-actions@github.com 147 | 148 | - name: Download target artifacts to their right folders 149 | uses: actions/download-artifact@v4 150 | with: 151 | pattern: targets-* 152 | merge-multiple: true 153 | path: crypto/crypto-android/src/main/jniLibs/ 154 | 155 | - name: Download FFI bindings to their package 156 | uses: actions/download-artifact@v4 157 | with: 158 | name: ffi-bindings 159 | path: crypto/crypto-android/src/main/kotlin/ 160 | 161 | - name: Set up JDK 17 162 | uses: actions/setup-java@v4 163 | with: 164 | java-version: '17' 165 | distribution: 'temurin' # See 'Supported distributions' for available options 166 | 167 | - name: Install android sdk 168 | uses: malinskiy/action-android/install-sdk@release/0.1.4 169 | 170 | - name: Set up Python 3 171 | uses: actions/setup-python@v5 172 | with: 173 | python-version: '3.x' 174 | 175 | - name: Install python dependencies 176 | run: | 177 | python -m pip install --upgrade pip 178 | pip install argparse 179 | pip install requests 180 | 181 | - name: Run release script 182 | env: 183 | OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} 184 | OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} 185 | SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }} 186 | SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} 187 | SIGNING_KEY: ${{ secrets.SIGNING_KEY }} 188 | SONATYPE_STAGING_PROFILE_ID: ${{ secrets.SONATYPE_STAGING_PROFILE_ID }} 189 | GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} 190 | run: | 191 | python3 ./scripts/publish_release.py --module CRYPTO --version ${{ github.event.inputs.sdk-version }} --linkable-ref ${{ needs.build_targets.outputs.linkable_ref }} 192 | 193 | - name: Upload AAR results 194 | if: success() || failure() 195 | uses: actions/upload-artifact@v4 196 | with: 197 | name: sdk-android-release 198 | if-no-files-found: error 199 | path: ./sdk/sdk-android/build/**/*.aar 200 | retention-days: 7 201 | -------------------------------------------------------------------------------- /scripts/publish_release.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import argparse 4 | import os 5 | import re 6 | import requests 7 | import subprocess 8 | from enum import Enum, auto 9 | 10 | 11 | class Module(Enum): 12 | SDK = auto() 13 | CRYPTO = auto() 14 | 15 | 16 | def module_type(value): 17 | try: 18 | return Module[value.upper()] 19 | except KeyError: 20 | raise argparse.ArgumentTypeError( 21 | f"Invalid module choice: {value}. Available options: SDK, CRYPTO") 22 | 23 | 24 | def override_version_in_build_version_file(file_path: str, new_version: str): 25 | with open(file_path, 'r') as file: 26 | content = file.read() 27 | 28 | new_major, new_minor, new_patch = map(int, new_version.split('.')) 29 | 30 | content = re.sub(r"(majorVersion\s*=\s*)(\d+)", rf"\g<1>{new_major}", content) 31 | content = re.sub(r"(minorVersion\s*=\s*)(\d+)", rf"\g<1>{new_minor}", content) 32 | content = re.sub(r"(patchVersion\s*=\s*)(\d+)", rf"\g<1>{new_patch}", content) 33 | 34 | with open(file_path, 'w') as file: 35 | file.write(content) 36 | 37 | 38 | def commit_and_push_changes(directory: str, message: str): 39 | try: 40 | subprocess.run( 41 | ["git", "add", "."], 42 | cwd=directory, 43 | check=True, 44 | capture_output=True, 45 | ) 46 | subprocess.run( 47 | ["git", "commit", "-m", message], 48 | cwd=directory, 49 | check=True, 50 | capture_output=True, 51 | ) 52 | subprocess.run(["git", "push"], cwd=directory, check=True, capture_output=True) 53 | print("Changes committed and pushed successfully.") 54 | except subprocess.CalledProcessError as e: 55 | print("Failed to commit and push changes.") 56 | print("Error message:") 57 | print(e.stderr) 58 | raise e 59 | 60 | 61 | def upload_asset_to_github_release( 62 | github_token: str, 63 | upload_url: str, 64 | asset_path: str, 65 | asset_name: str, 66 | ): 67 | print(f"Uploading {asset_name} to github release..") 68 | # Build headers with token and content type 69 | headers = { 70 | "Authorization": f"token {github_token}", 71 | "Content-Type": "application/octet-stream" 72 | } 73 | 74 | # Read asset file as binary content 75 | with open(asset_path, "rb") as asset_file: 76 | asset_content = asset_file.read() 77 | 78 | # Set the filename in the request URL 79 | upload_url = upload_url.replace("{?name,label}", f"?name={asset_name}") 80 | 81 | # Send asset upload request 82 | response = requests.post(upload_url, headers=headers, data=asset_content) 83 | if response.status_code == 201: 84 | print(f"Asset '{asset_name}' uploaded successfully.") 85 | else: 86 | print("Failed to upload asset.") 87 | print("Response:") 88 | print(response.json()) 89 | exit(1) 90 | 91 | 92 | def create_github_release( 93 | github_token: str, 94 | repo_url: str, 95 | tag_name: str, 96 | release_name: str, 97 | release_notes: str, 98 | asset_path: str, 99 | asset_name: str, 100 | ): 101 | print(f"Create github release {tag_name}") 102 | # Build release payload 103 | payload = { 104 | "tag_name": tag_name, 105 | "name": release_name, 106 | "body": release_notes, 107 | "draft": False, 108 | "prerelease": False 109 | } 110 | 111 | # Build request headers 112 | headers = { 113 | "Authorization": f"token {github_token}", 114 | "Accept": "application/vnd.github.v3+json" 115 | } 116 | 117 | # Send release request 118 | response = requests.post(f"{repo_url}/releases", headers=headers, json=payload) 119 | if response.status_code == 201: 120 | print("Release created successfully.") 121 | release_data = response.json() 122 | upload_url = release_data["upload_url"] 123 | upload_asset_to_github_release( 124 | github_token, 125 | upload_url, 126 | asset_path, 127 | asset_name, 128 | ) 129 | else: 130 | print("Failed to create release.") 131 | print("Response:") 132 | print(response.json()) 133 | exit(1) 134 | 135 | 136 | def get_asset_name(module: Module) -> str: 137 | if module == Module.SDK: 138 | return "matrix-android-sdk.aar" 139 | elif module == Module.CRYPTO: 140 | return "matrix-android-crypto.aar" 141 | else: 142 | raise ValueError(f"Unknown module: {module}") 143 | 144 | 145 | def get_asset_path(root_project_dir: str, module: Module) -> str: 146 | if module == Module.SDK: 147 | return os.path.join(root_project_dir, "sdk/sdk-android/build/outputs/aar", 148 | "sdk-android-release.aar") 149 | elif module == Module.CRYPTO: 150 | return os.path.join(root_project_dir, "crypto/crypto-android/build/outputs/aar", 151 | "crypto-android-release.aar") 152 | else: 153 | raise ValueError(f"Unknown module: {module}") 154 | 155 | 156 | def get_publish_task(module: Module) -> str: 157 | if module == Module.SDK: 158 | return ":sdk:sdk-android:publishToSonatype" 159 | elif module == Module.CRYPTO: 160 | return ":crypto:crypto-android:publishToSonatype" 161 | else: 162 | raise ValueError(f"Unknown module: {module}") 163 | 164 | 165 | def run_publish_close_and_release_tasks(root_project_dir, publish_task: str): 166 | gradle_command = f"./gradlew {publish_task} closeAndReleaseStagingRepository" 167 | result = subprocess.run(gradle_command, shell=True, cwd=root_project_dir, text=True) 168 | if result.returncode != 0: 169 | raise Exception(f"Gradle tasks failed with return code {result.returncode}") 170 | 171 | 172 | def get_build_version_file_path(module: Module, project_root: str) -> str: 173 | if module == Module.SDK: 174 | return os.path.join(project_root, 'buildSrc/src/main/kotlin', 'BuildVersionsSDK.kt') 175 | elif module == Module.CRYPTO: 176 | return os.path.join(project_root, 'buildSrc/src/main/kotlin', 'BuildVersionsCrypto.kt') 177 | else: 178 | raise ValueError(f"Unknown module: {module}") 179 | 180 | 181 | def build_aar_files(script_directory: str, module: Module): 182 | print("Execute build script...") 183 | build_script_path = os.path.join(script_directory, "build-aar.sh") 184 | subprocess.run( 185 | ["/bin/bash", build_script_path, "-m", module.name.lower(), "-r"], 186 | check=True, 187 | text=True 188 | ) 189 | print("Finish executing build script with success") 190 | 191 | 192 | def main(args: argparse.Namespace): 193 | github_token = os.environ['GITHUB_API_TOKEN'] 194 | if github_token is None: 195 | print("Please set GITHUB_API_TOKEN environment variable") 196 | exit(1) 197 | 198 | current_dir = os.path.dirname(os.path.abspath(__file__)) 199 | project_root = os.path.dirname(current_dir).rstrip(os.sep) 200 | 201 | print(f"Project Root Directory: {project_root}") 202 | print(f"Selected module: {args.module}") 203 | print(f"Version: {args.version}") 204 | 205 | build_version_file_path = get_build_version_file_path(args.module, project_root) 206 | 207 | build_aar_files(current_dir, args.module) 208 | 209 | override_version_in_build_version_file(build_version_file_path, args.version) 210 | 211 | # First release on Maven 212 | run_publish_close_and_release_tasks( 213 | project_root, 214 | get_publish_task(args.module), 215 | ) 216 | 217 | # Success, commit and push changes, then create github release 218 | commit_message = f"Bump {args.module.name} version to {args.version} (matrix-rust-sdk to {args.linkable_ref})" 219 | print(f"Commit message: {commit_message}") 220 | commit_and_push_changes(project_root, commit_message) 221 | 222 | release_name = f"{args.module.name.lower()}-v{args.version}" 223 | release_notes = f"https://github.com/matrix-org/matrix-rust-sdk/tree/{args.linkable_ref}" 224 | asset_path = get_asset_path(project_root, args.module) 225 | asset_name = get_asset_name(args.module) 226 | create_github_release( 227 | github_token, 228 | "https://api.github.com/repos/matrix-org/matrix-rust-components-kotlin", 229 | release_name, 230 | release_name, 231 | release_notes, 232 | asset_path, 233 | asset_name, 234 | ) 235 | 236 | 237 | parser = argparse.ArgumentParser() 238 | parser.add_argument("-m", "--module", type=module_type, required=True, 239 | help="Choose a module (SDK or CRYPTO)") 240 | parser.add_argument("-v", "--version", type=str, required=True, 241 | help="Version as a string (e.g. '1.0.0')") 242 | parser.add_argument("-l", "--linkable-ref", type=str, required=True, 243 | help="The git ref to link to in the matrix-rust-sdk project") 244 | args = parser.parse_args() 245 | 246 | main(args) 247 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # SPDX-License-Identifier: Apache-2.0 19 | # 20 | 21 | ############################################################################## 22 | # 23 | # Gradle start up script for POSIX generated by Gradle. 24 | # 25 | # Important for running: 26 | # 27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 | # noncompliant, but you have some other compliant shell such as ksh or 29 | # bash, then to run this script, type that shell name before the whole 30 | # command line, like: 31 | # 32 | # ksh Gradle 33 | # 34 | # Busybox and similar reduced shells will NOT work, because this script 35 | # requires all of these POSIX shell features: 36 | # * functions; 37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 | # * compound commands having a testable exit status, especially «case»; 40 | # * various built-in commands including «command», «set», and «ulimit». 41 | # 42 | # Important for patching: 43 | # 44 | # (2) This script targets any POSIX shell, so it avoids extensions provided 45 | # by Bash, Ksh, etc; in particular arrays are avoided. 46 | # 47 | # The "traditional" practice of packing multiple parameters into a 48 | # space-separated string is a well documented source of bugs and security 49 | # problems, so this is (mostly) avoided, by progressively accumulating 50 | # options in "$@", and eventually passing that to Java. 51 | # 52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 | # see the in-line comments for details. 55 | # 56 | # There are tweaks for specific operating systems such as AIX, CygWin, 57 | # Darwin, MinGW, and NonStop. 58 | # 59 | # (3) This script is generated from the Groovy template 60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 | # within the Gradle project. 62 | # 63 | # You can find Gradle at https://github.com/gradle/gradle/. 64 | # 65 | ############################################################################## 66 | 67 | # Attempt to set APP_HOME 68 | 69 | # Resolve links: $0 may be a link 70 | app_path=$0 71 | 72 | # Need this for daisy-chained symlinks. 73 | while 74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 | [ -h "$app_path" ] 76 | do 77 | ls=$( ls -ld "$app_path" ) 78 | link=${ls#*' -> '} 79 | case $link in #( 80 | /*) app_path=$link ;; #( 81 | *) app_path=$APP_HOME$link ;; 82 | esac 83 | done 84 | 85 | # This is normally unused 86 | # shellcheck disable=SC2034 87 | APP_BASE_NAME=${0##*/} 88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH="\\\"\\\"" 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | if ! command -v java >/dev/null 2>&1 137 | then 138 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 139 | 140 | Please set the JAVA_HOME variable in your environment to match the 141 | location of your Java installation." 142 | fi 143 | fi 144 | 145 | # Increase the maximum file descriptors if we can. 146 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 147 | case $MAX_FD in #( 148 | max*) 149 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 150 | # shellcheck disable=SC2039,SC3045 151 | MAX_FD=$( ulimit -H -n ) || 152 | warn "Could not query maximum file descriptor limit" 153 | esac 154 | case $MAX_FD in #( 155 | '' | soft) :;; #( 156 | *) 157 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 158 | # shellcheck disable=SC2039,SC3045 159 | ulimit -n "$MAX_FD" || 160 | warn "Could not set maximum file descriptor limit to $MAX_FD" 161 | esac 162 | fi 163 | 164 | # Collect all arguments for the java command, stacking in reverse order: 165 | # * args from the command line 166 | # * the main class name 167 | # * -classpath 168 | # * -D...appname settings 169 | # * --module-path (only if needed) 170 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 171 | 172 | # For Cygwin or MSYS, switch paths to Windows format before running java 173 | if "$cygwin" || "$msys" ; then 174 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 175 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 176 | 177 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 178 | 179 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 180 | for arg do 181 | if 182 | case $arg in #( 183 | -*) false ;; # don't mess with options #( 184 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 185 | [ -e "$t" ] ;; #( 186 | *) false ;; 187 | esac 188 | then 189 | arg=$( cygpath --path --ignore --mixed "$arg" ) 190 | fi 191 | # Roll the args list around exactly as many times as the number of 192 | # args, so each arg winds up back in the position where it started, but 193 | # possibly modified. 194 | # 195 | # NB: a `for` loop captures its iteration list before it begins, so 196 | # changing the positional parameters here affects neither the number of 197 | # iterations, nor the values presented in `arg`. 198 | shift # remove old arg 199 | set -- "$@" "$arg" # push replacement arg 200 | done 201 | fi 202 | 203 | 204 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 205 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 206 | 207 | # Collect all arguments for the java command: 208 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 209 | # and any embedded shellness will be escaped. 210 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 211 | # treated as '${Hostname}' itself on the command line. 212 | 213 | set -- \ 214 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 215 | -classpath "$CLASSPATH" \ 216 | -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ 217 | "$@" 218 | 219 | # Stop when "xargs" is not available. 220 | if ! command -v xargs >/dev/null 2>&1 221 | then 222 | die "xargs is not available" 223 | fi 224 | 225 | # Use "xargs" to parse quoted args. 226 | # 227 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 228 | # 229 | # In Bash we could simply go: 230 | # 231 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 232 | # set -- "${ARGS[@]}" "$@" 233 | # 234 | # but POSIX shell has neither arrays nor command substitution, so instead we 235 | # post-process each arg (as a line of input to sed) to backslash-escape any 236 | # character that might be a shell metacharacter, then use eval to reverse 237 | # that process (while maintaining the separation between arguments), and wrap 238 | # the whole thing up as a single "set" statement. 239 | # 240 | # This will of course break if any of these variables contains a newline or 241 | # an unmatched quote. 242 | # 243 | 244 | eval "set -- $( 245 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 246 | xargs -n1 | 247 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 248 | tr '\n' ' ' 249 | )" '"$@"' 250 | 251 | exec "$JAVACMD" "$@" 252 | -------------------------------------------------------------------------------- /crypto/crypto-android/src/main/kotlin/uniffi/matrix_sdk_common/matrix_sdk_common.kt: -------------------------------------------------------------------------------- 1 | // This file was autogenerated by some hot garbage in the `uniffi` crate. 2 | // Trust me, you don't want to mess with it! 3 | 4 | @file:Suppress("NAME_SHADOWING") 5 | 6 | package uniffi.matrix_sdk_common 7 | 8 | // Common helper code. 9 | // 10 | // Ideally this would live in a separate .kt file where it can be unittested etc 11 | // in isolation, and perhaps even published as a re-useable package. 12 | // 13 | // However, it's important that the details of how this helper code works (e.g. the 14 | // way that different builtin types are passed across the FFI) exactly match what's 15 | // expected by the Rust code on the other side of the interface. In practice right 16 | // now that means coming from the exact some version of `uniffi` that was used to 17 | // compile the Rust component. The easiest way to ensure this is to bundle the Kotlin 18 | // helpers directly inline like we're doing here. 19 | 20 | import com.sun.jna.Library 21 | import com.sun.jna.IntegerType 22 | import com.sun.jna.Native 23 | import com.sun.jna.Pointer 24 | import com.sun.jna.Structure 25 | import com.sun.jna.Callback 26 | import com.sun.jna.ptr.* 27 | import java.nio.ByteBuffer 28 | import java.nio.ByteOrder 29 | import java.nio.CharBuffer 30 | import java.nio.charset.CodingErrorAction 31 | import java.util.concurrent.atomic.AtomicLong 32 | import java.util.concurrent.ConcurrentHashMap 33 | 34 | // This is a helper for safely working with byte buffers returned from the Rust code. 35 | // A rust-owned buffer is represented by its capacity, its current length, and a 36 | // pointer to the underlying data. 37 | 38 | @Structure.FieldOrder("capacity", "len", "data") 39 | open class RustBuffer : Structure() { 40 | // Note: `capacity` and `len` are actually `ULong` values, but JVM only supports signed values. 41 | // When dealing with these fields, make sure to call `toULong()`. 42 | @JvmField var capacity: Long = 0 43 | @JvmField var len: Long = 0 44 | @JvmField var data: Pointer? = null 45 | 46 | class ByValue: RustBuffer(), Structure.ByValue 47 | class ByReference: RustBuffer(), Structure.ByReference 48 | 49 | internal fun setValue(other: RustBuffer) { 50 | capacity = other.capacity 51 | len = other.len 52 | data = other.data 53 | } 54 | 55 | companion object { 56 | internal fun alloc(size: ULong = 0UL) = uniffiRustCall() { status -> 57 | // Note: need to convert the size to a `Long` value to make this work with JVM. 58 | UniffiLib.INSTANCE.ffi_matrix_sdk_common_rustbuffer_alloc(size.toLong(), status) 59 | }.also { 60 | if(it.data == null) { 61 | throw RuntimeException("RustBuffer.alloc() returned null data pointer (size=${size})") 62 | } 63 | } 64 | 65 | internal fun create(capacity: ULong, len: ULong, data: Pointer?): RustBuffer.ByValue { 66 | var buf = RustBuffer.ByValue() 67 | buf.capacity = capacity.toLong() 68 | buf.len = len.toLong() 69 | buf.data = data 70 | return buf 71 | } 72 | 73 | internal fun free(buf: RustBuffer.ByValue) = uniffiRustCall() { status -> 74 | UniffiLib.INSTANCE.ffi_matrix_sdk_common_rustbuffer_free(buf, status) 75 | } 76 | } 77 | 78 | @Suppress("TooGenericExceptionThrown") 79 | fun asByteBuffer() = 80 | this.data?.getByteBuffer(0, this.len.toLong())?.also { 81 | it.order(ByteOrder.BIG_ENDIAN) 82 | } 83 | } 84 | 85 | /** 86 | * The equivalent of the `*mut RustBuffer` type. 87 | * Required for callbacks taking in an out pointer. 88 | * 89 | * Size is the sum of all values in the struct. 90 | */ 91 | class RustBufferByReference : ByReference(16) { 92 | /** 93 | * Set the pointed-to `RustBuffer` to the given value. 94 | */ 95 | fun setValue(value: RustBuffer.ByValue) { 96 | // NOTE: The offsets are as they are in the C-like struct. 97 | val pointer = getPointer() 98 | pointer.setLong(0, value.capacity) 99 | pointer.setLong(8, value.len) 100 | pointer.setPointer(16, value.data) 101 | } 102 | 103 | /** 104 | * Get a `RustBuffer.ByValue` from this reference. 105 | */ 106 | fun getValue(): RustBuffer.ByValue { 107 | val pointer = getPointer() 108 | val value = RustBuffer.ByValue() 109 | value.writeField("capacity", pointer.getLong(0)) 110 | value.writeField("len", pointer.getLong(8)) 111 | value.writeField("data", pointer.getLong(16)) 112 | 113 | return value 114 | } 115 | } 116 | 117 | // This is a helper for safely passing byte references into the rust code. 118 | // It's not actually used at the moment, because there aren't many things that you 119 | // can take a direct pointer to in the JVM, and if we're going to copy something 120 | // then we might as well copy it into a `RustBuffer`. But it's here for API 121 | // completeness. 122 | 123 | @Structure.FieldOrder("len", "data") 124 | open class ForeignBytes : Structure() { 125 | @JvmField var len: Int = 0 126 | @JvmField var data: Pointer? = null 127 | 128 | class ByValue : ForeignBytes(), Structure.ByValue 129 | } 130 | // The FfiConverter interface handles converter types to and from the FFI 131 | // 132 | // All implementing objects should be public to support external types. When a 133 | // type is external we need to import it's FfiConverter. 134 | public interface FfiConverter { 135 | // Convert an FFI type to a Kotlin type 136 | fun lift(value: FfiType): KotlinType 137 | 138 | // Convert an Kotlin type to an FFI type 139 | fun lower(value: KotlinType): FfiType 140 | 141 | // Read a Kotlin type from a `ByteBuffer` 142 | fun read(buf: ByteBuffer): KotlinType 143 | 144 | // Calculate bytes to allocate when creating a `RustBuffer` 145 | // 146 | // This must return at least as many bytes as the write() function will 147 | // write. It can return more bytes than needed, for example when writing 148 | // Strings we can't know the exact bytes needed until we the UTF-8 149 | // encoding, so we pessimistically allocate the largest size possible (3 150 | // bytes per codepoint). Allocating extra bytes is not really a big deal 151 | // because the `RustBuffer` is short-lived. 152 | fun allocationSize(value: KotlinType): ULong 153 | 154 | // Write a Kotlin type to a `ByteBuffer` 155 | fun write(value: KotlinType, buf: ByteBuffer) 156 | 157 | // Lower a value into a `RustBuffer` 158 | // 159 | // This method lowers a value into a `RustBuffer` rather than the normal 160 | // FfiType. It's used by the callback interface code. Callback interface 161 | // returns are always serialized into a `RustBuffer` regardless of their 162 | // normal FFI type. 163 | fun lowerIntoRustBuffer(value: KotlinType): RustBuffer.ByValue { 164 | val rbuf = RustBuffer.alloc(allocationSize(value)) 165 | try { 166 | val bbuf = rbuf.data!!.getByteBuffer(0, rbuf.capacity).also { 167 | it.order(ByteOrder.BIG_ENDIAN) 168 | } 169 | write(value, bbuf) 170 | rbuf.writeField("len", bbuf.position().toLong()) 171 | return rbuf 172 | } catch (e: Throwable) { 173 | RustBuffer.free(rbuf) 174 | throw e 175 | } 176 | } 177 | 178 | // Lift a value from a `RustBuffer`. 179 | // 180 | // This here mostly because of the symmetry with `lowerIntoRustBuffer()`. 181 | // It's currently only used by the `FfiConverterRustBuffer` class below. 182 | fun liftFromRustBuffer(rbuf: RustBuffer.ByValue): KotlinType { 183 | val byteBuf = rbuf.asByteBuffer()!! 184 | try { 185 | val item = read(byteBuf) 186 | if (byteBuf.hasRemaining()) { 187 | throw RuntimeException("junk remaining in buffer after lifting, something is very wrong!!") 188 | } 189 | return item 190 | } finally { 191 | RustBuffer.free(rbuf) 192 | } 193 | } 194 | } 195 | 196 | // FfiConverter that uses `RustBuffer` as the FfiType 197 | public interface FfiConverterRustBuffer: FfiConverter { 198 | override fun lift(value: RustBuffer.ByValue) = liftFromRustBuffer(value) 199 | override fun lower(value: KotlinType) = lowerIntoRustBuffer(value) 200 | } 201 | // A handful of classes and functions to support the generated data structures. 202 | // This would be a good candidate for isolating in its own ffi-support lib. 203 | 204 | internal const val UNIFFI_CALL_SUCCESS = 0.toByte() 205 | internal const val UNIFFI_CALL_ERROR = 1.toByte() 206 | internal const val UNIFFI_CALL_UNEXPECTED_ERROR = 2.toByte() 207 | 208 | @Structure.FieldOrder("code", "error_buf") 209 | internal open class UniffiRustCallStatus : Structure() { 210 | @JvmField var code: Byte = 0 211 | @JvmField var error_buf: RustBuffer.ByValue = RustBuffer.ByValue() 212 | 213 | class ByValue: UniffiRustCallStatus(), Structure.ByValue 214 | 215 | fun isSuccess(): Boolean { 216 | return code == UNIFFI_CALL_SUCCESS 217 | } 218 | 219 | fun isError(): Boolean { 220 | return code == UNIFFI_CALL_ERROR 221 | } 222 | 223 | fun isPanic(): Boolean { 224 | return code == UNIFFI_CALL_UNEXPECTED_ERROR 225 | } 226 | 227 | companion object { 228 | fun create(code: Byte, errorBuf: RustBuffer.ByValue): UniffiRustCallStatus.ByValue { 229 | val callStatus = UniffiRustCallStatus.ByValue() 230 | callStatus.code = code 231 | callStatus.error_buf = errorBuf 232 | return callStatus 233 | } 234 | } 235 | } 236 | 237 | class InternalException(message: String) : kotlin.Exception(message) 238 | 239 | // Each top-level error class has a companion object that can lift the error from the call status's rust buffer 240 | interface UniffiRustCallStatusErrorHandler { 241 | fun lift(error_buf: RustBuffer.ByValue): E; 242 | } 243 | 244 | // Helpers for calling Rust 245 | // In practice we usually need to be synchronized to call this safely, so it doesn't 246 | // synchronize itself 247 | 248 | // Call a rust function that returns a Result<>. Pass in the Error class companion that corresponds to the Err 249 | private inline fun uniffiRustCallWithError(errorHandler: UniffiRustCallStatusErrorHandler, callback: (UniffiRustCallStatus) -> U): U { 250 | var status = UniffiRustCallStatus() 251 | val return_value = callback(status) 252 | uniffiCheckCallStatus(errorHandler, status) 253 | return return_value 254 | } 255 | 256 | // Check UniffiRustCallStatus and throw an error if the call wasn't successful 257 | private fun uniffiCheckCallStatus(errorHandler: UniffiRustCallStatusErrorHandler, status: UniffiRustCallStatus) { 258 | if (status.isSuccess()) { 259 | return 260 | } else if (status.isError()) { 261 | throw errorHandler.lift(status.error_buf) 262 | } else if (status.isPanic()) { 263 | // when the rust code sees a panic, it tries to construct a rustbuffer 264 | // with the message. but if that code panics, then it just sends back 265 | // an empty buffer. 266 | if (status.error_buf.len > 0) { 267 | throw InternalException(FfiConverterString.lift(status.error_buf)) 268 | } else { 269 | throw InternalException("Rust panic") 270 | } 271 | } else { 272 | throw InternalException("Unknown rust call status: $status.code") 273 | } 274 | } 275 | 276 | // UniffiRustCallStatusErrorHandler implementation for times when we don't expect a CALL_ERROR 277 | object UniffiNullRustCallStatusErrorHandler: UniffiRustCallStatusErrorHandler { 278 | override fun lift(error_buf: RustBuffer.ByValue): InternalException { 279 | RustBuffer.free(error_buf) 280 | return InternalException("Unexpected CALL_ERROR") 281 | } 282 | } 283 | 284 | // Call a rust function that returns a plain value 285 | private inline fun uniffiRustCall(callback: (UniffiRustCallStatus) -> U): U { 286 | return uniffiRustCallWithError(UniffiNullRustCallStatusErrorHandler, callback) 287 | } 288 | 289 | internal inline fun uniffiTraitInterfaceCall( 290 | callStatus: UniffiRustCallStatus, 291 | makeCall: () -> T, 292 | writeReturn: (T) -> Unit, 293 | ) { 294 | try { 295 | writeReturn(makeCall()) 296 | } catch(e: kotlin.Exception) { 297 | callStatus.code = UNIFFI_CALL_UNEXPECTED_ERROR 298 | callStatus.error_buf = FfiConverterString.lower(e.toString()) 299 | } 300 | } 301 | 302 | internal inline fun uniffiTraitInterfaceCallWithError( 303 | callStatus: UniffiRustCallStatus, 304 | makeCall: () -> T, 305 | writeReturn: (T) -> Unit, 306 | lowerError: (E) -> RustBuffer.ByValue 307 | ) { 308 | try { 309 | writeReturn(makeCall()) 310 | } catch(e: kotlin.Exception) { 311 | if (e is E) { 312 | callStatus.code = UNIFFI_CALL_ERROR 313 | callStatus.error_buf = lowerError(e) 314 | } else { 315 | callStatus.code = UNIFFI_CALL_UNEXPECTED_ERROR 316 | callStatus.error_buf = FfiConverterString.lower(e.toString()) 317 | } 318 | } 319 | } 320 | // Map handles to objects 321 | // 322 | // This is used pass an opaque 64-bit handle representing a foreign object to the Rust code. 323 | internal class UniffiHandleMap { 324 | private val map = ConcurrentHashMap() 325 | private val counter = java.util.concurrent.atomic.AtomicLong(0) 326 | 327 | val size: Int 328 | get() = map.size 329 | 330 | // Insert a new object into the handle map and get a handle for it 331 | fun insert(obj: T): Long { 332 | val handle = counter.getAndAdd(1) 333 | map.put(handle, obj) 334 | return handle 335 | } 336 | 337 | // Get an object from the handle map 338 | fun get(handle: Long): T { 339 | return map.get(handle) ?: throw InternalException("UniffiHandleMap.get: Invalid handle") 340 | } 341 | 342 | // Remove an entry from the handlemap and get the Kotlin object back 343 | fun remove(handle: Long): T { 344 | return map.remove(handle) ?: throw InternalException("UniffiHandleMap: Invalid handle") 345 | } 346 | } 347 | 348 | // Contains loading, initialization code, 349 | // and the FFI Function declarations in a com.sun.jna.Library. 350 | @Synchronized 351 | private fun findLibraryName(componentName: String): String { 352 | val libOverride = System.getProperty("uniffi.component.$componentName.libraryOverride") 353 | if (libOverride != null) { 354 | return libOverride 355 | } 356 | return "matrix_sdk_crypto_ffi" 357 | } 358 | 359 | private inline fun loadIndirect( 360 | componentName: String 361 | ): Lib { 362 | return Native.load(findLibraryName(componentName), Lib::class.java) 363 | } 364 | 365 | // Define FFI callback types 366 | internal interface UniffiRustFutureContinuationCallback : com.sun.jna.Callback { 367 | fun callback(`data`: Long,`pollResult`: Byte,) 368 | } 369 | internal interface UniffiForeignFutureFree : com.sun.jna.Callback { 370 | fun callback(`handle`: Long,) 371 | } 372 | internal interface UniffiCallbackInterfaceFree : com.sun.jna.Callback { 373 | fun callback(`handle`: Long,) 374 | } 375 | @Structure.FieldOrder("handle", "free") 376 | internal open class UniffiForeignFuture( 377 | @JvmField internal var `handle`: Long = 0.toLong(), 378 | @JvmField internal var `free`: UniffiForeignFutureFree? = null, 379 | ) : Structure() { 380 | class UniffiByValue( 381 | `handle`: Long = 0.toLong(), 382 | `free`: UniffiForeignFutureFree? = null, 383 | ): UniffiForeignFuture(`handle`,`free`,), Structure.ByValue 384 | 385 | internal fun uniffiSetValue(other: UniffiForeignFuture) { 386 | `handle` = other.`handle` 387 | `free` = other.`free` 388 | } 389 | 390 | } 391 | @Structure.FieldOrder("returnValue", "callStatus") 392 | internal open class UniffiForeignFutureStructU8( 393 | @JvmField internal var `returnValue`: Byte = 0.toByte(), 394 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 395 | ) : Structure() { 396 | class UniffiByValue( 397 | `returnValue`: Byte = 0.toByte(), 398 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 399 | ): UniffiForeignFutureStructU8(`returnValue`,`callStatus`,), Structure.ByValue 400 | 401 | internal fun uniffiSetValue(other: UniffiForeignFutureStructU8) { 402 | `returnValue` = other.`returnValue` 403 | `callStatus` = other.`callStatus` 404 | } 405 | 406 | } 407 | internal interface UniffiForeignFutureCompleteU8 : com.sun.jna.Callback { 408 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructU8.UniffiByValue,) 409 | } 410 | @Structure.FieldOrder("returnValue", "callStatus") 411 | internal open class UniffiForeignFutureStructI8( 412 | @JvmField internal var `returnValue`: Byte = 0.toByte(), 413 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 414 | ) : Structure() { 415 | class UniffiByValue( 416 | `returnValue`: Byte = 0.toByte(), 417 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 418 | ): UniffiForeignFutureStructI8(`returnValue`,`callStatus`,), Structure.ByValue 419 | 420 | internal fun uniffiSetValue(other: UniffiForeignFutureStructI8) { 421 | `returnValue` = other.`returnValue` 422 | `callStatus` = other.`callStatus` 423 | } 424 | 425 | } 426 | internal interface UniffiForeignFutureCompleteI8 : com.sun.jna.Callback { 427 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructI8.UniffiByValue,) 428 | } 429 | @Structure.FieldOrder("returnValue", "callStatus") 430 | internal open class UniffiForeignFutureStructU16( 431 | @JvmField internal var `returnValue`: Short = 0.toShort(), 432 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 433 | ) : Structure() { 434 | class UniffiByValue( 435 | `returnValue`: Short = 0.toShort(), 436 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 437 | ): UniffiForeignFutureStructU16(`returnValue`,`callStatus`,), Structure.ByValue 438 | 439 | internal fun uniffiSetValue(other: UniffiForeignFutureStructU16) { 440 | `returnValue` = other.`returnValue` 441 | `callStatus` = other.`callStatus` 442 | } 443 | 444 | } 445 | internal interface UniffiForeignFutureCompleteU16 : com.sun.jna.Callback { 446 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructU16.UniffiByValue,) 447 | } 448 | @Structure.FieldOrder("returnValue", "callStatus") 449 | internal open class UniffiForeignFutureStructI16( 450 | @JvmField internal var `returnValue`: Short = 0.toShort(), 451 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 452 | ) : Structure() { 453 | class UniffiByValue( 454 | `returnValue`: Short = 0.toShort(), 455 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 456 | ): UniffiForeignFutureStructI16(`returnValue`,`callStatus`,), Structure.ByValue 457 | 458 | internal fun uniffiSetValue(other: UniffiForeignFutureStructI16) { 459 | `returnValue` = other.`returnValue` 460 | `callStatus` = other.`callStatus` 461 | } 462 | 463 | } 464 | internal interface UniffiForeignFutureCompleteI16 : com.sun.jna.Callback { 465 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructI16.UniffiByValue,) 466 | } 467 | @Structure.FieldOrder("returnValue", "callStatus") 468 | internal open class UniffiForeignFutureStructU32( 469 | @JvmField internal var `returnValue`: Int = 0, 470 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 471 | ) : Structure() { 472 | class UniffiByValue( 473 | `returnValue`: Int = 0, 474 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 475 | ): UniffiForeignFutureStructU32(`returnValue`,`callStatus`,), Structure.ByValue 476 | 477 | internal fun uniffiSetValue(other: UniffiForeignFutureStructU32) { 478 | `returnValue` = other.`returnValue` 479 | `callStatus` = other.`callStatus` 480 | } 481 | 482 | } 483 | internal interface UniffiForeignFutureCompleteU32 : com.sun.jna.Callback { 484 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructU32.UniffiByValue,) 485 | } 486 | @Structure.FieldOrder("returnValue", "callStatus") 487 | internal open class UniffiForeignFutureStructI32( 488 | @JvmField internal var `returnValue`: Int = 0, 489 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 490 | ) : Structure() { 491 | class UniffiByValue( 492 | `returnValue`: Int = 0, 493 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 494 | ): UniffiForeignFutureStructI32(`returnValue`,`callStatus`,), Structure.ByValue 495 | 496 | internal fun uniffiSetValue(other: UniffiForeignFutureStructI32) { 497 | `returnValue` = other.`returnValue` 498 | `callStatus` = other.`callStatus` 499 | } 500 | 501 | } 502 | internal interface UniffiForeignFutureCompleteI32 : com.sun.jna.Callback { 503 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructI32.UniffiByValue,) 504 | } 505 | @Structure.FieldOrder("returnValue", "callStatus") 506 | internal open class UniffiForeignFutureStructU64( 507 | @JvmField internal var `returnValue`: Long = 0.toLong(), 508 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 509 | ) : Structure() { 510 | class UniffiByValue( 511 | `returnValue`: Long = 0.toLong(), 512 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 513 | ): UniffiForeignFutureStructU64(`returnValue`,`callStatus`,), Structure.ByValue 514 | 515 | internal fun uniffiSetValue(other: UniffiForeignFutureStructU64) { 516 | `returnValue` = other.`returnValue` 517 | `callStatus` = other.`callStatus` 518 | } 519 | 520 | } 521 | internal interface UniffiForeignFutureCompleteU64 : com.sun.jna.Callback { 522 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructU64.UniffiByValue,) 523 | } 524 | @Structure.FieldOrder("returnValue", "callStatus") 525 | internal open class UniffiForeignFutureStructI64( 526 | @JvmField internal var `returnValue`: Long = 0.toLong(), 527 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 528 | ) : Structure() { 529 | class UniffiByValue( 530 | `returnValue`: Long = 0.toLong(), 531 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 532 | ): UniffiForeignFutureStructI64(`returnValue`,`callStatus`,), Structure.ByValue 533 | 534 | internal fun uniffiSetValue(other: UniffiForeignFutureStructI64) { 535 | `returnValue` = other.`returnValue` 536 | `callStatus` = other.`callStatus` 537 | } 538 | 539 | } 540 | internal interface UniffiForeignFutureCompleteI64 : com.sun.jna.Callback { 541 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructI64.UniffiByValue,) 542 | } 543 | @Structure.FieldOrder("returnValue", "callStatus") 544 | internal open class UniffiForeignFutureStructF32( 545 | @JvmField internal var `returnValue`: Float = 0.0f, 546 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 547 | ) : Structure() { 548 | class UniffiByValue( 549 | `returnValue`: Float = 0.0f, 550 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 551 | ): UniffiForeignFutureStructF32(`returnValue`,`callStatus`,), Structure.ByValue 552 | 553 | internal fun uniffiSetValue(other: UniffiForeignFutureStructF32) { 554 | `returnValue` = other.`returnValue` 555 | `callStatus` = other.`callStatus` 556 | } 557 | 558 | } 559 | internal interface UniffiForeignFutureCompleteF32 : com.sun.jna.Callback { 560 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructF32.UniffiByValue,) 561 | } 562 | @Structure.FieldOrder("returnValue", "callStatus") 563 | internal open class UniffiForeignFutureStructF64( 564 | @JvmField internal var `returnValue`: Double = 0.0, 565 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 566 | ) : Structure() { 567 | class UniffiByValue( 568 | `returnValue`: Double = 0.0, 569 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 570 | ): UniffiForeignFutureStructF64(`returnValue`,`callStatus`,), Structure.ByValue 571 | 572 | internal fun uniffiSetValue(other: UniffiForeignFutureStructF64) { 573 | `returnValue` = other.`returnValue` 574 | `callStatus` = other.`callStatus` 575 | } 576 | 577 | } 578 | internal interface UniffiForeignFutureCompleteF64 : com.sun.jna.Callback { 579 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructF64.UniffiByValue,) 580 | } 581 | @Structure.FieldOrder("returnValue", "callStatus") 582 | internal open class UniffiForeignFutureStructPointer( 583 | @JvmField internal var `returnValue`: Pointer = Pointer.NULL, 584 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 585 | ) : Structure() { 586 | class UniffiByValue( 587 | `returnValue`: Pointer = Pointer.NULL, 588 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 589 | ): UniffiForeignFutureStructPointer(`returnValue`,`callStatus`,), Structure.ByValue 590 | 591 | internal fun uniffiSetValue(other: UniffiForeignFutureStructPointer) { 592 | `returnValue` = other.`returnValue` 593 | `callStatus` = other.`callStatus` 594 | } 595 | 596 | } 597 | internal interface UniffiForeignFutureCompletePointer : com.sun.jna.Callback { 598 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructPointer.UniffiByValue,) 599 | } 600 | @Structure.FieldOrder("returnValue", "callStatus") 601 | internal open class UniffiForeignFutureStructRustBuffer( 602 | @JvmField internal var `returnValue`: RustBuffer.ByValue = RustBuffer.ByValue(), 603 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 604 | ) : Structure() { 605 | class UniffiByValue( 606 | `returnValue`: RustBuffer.ByValue = RustBuffer.ByValue(), 607 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 608 | ): UniffiForeignFutureStructRustBuffer(`returnValue`,`callStatus`,), Structure.ByValue 609 | 610 | internal fun uniffiSetValue(other: UniffiForeignFutureStructRustBuffer) { 611 | `returnValue` = other.`returnValue` 612 | `callStatus` = other.`callStatus` 613 | } 614 | 615 | } 616 | internal interface UniffiForeignFutureCompleteRustBuffer : com.sun.jna.Callback { 617 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructRustBuffer.UniffiByValue,) 618 | } 619 | @Structure.FieldOrder("callStatus") 620 | internal open class UniffiForeignFutureStructVoid( 621 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 622 | ) : Structure() { 623 | class UniffiByValue( 624 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 625 | ): UniffiForeignFutureStructVoid(`callStatus`,), Structure.ByValue 626 | 627 | internal fun uniffiSetValue(other: UniffiForeignFutureStructVoid) { 628 | `callStatus` = other.`callStatus` 629 | } 630 | 631 | } 632 | internal interface UniffiForeignFutureCompleteVoid : com.sun.jna.Callback { 633 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructVoid.UniffiByValue,) 634 | } 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | // A JNA Library to expose the extern-C FFI definitions. 694 | // This is an implementation detail which will be called internally by the public API. 695 | 696 | internal interface UniffiLib : Library { 697 | companion object { 698 | internal val INSTANCE: UniffiLib by lazy { 699 | loadIndirect(componentName = "matrix_sdk_common") 700 | .also { lib: UniffiLib -> 701 | uniffiCheckContractApiVersion(lib) 702 | uniffiCheckApiChecksums(lib) 703 | } 704 | } 705 | 706 | } 707 | 708 | fun ffi_matrix_sdk_common_rustbuffer_alloc(`size`: Long,uniffi_out_err: UniffiRustCallStatus, 709 | ): RustBuffer.ByValue 710 | fun ffi_matrix_sdk_common_rustbuffer_from_bytes(`bytes`: ForeignBytes.ByValue,uniffi_out_err: UniffiRustCallStatus, 711 | ): RustBuffer.ByValue 712 | fun ffi_matrix_sdk_common_rustbuffer_free(`buf`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, 713 | ): Unit 714 | fun ffi_matrix_sdk_common_rustbuffer_reserve(`buf`: RustBuffer.ByValue,`additional`: Long,uniffi_out_err: UniffiRustCallStatus, 715 | ): RustBuffer.ByValue 716 | fun ffi_matrix_sdk_common_rust_future_poll_u8(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 717 | ): Unit 718 | fun ffi_matrix_sdk_common_rust_future_cancel_u8(`handle`: Long, 719 | ): Unit 720 | fun ffi_matrix_sdk_common_rust_future_free_u8(`handle`: Long, 721 | ): Unit 722 | fun ffi_matrix_sdk_common_rust_future_complete_u8(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 723 | ): Byte 724 | fun ffi_matrix_sdk_common_rust_future_poll_i8(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 725 | ): Unit 726 | fun ffi_matrix_sdk_common_rust_future_cancel_i8(`handle`: Long, 727 | ): Unit 728 | fun ffi_matrix_sdk_common_rust_future_free_i8(`handle`: Long, 729 | ): Unit 730 | fun ffi_matrix_sdk_common_rust_future_complete_i8(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 731 | ): Byte 732 | fun ffi_matrix_sdk_common_rust_future_poll_u16(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 733 | ): Unit 734 | fun ffi_matrix_sdk_common_rust_future_cancel_u16(`handle`: Long, 735 | ): Unit 736 | fun ffi_matrix_sdk_common_rust_future_free_u16(`handle`: Long, 737 | ): Unit 738 | fun ffi_matrix_sdk_common_rust_future_complete_u16(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 739 | ): Short 740 | fun ffi_matrix_sdk_common_rust_future_poll_i16(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 741 | ): Unit 742 | fun ffi_matrix_sdk_common_rust_future_cancel_i16(`handle`: Long, 743 | ): Unit 744 | fun ffi_matrix_sdk_common_rust_future_free_i16(`handle`: Long, 745 | ): Unit 746 | fun ffi_matrix_sdk_common_rust_future_complete_i16(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 747 | ): Short 748 | fun ffi_matrix_sdk_common_rust_future_poll_u32(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 749 | ): Unit 750 | fun ffi_matrix_sdk_common_rust_future_cancel_u32(`handle`: Long, 751 | ): Unit 752 | fun ffi_matrix_sdk_common_rust_future_free_u32(`handle`: Long, 753 | ): Unit 754 | fun ffi_matrix_sdk_common_rust_future_complete_u32(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 755 | ): Int 756 | fun ffi_matrix_sdk_common_rust_future_poll_i32(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 757 | ): Unit 758 | fun ffi_matrix_sdk_common_rust_future_cancel_i32(`handle`: Long, 759 | ): Unit 760 | fun ffi_matrix_sdk_common_rust_future_free_i32(`handle`: Long, 761 | ): Unit 762 | fun ffi_matrix_sdk_common_rust_future_complete_i32(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 763 | ): Int 764 | fun ffi_matrix_sdk_common_rust_future_poll_u64(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 765 | ): Unit 766 | fun ffi_matrix_sdk_common_rust_future_cancel_u64(`handle`: Long, 767 | ): Unit 768 | fun ffi_matrix_sdk_common_rust_future_free_u64(`handle`: Long, 769 | ): Unit 770 | fun ffi_matrix_sdk_common_rust_future_complete_u64(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 771 | ): Long 772 | fun ffi_matrix_sdk_common_rust_future_poll_i64(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 773 | ): Unit 774 | fun ffi_matrix_sdk_common_rust_future_cancel_i64(`handle`: Long, 775 | ): Unit 776 | fun ffi_matrix_sdk_common_rust_future_free_i64(`handle`: Long, 777 | ): Unit 778 | fun ffi_matrix_sdk_common_rust_future_complete_i64(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 779 | ): Long 780 | fun ffi_matrix_sdk_common_rust_future_poll_f32(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 781 | ): Unit 782 | fun ffi_matrix_sdk_common_rust_future_cancel_f32(`handle`: Long, 783 | ): Unit 784 | fun ffi_matrix_sdk_common_rust_future_free_f32(`handle`: Long, 785 | ): Unit 786 | fun ffi_matrix_sdk_common_rust_future_complete_f32(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 787 | ): Float 788 | fun ffi_matrix_sdk_common_rust_future_poll_f64(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 789 | ): Unit 790 | fun ffi_matrix_sdk_common_rust_future_cancel_f64(`handle`: Long, 791 | ): Unit 792 | fun ffi_matrix_sdk_common_rust_future_free_f64(`handle`: Long, 793 | ): Unit 794 | fun ffi_matrix_sdk_common_rust_future_complete_f64(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 795 | ): Double 796 | fun ffi_matrix_sdk_common_rust_future_poll_pointer(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 797 | ): Unit 798 | fun ffi_matrix_sdk_common_rust_future_cancel_pointer(`handle`: Long, 799 | ): Unit 800 | fun ffi_matrix_sdk_common_rust_future_free_pointer(`handle`: Long, 801 | ): Unit 802 | fun ffi_matrix_sdk_common_rust_future_complete_pointer(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 803 | ): Pointer 804 | fun ffi_matrix_sdk_common_rust_future_poll_rust_buffer(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 805 | ): Unit 806 | fun ffi_matrix_sdk_common_rust_future_cancel_rust_buffer(`handle`: Long, 807 | ): Unit 808 | fun ffi_matrix_sdk_common_rust_future_free_rust_buffer(`handle`: Long, 809 | ): Unit 810 | fun ffi_matrix_sdk_common_rust_future_complete_rust_buffer(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 811 | ): RustBuffer.ByValue 812 | fun ffi_matrix_sdk_common_rust_future_poll_void(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 813 | ): Unit 814 | fun ffi_matrix_sdk_common_rust_future_cancel_void(`handle`: Long, 815 | ): Unit 816 | fun ffi_matrix_sdk_common_rust_future_free_void(`handle`: Long, 817 | ): Unit 818 | fun ffi_matrix_sdk_common_rust_future_complete_void(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 819 | ): Unit 820 | fun ffi_matrix_sdk_common_uniffi_contract_version( 821 | ): Int 822 | 823 | } 824 | 825 | private fun uniffiCheckContractApiVersion(lib: UniffiLib) { 826 | // Get the bindings contract version from our ComponentInterface 827 | val bindings_contract_version = 26 828 | // Get the scaffolding contract version by calling the into the dylib 829 | val scaffolding_contract_version = lib.ffi_matrix_sdk_common_uniffi_contract_version() 830 | if (bindings_contract_version != scaffolding_contract_version) { 831 | throw RuntimeException("UniFFI contract version mismatch: try cleaning and rebuilding your project") 832 | } 833 | } 834 | 835 | @Suppress("UNUSED_PARAMETER") 836 | private fun uniffiCheckApiChecksums(lib: UniffiLib) { 837 | } 838 | 839 | // Async support 840 | 841 | // Public interface members begin here. 842 | 843 | 844 | // Interface implemented by anything that can contain an object reference. 845 | // 846 | // Such types expose a `destroy()` method that must be called to cleanly 847 | // dispose of the contained objects. Failure to call this method may result 848 | // in memory leaks. 849 | // 850 | // The easiest way to ensure this method is called is to use the `.use` 851 | // helper method to execute a block and destroy the object at the end. 852 | interface Disposable { 853 | fun destroy() 854 | companion object { 855 | fun destroy(vararg args: Any?) { 856 | args.filterIsInstance() 857 | .forEach(Disposable::destroy) 858 | } 859 | } 860 | } 861 | 862 | inline fun T.use(block: (T) -> R) = 863 | try { 864 | block(this) 865 | } finally { 866 | try { 867 | // N.B. our implementation is on the nullable type `Disposable?`. 868 | this?.destroy() 869 | } catch (e: Throwable) { 870 | // swallow 871 | } 872 | } 873 | 874 | /** Used to instantiate an interface without an actual pointer, for fakes in tests, mostly. */ 875 | object NoPointer 876 | 877 | public object FfiConverterString: FfiConverter { 878 | // Note: we don't inherit from FfiConverterRustBuffer, because we use a 879 | // special encoding when lowering/lifting. We can use `RustBuffer.len` to 880 | // store our length and avoid writing it out to the buffer. 881 | override fun lift(value: RustBuffer.ByValue): String { 882 | try { 883 | val byteArr = ByteArray(value.len.toInt()) 884 | value.asByteBuffer()!!.get(byteArr) 885 | return byteArr.toString(Charsets.UTF_8) 886 | } finally { 887 | RustBuffer.free(value) 888 | } 889 | } 890 | 891 | override fun read(buf: ByteBuffer): String { 892 | val len = buf.getInt() 893 | val byteArr = ByteArray(len) 894 | buf.get(byteArr) 895 | return byteArr.toString(Charsets.UTF_8) 896 | } 897 | 898 | fun toUtf8(value: String): ByteBuffer { 899 | // Make sure we don't have invalid UTF-16, check for lone surrogates. 900 | return Charsets.UTF_8.newEncoder().run { 901 | onMalformedInput(CodingErrorAction.REPORT) 902 | encode(CharBuffer.wrap(value)) 903 | } 904 | } 905 | 906 | override fun lower(value: String): RustBuffer.ByValue { 907 | val byteBuf = toUtf8(value) 908 | // Ideally we'd pass these bytes to `ffi_bytebuffer_from_bytes`, but doing so would require us 909 | // to copy them into a JNA `Memory`. So we might as well directly copy them into a `RustBuffer`. 910 | val rbuf = RustBuffer.alloc(byteBuf.limit().toULong()) 911 | rbuf.asByteBuffer()!!.put(byteBuf) 912 | return rbuf 913 | } 914 | 915 | // We aren't sure exactly how many bytes our string will be once it's UTF-8 916 | // encoded. Allocate 3 bytes per UTF-16 code unit which will always be 917 | // enough. 918 | override fun allocationSize(value: String): ULong { 919 | val sizeForLength = 4UL 920 | val sizeForString = value.length.toULong() * 3UL 921 | return sizeForLength + sizeForString 922 | } 923 | 924 | override fun write(value: String, buf: ByteBuffer) { 925 | val byteBuf = toUtf8(value) 926 | buf.putInt(byteBuf.limit()) 927 | buf.put(byteBuf) 928 | } 929 | } 930 | 931 | 932 | 933 | /** 934 | * A machine-readable representation of the authenticity for a `ShieldState`. 935 | */ 936 | 937 | enum class ShieldStateCode { 938 | 939 | /** 940 | * Not enough information available to check the authenticity. 941 | */ 942 | AUTHENTICITY_NOT_GUARANTEED, 943 | /** 944 | * The sending device isn't yet known by the Client. 945 | */ 946 | UNKNOWN_DEVICE, 947 | /** 948 | * The sending device hasn't been verified by the sender. 949 | */ 950 | UNSIGNED_DEVICE, 951 | /** 952 | * The sender hasn't been verified by the Client's user. 953 | */ 954 | UNVERIFIED_IDENTITY, 955 | /** 956 | * An unencrypted event in an encrypted room. 957 | */ 958 | SENT_IN_CLEAR, 959 | /** 960 | * The sender was previously verified but changed their identity. 961 | */ 962 | VERIFICATION_VIOLATION; 963 | companion object 964 | } 965 | 966 | 967 | public object FfiConverterTypeShieldStateCode: FfiConverterRustBuffer { 968 | override fun read(buf: ByteBuffer) = try { 969 | ShieldStateCode.values()[buf.getInt() - 1] 970 | } catch (e: IndexOutOfBoundsException) { 971 | throw RuntimeException("invalid enum value, something is very wrong!!", e) 972 | } 973 | 974 | override fun allocationSize(value: ShieldStateCode) = 4UL 975 | 976 | override fun write(value: ShieldStateCode, buf: ByteBuffer) { 977 | buf.putInt(value.ordinal + 1) 978 | } 979 | } 980 | 981 | 982 | 983 | -------------------------------------------------------------------------------- /sdk/sdk-android/src/main/kotlin/uniffi/matrix_sdk_common/matrix_sdk_common.kt: -------------------------------------------------------------------------------- 1 | // This file was autogenerated by some hot garbage in the `uniffi` crate. 2 | // Trust me, you don't want to mess with it! 3 | 4 | @file:Suppress("NAME_SHADOWING") 5 | 6 | package uniffi.matrix_sdk_common 7 | 8 | // Common helper code. 9 | // 10 | // Ideally this would live in a separate .kt file where it can be unittested etc 11 | // in isolation, and perhaps even published as a re-useable package. 12 | // 13 | // However, it's important that the details of how this helper code works (e.g. the 14 | // way that different builtin types are passed across the FFI) exactly match what's 15 | // expected by the Rust code on the other side of the interface. In practice right 16 | // now that means coming from the exact some version of `uniffi` that was used to 17 | // compile the Rust component. The easiest way to ensure this is to bundle the Kotlin 18 | // helpers directly inline like we're doing here. 19 | 20 | import com.sun.jna.Library 21 | import com.sun.jna.IntegerType 22 | import com.sun.jna.Native 23 | import com.sun.jna.Pointer 24 | import com.sun.jna.Structure 25 | import com.sun.jna.Callback 26 | import com.sun.jna.ptr.* 27 | import java.nio.ByteBuffer 28 | import java.nio.ByteOrder 29 | import java.nio.CharBuffer 30 | import java.nio.charset.CodingErrorAction 31 | import java.util.concurrent.atomic.AtomicLong 32 | import java.util.concurrent.ConcurrentHashMap 33 | 34 | // This is a helper for safely working with byte buffers returned from the Rust code. 35 | // A rust-owned buffer is represented by its capacity, its current length, and a 36 | // pointer to the underlying data. 37 | 38 | /** 39 | * @suppress 40 | */ 41 | @Structure.FieldOrder("capacity", "len", "data") 42 | open class RustBuffer : Structure() { 43 | // Note: `capacity` and `len` are actually `ULong` values, but JVM only supports signed values. 44 | // When dealing with these fields, make sure to call `toULong()`. 45 | @JvmField var capacity: Long = 0 46 | @JvmField var len: Long = 0 47 | @JvmField var data: Pointer? = null 48 | 49 | class ByValue: RustBuffer(), Structure.ByValue 50 | class ByReference: RustBuffer(), Structure.ByReference 51 | 52 | internal fun setValue(other: RustBuffer) { 53 | capacity = other.capacity 54 | len = other.len 55 | data = other.data 56 | } 57 | 58 | companion object { 59 | internal fun alloc(size: ULong = 0UL) = uniffiRustCall() { status -> 60 | // Note: need to convert the size to a `Long` value to make this work with JVM. 61 | UniffiLib.ffi_matrix_sdk_common_rustbuffer_alloc(size.toLong(), status) 62 | }.also { 63 | if(it.data == null) { 64 | throw RuntimeException("RustBuffer.alloc() returned null data pointer (size=${size})") 65 | } 66 | } 67 | 68 | internal fun create(capacity: ULong, len: ULong, data: Pointer?): RustBuffer.ByValue { 69 | var buf = RustBuffer.ByValue() 70 | buf.capacity = capacity.toLong() 71 | buf.len = len.toLong() 72 | buf.data = data 73 | return buf 74 | } 75 | 76 | internal fun free(buf: RustBuffer.ByValue) = uniffiRustCall() { status -> 77 | UniffiLib.ffi_matrix_sdk_common_rustbuffer_free(buf, status) 78 | } 79 | } 80 | 81 | @Suppress("TooGenericExceptionThrown") 82 | fun asByteBuffer() = 83 | this.data?.getByteBuffer(0, this.len.toLong())?.also { 84 | it.order(ByteOrder.BIG_ENDIAN) 85 | } 86 | } 87 | 88 | // This is a helper for safely passing byte references into the rust code. 89 | // It's not actually used at the moment, because there aren't many things that you 90 | // can take a direct pointer to in the JVM, and if we're going to copy something 91 | // then we might as well copy it into a `RustBuffer`. But it's here for API 92 | // completeness. 93 | 94 | @Structure.FieldOrder("len", "data") 95 | internal open class ForeignBytes : Structure() { 96 | @JvmField var len: Int = 0 97 | @JvmField var data: Pointer? = null 98 | 99 | class ByValue : ForeignBytes(), Structure.ByValue 100 | } 101 | /** 102 | * The FfiConverter interface handles converter types to and from the FFI 103 | * 104 | * All implementing objects should be public to support external types. When a 105 | * type is external we need to import it's FfiConverter. 106 | * 107 | * @suppress 108 | */ 109 | public interface FfiConverter { 110 | // Convert an FFI type to a Kotlin type 111 | fun lift(value: FfiType): KotlinType 112 | 113 | // Convert an Kotlin type to an FFI type 114 | fun lower(value: KotlinType): FfiType 115 | 116 | // Read a Kotlin type from a `ByteBuffer` 117 | fun read(buf: ByteBuffer): KotlinType 118 | 119 | // Calculate bytes to allocate when creating a `RustBuffer` 120 | // 121 | // This must return at least as many bytes as the write() function will 122 | // write. It can return more bytes than needed, for example when writing 123 | // Strings we can't know the exact bytes needed until we the UTF-8 124 | // encoding, so we pessimistically allocate the largest size possible (3 125 | // bytes per codepoint). Allocating extra bytes is not really a big deal 126 | // because the `RustBuffer` is short-lived. 127 | fun allocationSize(value: KotlinType): ULong 128 | 129 | // Write a Kotlin type to a `ByteBuffer` 130 | fun write(value: KotlinType, buf: ByteBuffer) 131 | 132 | // Lower a value into a `RustBuffer` 133 | // 134 | // This method lowers a value into a `RustBuffer` rather than the normal 135 | // FfiType. It's used by the callback interface code. Callback interface 136 | // returns are always serialized into a `RustBuffer` regardless of their 137 | // normal FFI type. 138 | fun lowerIntoRustBuffer(value: KotlinType): RustBuffer.ByValue { 139 | val rbuf = RustBuffer.alloc(allocationSize(value)) 140 | try { 141 | val bbuf = rbuf.data!!.getByteBuffer(0, rbuf.capacity).also { 142 | it.order(ByteOrder.BIG_ENDIAN) 143 | } 144 | write(value, bbuf) 145 | rbuf.writeField("len", bbuf.position().toLong()) 146 | return rbuf 147 | } catch (e: Throwable) { 148 | RustBuffer.free(rbuf) 149 | throw e 150 | } 151 | } 152 | 153 | // Lift a value from a `RustBuffer`. 154 | // 155 | // This here mostly because of the symmetry with `lowerIntoRustBuffer()`. 156 | // It's currently only used by the `FfiConverterRustBuffer` class below. 157 | fun liftFromRustBuffer(rbuf: RustBuffer.ByValue): KotlinType { 158 | val byteBuf = rbuf.asByteBuffer()!! 159 | try { 160 | val item = read(byteBuf) 161 | if (byteBuf.hasRemaining()) { 162 | throw RuntimeException("junk remaining in buffer after lifting, something is very wrong!!") 163 | } 164 | return item 165 | } finally { 166 | RustBuffer.free(rbuf) 167 | } 168 | } 169 | } 170 | 171 | /** 172 | * FfiConverter that uses `RustBuffer` as the FfiType 173 | * 174 | * @suppress 175 | */ 176 | public interface FfiConverterRustBuffer: FfiConverter { 177 | override fun lift(value: RustBuffer.ByValue) = liftFromRustBuffer(value) 178 | override fun lower(value: KotlinType) = lowerIntoRustBuffer(value) 179 | } 180 | // A handful of classes and functions to support the generated data structures. 181 | // This would be a good candidate for isolating in its own ffi-support lib. 182 | 183 | internal const val UNIFFI_CALL_SUCCESS = 0.toByte() 184 | internal const val UNIFFI_CALL_ERROR = 1.toByte() 185 | internal const val UNIFFI_CALL_UNEXPECTED_ERROR = 2.toByte() 186 | 187 | @Structure.FieldOrder("code", "error_buf") 188 | internal open class UniffiRustCallStatus : Structure() { 189 | @JvmField var code: Byte = 0 190 | @JvmField var error_buf: RustBuffer.ByValue = RustBuffer.ByValue() 191 | 192 | class ByValue: UniffiRustCallStatus(), Structure.ByValue 193 | 194 | fun isSuccess(): Boolean { 195 | return code == UNIFFI_CALL_SUCCESS 196 | } 197 | 198 | fun isError(): Boolean { 199 | return code == UNIFFI_CALL_ERROR 200 | } 201 | 202 | fun isPanic(): Boolean { 203 | return code == UNIFFI_CALL_UNEXPECTED_ERROR 204 | } 205 | 206 | companion object { 207 | fun create(code: Byte, errorBuf: RustBuffer.ByValue): UniffiRustCallStatus.ByValue { 208 | val callStatus = UniffiRustCallStatus.ByValue() 209 | callStatus.code = code 210 | callStatus.error_buf = errorBuf 211 | return callStatus 212 | } 213 | } 214 | } 215 | 216 | class InternalException(message: String) : kotlin.Exception(message) 217 | 218 | /** 219 | * Each top-level error class has a companion object that can lift the error from the call status's rust buffer 220 | * 221 | * @suppress 222 | */ 223 | interface UniffiRustCallStatusErrorHandler { 224 | fun lift(error_buf: RustBuffer.ByValue): E; 225 | } 226 | 227 | // Helpers for calling Rust 228 | // In practice we usually need to be synchronized to call this safely, so it doesn't 229 | // synchronize itself 230 | 231 | // Call a rust function that returns a Result<>. Pass in the Error class companion that corresponds to the Err 232 | private inline fun uniffiRustCallWithError(errorHandler: UniffiRustCallStatusErrorHandler, callback: (UniffiRustCallStatus) -> U): U { 233 | var status = UniffiRustCallStatus() 234 | val return_value = callback(status) 235 | uniffiCheckCallStatus(errorHandler, status) 236 | return return_value 237 | } 238 | 239 | // Check UniffiRustCallStatus and throw an error if the call wasn't successful 240 | private fun uniffiCheckCallStatus(errorHandler: UniffiRustCallStatusErrorHandler, status: UniffiRustCallStatus) { 241 | if (status.isSuccess()) { 242 | return 243 | } else if (status.isError()) { 244 | throw errorHandler.lift(status.error_buf) 245 | } else if (status.isPanic()) { 246 | // when the rust code sees a panic, it tries to construct a rustbuffer 247 | // with the message. but if that code panics, then it just sends back 248 | // an empty buffer. 249 | if (status.error_buf.len > 0) { 250 | throw InternalException(FfiConverterString.lift(status.error_buf)) 251 | } else { 252 | throw InternalException("Rust panic") 253 | } 254 | } else { 255 | throw InternalException("Unknown rust call status: $status.code") 256 | } 257 | } 258 | 259 | /** 260 | * UniffiRustCallStatusErrorHandler implementation for times when we don't expect a CALL_ERROR 261 | * 262 | * @suppress 263 | */ 264 | object UniffiNullRustCallStatusErrorHandler: UniffiRustCallStatusErrorHandler { 265 | override fun lift(error_buf: RustBuffer.ByValue): InternalException { 266 | RustBuffer.free(error_buf) 267 | return InternalException("Unexpected CALL_ERROR") 268 | } 269 | } 270 | 271 | // Call a rust function that returns a plain value 272 | private inline fun uniffiRustCall(callback: (UniffiRustCallStatus) -> U): U { 273 | return uniffiRustCallWithError(UniffiNullRustCallStatusErrorHandler, callback) 274 | } 275 | 276 | internal inline fun uniffiTraitInterfaceCall( 277 | callStatus: UniffiRustCallStatus, 278 | makeCall: () -> T, 279 | writeReturn: (T) -> Unit, 280 | ) { 281 | try { 282 | writeReturn(makeCall()) 283 | } catch(e: kotlin.Exception) { 284 | val err = try { e.stackTraceToString() } catch(_: Throwable) { "" } 285 | callStatus.code = UNIFFI_CALL_UNEXPECTED_ERROR 286 | callStatus.error_buf = FfiConverterString.lower(err) 287 | } 288 | } 289 | 290 | internal inline fun uniffiTraitInterfaceCallWithError( 291 | callStatus: UniffiRustCallStatus, 292 | makeCall: () -> T, 293 | writeReturn: (T) -> Unit, 294 | lowerError: (E) -> RustBuffer.ByValue 295 | ) { 296 | try { 297 | writeReturn(makeCall()) 298 | } catch(e: kotlin.Exception) { 299 | if (e is E) { 300 | callStatus.code = UNIFFI_CALL_ERROR 301 | callStatus.error_buf = lowerError(e) 302 | } else { 303 | val err = try { e.stackTraceToString() } catch(_: Throwable) { "" } 304 | callStatus.code = UNIFFI_CALL_UNEXPECTED_ERROR 305 | callStatus.error_buf = FfiConverterString.lower(err) 306 | } 307 | } 308 | } 309 | // Initial value and increment amount for handles. 310 | // These ensure that Kotlin-generated handles always have the lowest bit set 311 | private const val UNIFFI_HANDLEMAP_INITIAL = 1.toLong() 312 | private const val UNIFFI_HANDLEMAP_DELTA = 2.toLong() 313 | 314 | // Map handles to objects 315 | // 316 | // This is used pass an opaque 64-bit handle representing a foreign object to the Rust code. 317 | internal class UniffiHandleMap { 318 | private val map = ConcurrentHashMap() 319 | // Start 320 | private val counter = java.util.concurrent.atomic.AtomicLong(UNIFFI_HANDLEMAP_INITIAL) 321 | 322 | val size: Int 323 | get() = map.size 324 | 325 | // Insert a new object into the handle map and get a handle for it 326 | fun insert(obj: T): Long { 327 | val handle = counter.getAndAdd(UNIFFI_HANDLEMAP_DELTA) 328 | map.put(handle, obj) 329 | return handle 330 | } 331 | 332 | // Clone a handle, creating a new one 333 | fun clone(handle: Long): Long { 334 | val obj = map.get(handle) ?: throw InternalException("UniffiHandleMap.clone: Invalid handle") 335 | return insert(obj) 336 | } 337 | 338 | // Get an object from the handle map 339 | fun get(handle: Long): T { 340 | return map.get(handle) ?: throw InternalException("UniffiHandleMap.get: Invalid handle") 341 | } 342 | 343 | // Remove an entry from the handlemap and get the Kotlin object back 344 | fun remove(handle: Long): T { 345 | return map.remove(handle) ?: throw InternalException("UniffiHandleMap: Invalid handle") 346 | } 347 | } 348 | 349 | // Contains loading, initialization code, 350 | // and the FFI Function declarations in a com.sun.jna.Library. 351 | @Synchronized 352 | private fun findLibraryName(componentName: String): String { 353 | val libOverride = System.getProperty("uniffi.component.$componentName.libraryOverride") 354 | if (libOverride != null) { 355 | return libOverride 356 | } 357 | return "matrix_sdk_ffi" 358 | } 359 | 360 | // Define FFI callback types 361 | internal interface UniffiRustFutureContinuationCallback : com.sun.jna.Callback { 362 | fun callback(`data`: Long,`pollResult`: Byte,) 363 | } 364 | internal interface UniffiForeignFutureDroppedCallback : com.sun.jna.Callback { 365 | fun callback(`handle`: Long,) 366 | } 367 | internal interface UniffiCallbackInterfaceFree : com.sun.jna.Callback { 368 | fun callback(`handle`: Long,) 369 | } 370 | internal interface UniffiCallbackInterfaceClone : com.sun.jna.Callback { 371 | fun callback(`handle`: Long,) 372 | : Long 373 | } 374 | @Structure.FieldOrder("handle", "free") 375 | internal open class UniffiForeignFutureDroppedCallbackStruct( 376 | @JvmField internal var `handle`: Long = 0.toLong(), 377 | @JvmField internal var `free`: UniffiForeignFutureDroppedCallback? = null, 378 | ) : Structure() { 379 | class UniffiByValue( 380 | `handle`: Long = 0.toLong(), 381 | `free`: UniffiForeignFutureDroppedCallback? = null, 382 | ): UniffiForeignFutureDroppedCallbackStruct(`handle`,`free`,), Structure.ByValue 383 | 384 | internal fun uniffiSetValue(other: UniffiForeignFutureDroppedCallbackStruct) { 385 | `handle` = other.`handle` 386 | `free` = other.`free` 387 | } 388 | 389 | } 390 | @Structure.FieldOrder("returnValue", "callStatus") 391 | internal open class UniffiForeignFutureResultU8( 392 | @JvmField internal var `returnValue`: Byte = 0.toByte(), 393 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 394 | ) : Structure() { 395 | class UniffiByValue( 396 | `returnValue`: Byte = 0.toByte(), 397 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 398 | ): UniffiForeignFutureResultU8(`returnValue`,`callStatus`,), Structure.ByValue 399 | 400 | internal fun uniffiSetValue(other: UniffiForeignFutureResultU8) { 401 | `returnValue` = other.`returnValue` 402 | `callStatus` = other.`callStatus` 403 | } 404 | 405 | } 406 | internal interface UniffiForeignFutureCompleteU8 : com.sun.jna.Callback { 407 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultU8.UniffiByValue,) 408 | } 409 | @Structure.FieldOrder("returnValue", "callStatus") 410 | internal open class UniffiForeignFutureResultI8( 411 | @JvmField internal var `returnValue`: Byte = 0.toByte(), 412 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 413 | ) : Structure() { 414 | class UniffiByValue( 415 | `returnValue`: Byte = 0.toByte(), 416 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 417 | ): UniffiForeignFutureResultI8(`returnValue`,`callStatus`,), Structure.ByValue 418 | 419 | internal fun uniffiSetValue(other: UniffiForeignFutureResultI8) { 420 | `returnValue` = other.`returnValue` 421 | `callStatus` = other.`callStatus` 422 | } 423 | 424 | } 425 | internal interface UniffiForeignFutureCompleteI8 : com.sun.jna.Callback { 426 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultI8.UniffiByValue,) 427 | } 428 | @Structure.FieldOrder("returnValue", "callStatus") 429 | internal open class UniffiForeignFutureResultU16( 430 | @JvmField internal var `returnValue`: Short = 0.toShort(), 431 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 432 | ) : Structure() { 433 | class UniffiByValue( 434 | `returnValue`: Short = 0.toShort(), 435 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 436 | ): UniffiForeignFutureResultU16(`returnValue`,`callStatus`,), Structure.ByValue 437 | 438 | internal fun uniffiSetValue(other: UniffiForeignFutureResultU16) { 439 | `returnValue` = other.`returnValue` 440 | `callStatus` = other.`callStatus` 441 | } 442 | 443 | } 444 | internal interface UniffiForeignFutureCompleteU16 : com.sun.jna.Callback { 445 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultU16.UniffiByValue,) 446 | } 447 | @Structure.FieldOrder("returnValue", "callStatus") 448 | internal open class UniffiForeignFutureResultI16( 449 | @JvmField internal var `returnValue`: Short = 0.toShort(), 450 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 451 | ) : Structure() { 452 | class UniffiByValue( 453 | `returnValue`: Short = 0.toShort(), 454 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 455 | ): UniffiForeignFutureResultI16(`returnValue`,`callStatus`,), Structure.ByValue 456 | 457 | internal fun uniffiSetValue(other: UniffiForeignFutureResultI16) { 458 | `returnValue` = other.`returnValue` 459 | `callStatus` = other.`callStatus` 460 | } 461 | 462 | } 463 | internal interface UniffiForeignFutureCompleteI16 : com.sun.jna.Callback { 464 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultI16.UniffiByValue,) 465 | } 466 | @Structure.FieldOrder("returnValue", "callStatus") 467 | internal open class UniffiForeignFutureResultU32( 468 | @JvmField internal var `returnValue`: Int = 0, 469 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 470 | ) : Structure() { 471 | class UniffiByValue( 472 | `returnValue`: Int = 0, 473 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 474 | ): UniffiForeignFutureResultU32(`returnValue`,`callStatus`,), Structure.ByValue 475 | 476 | internal fun uniffiSetValue(other: UniffiForeignFutureResultU32) { 477 | `returnValue` = other.`returnValue` 478 | `callStatus` = other.`callStatus` 479 | } 480 | 481 | } 482 | internal interface UniffiForeignFutureCompleteU32 : com.sun.jna.Callback { 483 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultU32.UniffiByValue,) 484 | } 485 | @Structure.FieldOrder("returnValue", "callStatus") 486 | internal open class UniffiForeignFutureResultI32( 487 | @JvmField internal var `returnValue`: Int = 0, 488 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 489 | ) : Structure() { 490 | class UniffiByValue( 491 | `returnValue`: Int = 0, 492 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 493 | ): UniffiForeignFutureResultI32(`returnValue`,`callStatus`,), Structure.ByValue 494 | 495 | internal fun uniffiSetValue(other: UniffiForeignFutureResultI32) { 496 | `returnValue` = other.`returnValue` 497 | `callStatus` = other.`callStatus` 498 | } 499 | 500 | } 501 | internal interface UniffiForeignFutureCompleteI32 : com.sun.jna.Callback { 502 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultI32.UniffiByValue,) 503 | } 504 | @Structure.FieldOrder("returnValue", "callStatus") 505 | internal open class UniffiForeignFutureResultU64( 506 | @JvmField internal var `returnValue`: Long = 0.toLong(), 507 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 508 | ) : Structure() { 509 | class UniffiByValue( 510 | `returnValue`: Long = 0.toLong(), 511 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 512 | ): UniffiForeignFutureResultU64(`returnValue`,`callStatus`,), Structure.ByValue 513 | 514 | internal fun uniffiSetValue(other: UniffiForeignFutureResultU64) { 515 | `returnValue` = other.`returnValue` 516 | `callStatus` = other.`callStatus` 517 | } 518 | 519 | } 520 | internal interface UniffiForeignFutureCompleteU64 : com.sun.jna.Callback { 521 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultU64.UniffiByValue,) 522 | } 523 | @Structure.FieldOrder("returnValue", "callStatus") 524 | internal open class UniffiForeignFutureResultI64( 525 | @JvmField internal var `returnValue`: Long = 0.toLong(), 526 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 527 | ) : Structure() { 528 | class UniffiByValue( 529 | `returnValue`: Long = 0.toLong(), 530 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 531 | ): UniffiForeignFutureResultI64(`returnValue`,`callStatus`,), Structure.ByValue 532 | 533 | internal fun uniffiSetValue(other: UniffiForeignFutureResultI64) { 534 | `returnValue` = other.`returnValue` 535 | `callStatus` = other.`callStatus` 536 | } 537 | 538 | } 539 | internal interface UniffiForeignFutureCompleteI64 : com.sun.jna.Callback { 540 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultI64.UniffiByValue,) 541 | } 542 | @Structure.FieldOrder("returnValue", "callStatus") 543 | internal open class UniffiForeignFutureResultF32( 544 | @JvmField internal var `returnValue`: Float = 0.0f, 545 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 546 | ) : Structure() { 547 | class UniffiByValue( 548 | `returnValue`: Float = 0.0f, 549 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 550 | ): UniffiForeignFutureResultF32(`returnValue`,`callStatus`,), Structure.ByValue 551 | 552 | internal fun uniffiSetValue(other: UniffiForeignFutureResultF32) { 553 | `returnValue` = other.`returnValue` 554 | `callStatus` = other.`callStatus` 555 | } 556 | 557 | } 558 | internal interface UniffiForeignFutureCompleteF32 : com.sun.jna.Callback { 559 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultF32.UniffiByValue,) 560 | } 561 | @Structure.FieldOrder("returnValue", "callStatus") 562 | internal open class UniffiForeignFutureResultF64( 563 | @JvmField internal var `returnValue`: Double = 0.0, 564 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 565 | ) : Structure() { 566 | class UniffiByValue( 567 | `returnValue`: Double = 0.0, 568 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 569 | ): UniffiForeignFutureResultF64(`returnValue`,`callStatus`,), Structure.ByValue 570 | 571 | internal fun uniffiSetValue(other: UniffiForeignFutureResultF64) { 572 | `returnValue` = other.`returnValue` 573 | `callStatus` = other.`callStatus` 574 | } 575 | 576 | } 577 | internal interface UniffiForeignFutureCompleteF64 : com.sun.jna.Callback { 578 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultF64.UniffiByValue,) 579 | } 580 | @Structure.FieldOrder("returnValue", "callStatus") 581 | internal open class UniffiForeignFutureResultRustBuffer( 582 | @JvmField internal var `returnValue`: RustBuffer.ByValue = RustBuffer.ByValue(), 583 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 584 | ) : Structure() { 585 | class UniffiByValue( 586 | `returnValue`: RustBuffer.ByValue = RustBuffer.ByValue(), 587 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 588 | ): UniffiForeignFutureResultRustBuffer(`returnValue`,`callStatus`,), Structure.ByValue 589 | 590 | internal fun uniffiSetValue(other: UniffiForeignFutureResultRustBuffer) { 591 | `returnValue` = other.`returnValue` 592 | `callStatus` = other.`callStatus` 593 | } 594 | 595 | } 596 | internal interface UniffiForeignFutureCompleteRustBuffer : com.sun.jna.Callback { 597 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultRustBuffer.UniffiByValue,) 598 | } 599 | @Structure.FieldOrder("callStatus") 600 | internal open class UniffiForeignFutureResultVoid( 601 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 602 | ) : Structure() { 603 | class UniffiByValue( 604 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 605 | ): UniffiForeignFutureResultVoid(`callStatus`,), Structure.ByValue 606 | 607 | internal fun uniffiSetValue(other: UniffiForeignFutureResultVoid) { 608 | `callStatus` = other.`callStatus` 609 | } 610 | 611 | } 612 | internal interface UniffiForeignFutureCompleteVoid : com.sun.jna.Callback { 613 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultVoid.UniffiByValue,) 614 | } 615 | 616 | // A JNA Library to expose the extern-C FFI definitions. 617 | // This is an implementation detail which will be called internally by the public API. 618 | 619 | // For large crates we prevent `MethodTooLargeException` (see #2340) 620 | // N.B. the name of the extension is very misleading, since it is 621 | // rather `InterfaceTooLargeException`, caused by too many methods 622 | // in the interface for large crates. 623 | // 624 | // By splitting the otherwise huge interface into two parts 625 | // * UniffiLib (this) 626 | // * IntegrityCheckingUniffiLib 627 | // And all checksum methods are put into `IntegrityCheckingUniffiLib` 628 | // we allow for ~2x as many methods in the UniffiLib interface. 629 | // 630 | // Note: above all written when we used JNA's `loadIndirect` etc. 631 | // We now use JNA's "direct mapping" - unclear if same considerations apply exactly. 632 | internal object IntegrityCheckingUniffiLib { 633 | init { 634 | Native.register(IntegrityCheckingUniffiLib::class.java, findLibraryName(componentName = "matrix_sdk_common")) 635 | uniffiCheckContractApiVersion(this) 636 | uniffiCheckApiChecksums(this) 637 | } 638 | external fun ffi_matrix_sdk_common_uniffi_contract_version( 639 | ): Int 640 | 641 | 642 | } 643 | 644 | internal object UniffiLib { 645 | 646 | 647 | init { 648 | Native.register(UniffiLib::class.java, findLibraryName(componentName = "matrix_sdk_common")) 649 | 650 | } 651 | external fun ffi_matrix_sdk_common_rustbuffer_alloc(`size`: Long,uniffi_out_err: UniffiRustCallStatus, 652 | ): RustBuffer.ByValue 653 | external fun ffi_matrix_sdk_common_rustbuffer_from_bytes(`bytes`: ForeignBytes.ByValue,uniffi_out_err: UniffiRustCallStatus, 654 | ): RustBuffer.ByValue 655 | external fun ffi_matrix_sdk_common_rustbuffer_free(`buf`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, 656 | ): Unit 657 | external fun ffi_matrix_sdk_common_rustbuffer_reserve(`buf`: RustBuffer.ByValue,`additional`: Long,uniffi_out_err: UniffiRustCallStatus, 658 | ): RustBuffer.ByValue 659 | external fun ffi_matrix_sdk_common_rust_future_poll_u8(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 660 | ): Unit 661 | external fun ffi_matrix_sdk_common_rust_future_cancel_u8(`handle`: Long, 662 | ): Unit 663 | external fun ffi_matrix_sdk_common_rust_future_free_u8(`handle`: Long, 664 | ): Unit 665 | external fun ffi_matrix_sdk_common_rust_future_complete_u8(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 666 | ): Byte 667 | external fun ffi_matrix_sdk_common_rust_future_poll_i8(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 668 | ): Unit 669 | external fun ffi_matrix_sdk_common_rust_future_cancel_i8(`handle`: Long, 670 | ): Unit 671 | external fun ffi_matrix_sdk_common_rust_future_free_i8(`handle`: Long, 672 | ): Unit 673 | external fun ffi_matrix_sdk_common_rust_future_complete_i8(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 674 | ): Byte 675 | external fun ffi_matrix_sdk_common_rust_future_poll_u16(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 676 | ): Unit 677 | external fun ffi_matrix_sdk_common_rust_future_cancel_u16(`handle`: Long, 678 | ): Unit 679 | external fun ffi_matrix_sdk_common_rust_future_free_u16(`handle`: Long, 680 | ): Unit 681 | external fun ffi_matrix_sdk_common_rust_future_complete_u16(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 682 | ): Short 683 | external fun ffi_matrix_sdk_common_rust_future_poll_i16(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 684 | ): Unit 685 | external fun ffi_matrix_sdk_common_rust_future_cancel_i16(`handle`: Long, 686 | ): Unit 687 | external fun ffi_matrix_sdk_common_rust_future_free_i16(`handle`: Long, 688 | ): Unit 689 | external fun ffi_matrix_sdk_common_rust_future_complete_i16(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 690 | ): Short 691 | external fun ffi_matrix_sdk_common_rust_future_poll_u32(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 692 | ): Unit 693 | external fun ffi_matrix_sdk_common_rust_future_cancel_u32(`handle`: Long, 694 | ): Unit 695 | external fun ffi_matrix_sdk_common_rust_future_free_u32(`handle`: Long, 696 | ): Unit 697 | external fun ffi_matrix_sdk_common_rust_future_complete_u32(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 698 | ): Int 699 | external fun ffi_matrix_sdk_common_rust_future_poll_i32(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 700 | ): Unit 701 | external fun ffi_matrix_sdk_common_rust_future_cancel_i32(`handle`: Long, 702 | ): Unit 703 | external fun ffi_matrix_sdk_common_rust_future_free_i32(`handle`: Long, 704 | ): Unit 705 | external fun ffi_matrix_sdk_common_rust_future_complete_i32(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 706 | ): Int 707 | external fun ffi_matrix_sdk_common_rust_future_poll_u64(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 708 | ): Unit 709 | external fun ffi_matrix_sdk_common_rust_future_cancel_u64(`handle`: Long, 710 | ): Unit 711 | external fun ffi_matrix_sdk_common_rust_future_free_u64(`handle`: Long, 712 | ): Unit 713 | external fun ffi_matrix_sdk_common_rust_future_complete_u64(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 714 | ): Long 715 | external fun ffi_matrix_sdk_common_rust_future_poll_i64(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 716 | ): Unit 717 | external fun ffi_matrix_sdk_common_rust_future_cancel_i64(`handle`: Long, 718 | ): Unit 719 | external fun ffi_matrix_sdk_common_rust_future_free_i64(`handle`: Long, 720 | ): Unit 721 | external fun ffi_matrix_sdk_common_rust_future_complete_i64(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 722 | ): Long 723 | external fun ffi_matrix_sdk_common_rust_future_poll_f32(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 724 | ): Unit 725 | external fun ffi_matrix_sdk_common_rust_future_cancel_f32(`handle`: Long, 726 | ): Unit 727 | external fun ffi_matrix_sdk_common_rust_future_free_f32(`handle`: Long, 728 | ): Unit 729 | external fun ffi_matrix_sdk_common_rust_future_complete_f32(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 730 | ): Float 731 | external fun ffi_matrix_sdk_common_rust_future_poll_f64(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 732 | ): Unit 733 | external fun ffi_matrix_sdk_common_rust_future_cancel_f64(`handle`: Long, 734 | ): Unit 735 | external fun ffi_matrix_sdk_common_rust_future_free_f64(`handle`: Long, 736 | ): Unit 737 | external fun ffi_matrix_sdk_common_rust_future_complete_f64(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 738 | ): Double 739 | external fun ffi_matrix_sdk_common_rust_future_poll_rust_buffer(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 740 | ): Unit 741 | external fun ffi_matrix_sdk_common_rust_future_cancel_rust_buffer(`handle`: Long, 742 | ): Unit 743 | external fun ffi_matrix_sdk_common_rust_future_free_rust_buffer(`handle`: Long, 744 | ): Unit 745 | external fun ffi_matrix_sdk_common_rust_future_complete_rust_buffer(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 746 | ): RustBuffer.ByValue 747 | external fun ffi_matrix_sdk_common_rust_future_poll_void(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 748 | ): Unit 749 | external fun ffi_matrix_sdk_common_rust_future_cancel_void(`handle`: Long, 750 | ): Unit 751 | external fun ffi_matrix_sdk_common_rust_future_free_void(`handle`: Long, 752 | ): Unit 753 | external fun ffi_matrix_sdk_common_rust_future_complete_void(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 754 | ): Unit 755 | 756 | 757 | } 758 | 759 | private fun uniffiCheckContractApiVersion(lib: IntegrityCheckingUniffiLib) { 760 | // Get the bindings contract version from our ComponentInterface 761 | val bindings_contract_version = 30 762 | // Get the scaffolding contract version by calling the into the dylib 763 | val scaffolding_contract_version = lib.ffi_matrix_sdk_common_uniffi_contract_version() 764 | if (bindings_contract_version != scaffolding_contract_version) { 765 | throw RuntimeException("UniFFI contract version mismatch: try cleaning and rebuilding your project") 766 | } 767 | } 768 | @Suppress("UNUSED_PARAMETER") 769 | private fun uniffiCheckApiChecksums(lib: IntegrityCheckingUniffiLib) { 770 | } 771 | 772 | /** 773 | * @suppress 774 | */ 775 | public fun uniffiEnsureInitialized() { 776 | IntegrityCheckingUniffiLib 777 | // UniffiLib() initialized as objects are used, but we still need to explicitly 778 | // reference it so initialization across crates works as expected. 779 | UniffiLib 780 | } 781 | 782 | // Async support 783 | 784 | // Public interface members begin here. 785 | 786 | 787 | // Interface implemented by anything that can contain an object reference. 788 | // 789 | // Such types expose a `destroy()` method that must be called to cleanly 790 | // dispose of the contained objects. Failure to call this method may result 791 | // in memory leaks. 792 | // 793 | // The easiest way to ensure this method is called is to use the `.use` 794 | // helper method to execute a block and destroy the object at the end. 795 | interface Disposable { 796 | fun destroy() 797 | companion object { 798 | fun destroy(vararg args: Any?) { 799 | for (arg in args) { 800 | when (arg) { 801 | is Disposable -> arg.destroy() 802 | is ArrayList<*> -> { 803 | for (idx in arg.indices) { 804 | val element = arg[idx] 805 | if (element is Disposable) { 806 | element.destroy() 807 | } 808 | } 809 | } 810 | is Map<*, *> -> { 811 | for (element in arg.values) { 812 | if (element is Disposable) { 813 | element.destroy() 814 | } 815 | } 816 | } 817 | is Iterable<*> -> { 818 | for (element in arg) { 819 | if (element is Disposable) { 820 | element.destroy() 821 | } 822 | } 823 | } 824 | } 825 | } 826 | } 827 | } 828 | } 829 | 830 | /** 831 | * @suppress 832 | */ 833 | inline fun T.use(block: (T) -> R) = 834 | try { 835 | block(this) 836 | } finally { 837 | try { 838 | // N.B. our implementation is on the nullable type `Disposable?`. 839 | this?.destroy() 840 | } catch (e: Throwable) { 841 | // swallow 842 | } 843 | } 844 | 845 | /** 846 | * Placeholder object used to signal that we're constructing an interface with a FFI handle. 847 | * 848 | * This is the first argument for interface constructors that input a raw handle. It exists is that 849 | * so we can avoid signature conflicts when an interface has a regular constructor than inputs a 850 | * Long. 851 | * 852 | * @suppress 853 | * */ 854 | object UniffiWithHandle 855 | 856 | /** 857 | * Used to instantiate an interface without an actual pointer, for fakes in tests, mostly. 858 | * 859 | * @suppress 860 | * */ 861 | object NoHandle 862 | 863 | /** 864 | * @suppress 865 | */ 866 | public object FfiConverterString: FfiConverter { 867 | // Note: we don't inherit from FfiConverterRustBuffer, because we use a 868 | // special encoding when lowering/lifting. We can use `RustBuffer.len` to 869 | // store our length and avoid writing it out to the buffer. 870 | override fun lift(value: RustBuffer.ByValue): String { 871 | try { 872 | val byteArr = ByteArray(value.len.toInt()) 873 | value.asByteBuffer()!!.get(byteArr) 874 | return byteArr.toString(Charsets.UTF_8) 875 | } finally { 876 | RustBuffer.free(value) 877 | } 878 | } 879 | 880 | override fun read(buf: ByteBuffer): String { 881 | val len = buf.getInt() 882 | val byteArr = ByteArray(len) 883 | buf.get(byteArr) 884 | return byteArr.toString(Charsets.UTF_8) 885 | } 886 | 887 | fun toUtf8(value: String): ByteBuffer { 888 | // Make sure we don't have invalid UTF-16, check for lone surrogates. 889 | return Charsets.UTF_8.newEncoder().run { 890 | onMalformedInput(CodingErrorAction.REPORT) 891 | encode(CharBuffer.wrap(value)) 892 | } 893 | } 894 | 895 | override fun lower(value: String): RustBuffer.ByValue { 896 | val byteBuf = toUtf8(value) 897 | // Ideally we'd pass these bytes to `ffi_bytebuffer_from_bytes`, but doing so would require us 898 | // to copy them into a JNA `Memory`. So we might as well directly copy them into a `RustBuffer`. 899 | val rbuf = RustBuffer.alloc(byteBuf.limit().toULong()) 900 | rbuf.asByteBuffer()!!.put(byteBuf) 901 | return rbuf 902 | } 903 | 904 | // We aren't sure exactly how many bytes our string will be once it's UTF-8 905 | // encoded. Allocate 3 bytes per UTF-16 code unit which will always be 906 | // enough. 907 | override fun allocationSize(value: String): ULong { 908 | val sizeForLength = 4UL 909 | val sizeForString = value.length.toULong() * 3UL 910 | return sizeForLength + sizeForString 911 | } 912 | 913 | override fun write(value: String, buf: ByteBuffer) { 914 | val byteBuf = toUtf8(value) 915 | buf.putInt(byteBuf.limit()) 916 | buf.put(byteBuf) 917 | } 918 | } 919 | 920 | 921 | 922 | /** 923 | * A machine-readable representation of the authenticity for a `ShieldState`. 924 | */ 925 | 926 | enum class ShieldStateCode { 927 | 928 | /** 929 | * Not enough information available to check the authenticity. 930 | */ 931 | AUTHENTICITY_NOT_GUARANTEED, 932 | /** 933 | * The sending device isn't yet known by the Client. 934 | */ 935 | UNKNOWN_DEVICE, 936 | /** 937 | * The sending device hasn't been verified by the sender. 938 | */ 939 | UNSIGNED_DEVICE, 940 | /** 941 | * The sender hasn't been verified by the Client's user. 942 | */ 943 | UNVERIFIED_IDENTITY, 944 | /** 945 | * An unencrypted event in an encrypted room. 946 | */ 947 | SENT_IN_CLEAR, 948 | /** 949 | * The sender was previously verified but changed their identity. 950 | */ 951 | VERIFICATION_VIOLATION, 952 | /** 953 | * The `sender` field on the event does not match the owner of the device 954 | * that established the Megolm session. 955 | */ 956 | MISMATCHED_SENDER; 957 | 958 | 959 | 960 | 961 | companion object 962 | } 963 | 964 | 965 | /** 966 | * @suppress 967 | */ 968 | public object FfiConverterTypeShieldStateCode: FfiConverterRustBuffer { 969 | override fun read(buf: ByteBuffer) = try { 970 | ShieldStateCode.values()[buf.getInt() - 1] 971 | } catch (e: IndexOutOfBoundsException) { 972 | throw RuntimeException("invalid enum value, something is very wrong!!", e) 973 | } 974 | 975 | override fun allocationSize(value: ShieldStateCode) = 4UL 976 | 977 | override fun write(value: ShieldStateCode, buf: ByteBuffer) { 978 | buf.putInt(value.ordinal + 1) 979 | } 980 | } 981 | 982 | 983 | 984 | -------------------------------------------------------------------------------- /sdk/sdk-android/src/main/kotlin/uniffi/matrix_sdk_ui/matrix_sdk_ui.kt: -------------------------------------------------------------------------------- 1 | // This file was autogenerated by some hot garbage in the `uniffi` crate. 2 | // Trust me, you don't want to mess with it! 3 | 4 | @file:Suppress("NAME_SHADOWING") 5 | 6 | package uniffi.matrix_sdk_ui 7 | 8 | // Common helper code. 9 | // 10 | // Ideally this would live in a separate .kt file where it can be unittested etc 11 | // in isolation, and perhaps even published as a re-useable package. 12 | // 13 | // However, it's important that the details of how this helper code works (e.g. the 14 | // way that different builtin types are passed across the FFI) exactly match what's 15 | // expected by the Rust code on the other side of the interface. In practice right 16 | // now that means coming from the exact some version of `uniffi` that was used to 17 | // compile the Rust component. The easiest way to ensure this is to bundle the Kotlin 18 | // helpers directly inline like we're doing here. 19 | 20 | import com.sun.jna.Library 21 | import com.sun.jna.IntegerType 22 | import com.sun.jna.Native 23 | import com.sun.jna.Pointer 24 | import com.sun.jna.Structure 25 | import com.sun.jna.Callback 26 | import com.sun.jna.ptr.* 27 | import java.nio.ByteBuffer 28 | import java.nio.ByteOrder 29 | import java.nio.CharBuffer 30 | import java.nio.charset.CodingErrorAction 31 | import java.util.concurrent.atomic.AtomicLong 32 | import java.util.concurrent.ConcurrentHashMap 33 | 34 | // This is a helper for safely working with byte buffers returned from the Rust code. 35 | // A rust-owned buffer is represented by its capacity, its current length, and a 36 | // pointer to the underlying data. 37 | 38 | /** 39 | * @suppress 40 | */ 41 | @Structure.FieldOrder("capacity", "len", "data") 42 | open class RustBuffer : Structure() { 43 | // Note: `capacity` and `len` are actually `ULong` values, but JVM only supports signed values. 44 | // When dealing with these fields, make sure to call `toULong()`. 45 | @JvmField var capacity: Long = 0 46 | @JvmField var len: Long = 0 47 | @JvmField var data: Pointer? = null 48 | 49 | class ByValue: RustBuffer(), Structure.ByValue 50 | class ByReference: RustBuffer(), Structure.ByReference 51 | 52 | internal fun setValue(other: RustBuffer) { 53 | capacity = other.capacity 54 | len = other.len 55 | data = other.data 56 | } 57 | 58 | companion object { 59 | internal fun alloc(size: ULong = 0UL) = uniffiRustCall() { status -> 60 | // Note: need to convert the size to a `Long` value to make this work with JVM. 61 | UniffiLib.ffi_matrix_sdk_ui_rustbuffer_alloc(size.toLong(), status) 62 | }.also { 63 | if(it.data == null) { 64 | throw RuntimeException("RustBuffer.alloc() returned null data pointer (size=${size})") 65 | } 66 | } 67 | 68 | internal fun create(capacity: ULong, len: ULong, data: Pointer?): RustBuffer.ByValue { 69 | var buf = RustBuffer.ByValue() 70 | buf.capacity = capacity.toLong() 71 | buf.len = len.toLong() 72 | buf.data = data 73 | return buf 74 | } 75 | 76 | internal fun free(buf: RustBuffer.ByValue) = uniffiRustCall() { status -> 77 | UniffiLib.ffi_matrix_sdk_ui_rustbuffer_free(buf, status) 78 | } 79 | } 80 | 81 | @Suppress("TooGenericExceptionThrown") 82 | fun asByteBuffer() = 83 | this.data?.getByteBuffer(0, this.len.toLong())?.also { 84 | it.order(ByteOrder.BIG_ENDIAN) 85 | } 86 | } 87 | 88 | // This is a helper for safely passing byte references into the rust code. 89 | // It's not actually used at the moment, because there aren't many things that you 90 | // can take a direct pointer to in the JVM, and if we're going to copy something 91 | // then we might as well copy it into a `RustBuffer`. But it's here for API 92 | // completeness. 93 | 94 | @Structure.FieldOrder("len", "data") 95 | internal open class ForeignBytes : Structure() { 96 | @JvmField var len: Int = 0 97 | @JvmField var data: Pointer? = null 98 | 99 | class ByValue : ForeignBytes(), Structure.ByValue 100 | } 101 | /** 102 | * The FfiConverter interface handles converter types to and from the FFI 103 | * 104 | * All implementing objects should be public to support external types. When a 105 | * type is external we need to import it's FfiConverter. 106 | * 107 | * @suppress 108 | */ 109 | public interface FfiConverter { 110 | // Convert an FFI type to a Kotlin type 111 | fun lift(value: FfiType): KotlinType 112 | 113 | // Convert an Kotlin type to an FFI type 114 | fun lower(value: KotlinType): FfiType 115 | 116 | // Read a Kotlin type from a `ByteBuffer` 117 | fun read(buf: ByteBuffer): KotlinType 118 | 119 | // Calculate bytes to allocate when creating a `RustBuffer` 120 | // 121 | // This must return at least as many bytes as the write() function will 122 | // write. It can return more bytes than needed, for example when writing 123 | // Strings we can't know the exact bytes needed until we the UTF-8 124 | // encoding, so we pessimistically allocate the largest size possible (3 125 | // bytes per codepoint). Allocating extra bytes is not really a big deal 126 | // because the `RustBuffer` is short-lived. 127 | fun allocationSize(value: KotlinType): ULong 128 | 129 | // Write a Kotlin type to a `ByteBuffer` 130 | fun write(value: KotlinType, buf: ByteBuffer) 131 | 132 | // Lower a value into a `RustBuffer` 133 | // 134 | // This method lowers a value into a `RustBuffer` rather than the normal 135 | // FfiType. It's used by the callback interface code. Callback interface 136 | // returns are always serialized into a `RustBuffer` regardless of their 137 | // normal FFI type. 138 | fun lowerIntoRustBuffer(value: KotlinType): RustBuffer.ByValue { 139 | val rbuf = RustBuffer.alloc(allocationSize(value)) 140 | try { 141 | val bbuf = rbuf.data!!.getByteBuffer(0, rbuf.capacity).also { 142 | it.order(ByteOrder.BIG_ENDIAN) 143 | } 144 | write(value, bbuf) 145 | rbuf.writeField("len", bbuf.position().toLong()) 146 | return rbuf 147 | } catch (e: Throwable) { 148 | RustBuffer.free(rbuf) 149 | throw e 150 | } 151 | } 152 | 153 | // Lift a value from a `RustBuffer`. 154 | // 155 | // This here mostly because of the symmetry with `lowerIntoRustBuffer()`. 156 | // It's currently only used by the `FfiConverterRustBuffer` class below. 157 | fun liftFromRustBuffer(rbuf: RustBuffer.ByValue): KotlinType { 158 | val byteBuf = rbuf.asByteBuffer()!! 159 | try { 160 | val item = read(byteBuf) 161 | if (byteBuf.hasRemaining()) { 162 | throw RuntimeException("junk remaining in buffer after lifting, something is very wrong!!") 163 | } 164 | return item 165 | } finally { 166 | RustBuffer.free(rbuf) 167 | } 168 | } 169 | } 170 | 171 | /** 172 | * FfiConverter that uses `RustBuffer` as the FfiType 173 | * 174 | * @suppress 175 | */ 176 | public interface FfiConverterRustBuffer: FfiConverter { 177 | override fun lift(value: RustBuffer.ByValue) = liftFromRustBuffer(value) 178 | override fun lower(value: KotlinType) = lowerIntoRustBuffer(value) 179 | } 180 | // A handful of classes and functions to support the generated data structures. 181 | // This would be a good candidate for isolating in its own ffi-support lib. 182 | 183 | internal const val UNIFFI_CALL_SUCCESS = 0.toByte() 184 | internal const val UNIFFI_CALL_ERROR = 1.toByte() 185 | internal const val UNIFFI_CALL_UNEXPECTED_ERROR = 2.toByte() 186 | 187 | @Structure.FieldOrder("code", "error_buf") 188 | internal open class UniffiRustCallStatus : Structure() { 189 | @JvmField var code: Byte = 0 190 | @JvmField var error_buf: RustBuffer.ByValue = RustBuffer.ByValue() 191 | 192 | class ByValue: UniffiRustCallStatus(), Structure.ByValue 193 | 194 | fun isSuccess(): Boolean { 195 | return code == UNIFFI_CALL_SUCCESS 196 | } 197 | 198 | fun isError(): Boolean { 199 | return code == UNIFFI_CALL_ERROR 200 | } 201 | 202 | fun isPanic(): Boolean { 203 | return code == UNIFFI_CALL_UNEXPECTED_ERROR 204 | } 205 | 206 | companion object { 207 | fun create(code: Byte, errorBuf: RustBuffer.ByValue): UniffiRustCallStatus.ByValue { 208 | val callStatus = UniffiRustCallStatus.ByValue() 209 | callStatus.code = code 210 | callStatus.error_buf = errorBuf 211 | return callStatus 212 | } 213 | } 214 | } 215 | 216 | class InternalException(message: String) : kotlin.Exception(message) 217 | 218 | /** 219 | * Each top-level error class has a companion object that can lift the error from the call status's rust buffer 220 | * 221 | * @suppress 222 | */ 223 | interface UniffiRustCallStatusErrorHandler { 224 | fun lift(error_buf: RustBuffer.ByValue): E; 225 | } 226 | 227 | // Helpers for calling Rust 228 | // In practice we usually need to be synchronized to call this safely, so it doesn't 229 | // synchronize itself 230 | 231 | // Call a rust function that returns a Result<>. Pass in the Error class companion that corresponds to the Err 232 | private inline fun uniffiRustCallWithError(errorHandler: UniffiRustCallStatusErrorHandler, callback: (UniffiRustCallStatus) -> U): U { 233 | var status = UniffiRustCallStatus() 234 | val return_value = callback(status) 235 | uniffiCheckCallStatus(errorHandler, status) 236 | return return_value 237 | } 238 | 239 | // Check UniffiRustCallStatus and throw an error if the call wasn't successful 240 | private fun uniffiCheckCallStatus(errorHandler: UniffiRustCallStatusErrorHandler, status: UniffiRustCallStatus) { 241 | if (status.isSuccess()) { 242 | return 243 | } else if (status.isError()) { 244 | throw errorHandler.lift(status.error_buf) 245 | } else if (status.isPanic()) { 246 | // when the rust code sees a panic, it tries to construct a rustbuffer 247 | // with the message. but if that code panics, then it just sends back 248 | // an empty buffer. 249 | if (status.error_buf.len > 0) { 250 | throw InternalException(FfiConverterString.lift(status.error_buf)) 251 | } else { 252 | throw InternalException("Rust panic") 253 | } 254 | } else { 255 | throw InternalException("Unknown rust call status: $status.code") 256 | } 257 | } 258 | 259 | /** 260 | * UniffiRustCallStatusErrorHandler implementation for times when we don't expect a CALL_ERROR 261 | * 262 | * @suppress 263 | */ 264 | object UniffiNullRustCallStatusErrorHandler: UniffiRustCallStatusErrorHandler { 265 | override fun lift(error_buf: RustBuffer.ByValue): InternalException { 266 | RustBuffer.free(error_buf) 267 | return InternalException("Unexpected CALL_ERROR") 268 | } 269 | } 270 | 271 | // Call a rust function that returns a plain value 272 | private inline fun uniffiRustCall(callback: (UniffiRustCallStatus) -> U): U { 273 | return uniffiRustCallWithError(UniffiNullRustCallStatusErrorHandler, callback) 274 | } 275 | 276 | internal inline fun uniffiTraitInterfaceCall( 277 | callStatus: UniffiRustCallStatus, 278 | makeCall: () -> T, 279 | writeReturn: (T) -> Unit, 280 | ) { 281 | try { 282 | writeReturn(makeCall()) 283 | } catch(e: kotlin.Exception) { 284 | val err = try { e.stackTraceToString() } catch(_: Throwable) { "" } 285 | callStatus.code = UNIFFI_CALL_UNEXPECTED_ERROR 286 | callStatus.error_buf = FfiConverterString.lower(err) 287 | } 288 | } 289 | 290 | internal inline fun uniffiTraitInterfaceCallWithError( 291 | callStatus: UniffiRustCallStatus, 292 | makeCall: () -> T, 293 | writeReturn: (T) -> Unit, 294 | lowerError: (E) -> RustBuffer.ByValue 295 | ) { 296 | try { 297 | writeReturn(makeCall()) 298 | } catch(e: kotlin.Exception) { 299 | if (e is E) { 300 | callStatus.code = UNIFFI_CALL_ERROR 301 | callStatus.error_buf = lowerError(e) 302 | } else { 303 | val err = try { e.stackTraceToString() } catch(_: Throwable) { "" } 304 | callStatus.code = UNIFFI_CALL_UNEXPECTED_ERROR 305 | callStatus.error_buf = FfiConverterString.lower(err) 306 | } 307 | } 308 | } 309 | // Initial value and increment amount for handles. 310 | // These ensure that Kotlin-generated handles always have the lowest bit set 311 | private const val UNIFFI_HANDLEMAP_INITIAL = 1.toLong() 312 | private const val UNIFFI_HANDLEMAP_DELTA = 2.toLong() 313 | 314 | // Map handles to objects 315 | // 316 | // This is used pass an opaque 64-bit handle representing a foreign object to the Rust code. 317 | internal class UniffiHandleMap { 318 | private val map = ConcurrentHashMap() 319 | // Start 320 | private val counter = java.util.concurrent.atomic.AtomicLong(UNIFFI_HANDLEMAP_INITIAL) 321 | 322 | val size: Int 323 | get() = map.size 324 | 325 | // Insert a new object into the handle map and get a handle for it 326 | fun insert(obj: T): Long { 327 | val handle = counter.getAndAdd(UNIFFI_HANDLEMAP_DELTA) 328 | map.put(handle, obj) 329 | return handle 330 | } 331 | 332 | // Clone a handle, creating a new one 333 | fun clone(handle: Long): Long { 334 | val obj = map.get(handle) ?: throw InternalException("UniffiHandleMap.clone: Invalid handle") 335 | return insert(obj) 336 | } 337 | 338 | // Get an object from the handle map 339 | fun get(handle: Long): T { 340 | return map.get(handle) ?: throw InternalException("UniffiHandleMap.get: Invalid handle") 341 | } 342 | 343 | // Remove an entry from the handlemap and get the Kotlin object back 344 | fun remove(handle: Long): T { 345 | return map.remove(handle) ?: throw InternalException("UniffiHandleMap: Invalid handle") 346 | } 347 | } 348 | 349 | // Contains loading, initialization code, 350 | // and the FFI Function declarations in a com.sun.jna.Library. 351 | @Synchronized 352 | private fun findLibraryName(componentName: String): String { 353 | val libOverride = System.getProperty("uniffi.component.$componentName.libraryOverride") 354 | if (libOverride != null) { 355 | return libOverride 356 | } 357 | return "matrix_sdk_ffi" 358 | } 359 | 360 | // Define FFI callback types 361 | internal interface UniffiRustFutureContinuationCallback : com.sun.jna.Callback { 362 | fun callback(`data`: Long,`pollResult`: Byte,) 363 | } 364 | internal interface UniffiForeignFutureDroppedCallback : com.sun.jna.Callback { 365 | fun callback(`handle`: Long,) 366 | } 367 | internal interface UniffiCallbackInterfaceFree : com.sun.jna.Callback { 368 | fun callback(`handle`: Long,) 369 | } 370 | internal interface UniffiCallbackInterfaceClone : com.sun.jna.Callback { 371 | fun callback(`handle`: Long,) 372 | : Long 373 | } 374 | @Structure.FieldOrder("handle", "free") 375 | internal open class UniffiForeignFutureDroppedCallbackStruct( 376 | @JvmField internal var `handle`: Long = 0.toLong(), 377 | @JvmField internal var `free`: UniffiForeignFutureDroppedCallback? = null, 378 | ) : Structure() { 379 | class UniffiByValue( 380 | `handle`: Long = 0.toLong(), 381 | `free`: UniffiForeignFutureDroppedCallback? = null, 382 | ): UniffiForeignFutureDroppedCallbackStruct(`handle`,`free`,), Structure.ByValue 383 | 384 | internal fun uniffiSetValue(other: UniffiForeignFutureDroppedCallbackStruct) { 385 | `handle` = other.`handle` 386 | `free` = other.`free` 387 | } 388 | 389 | } 390 | @Structure.FieldOrder("returnValue", "callStatus") 391 | internal open class UniffiForeignFutureResultU8( 392 | @JvmField internal var `returnValue`: Byte = 0.toByte(), 393 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 394 | ) : Structure() { 395 | class UniffiByValue( 396 | `returnValue`: Byte = 0.toByte(), 397 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 398 | ): UniffiForeignFutureResultU8(`returnValue`,`callStatus`,), Structure.ByValue 399 | 400 | internal fun uniffiSetValue(other: UniffiForeignFutureResultU8) { 401 | `returnValue` = other.`returnValue` 402 | `callStatus` = other.`callStatus` 403 | } 404 | 405 | } 406 | internal interface UniffiForeignFutureCompleteU8 : com.sun.jna.Callback { 407 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultU8.UniffiByValue,) 408 | } 409 | @Structure.FieldOrder("returnValue", "callStatus") 410 | internal open class UniffiForeignFutureResultI8( 411 | @JvmField internal var `returnValue`: Byte = 0.toByte(), 412 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 413 | ) : Structure() { 414 | class UniffiByValue( 415 | `returnValue`: Byte = 0.toByte(), 416 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 417 | ): UniffiForeignFutureResultI8(`returnValue`,`callStatus`,), Structure.ByValue 418 | 419 | internal fun uniffiSetValue(other: UniffiForeignFutureResultI8) { 420 | `returnValue` = other.`returnValue` 421 | `callStatus` = other.`callStatus` 422 | } 423 | 424 | } 425 | internal interface UniffiForeignFutureCompleteI8 : com.sun.jna.Callback { 426 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultI8.UniffiByValue,) 427 | } 428 | @Structure.FieldOrder("returnValue", "callStatus") 429 | internal open class UniffiForeignFutureResultU16( 430 | @JvmField internal var `returnValue`: Short = 0.toShort(), 431 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 432 | ) : Structure() { 433 | class UniffiByValue( 434 | `returnValue`: Short = 0.toShort(), 435 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 436 | ): UniffiForeignFutureResultU16(`returnValue`,`callStatus`,), Structure.ByValue 437 | 438 | internal fun uniffiSetValue(other: UniffiForeignFutureResultU16) { 439 | `returnValue` = other.`returnValue` 440 | `callStatus` = other.`callStatus` 441 | } 442 | 443 | } 444 | internal interface UniffiForeignFutureCompleteU16 : com.sun.jna.Callback { 445 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultU16.UniffiByValue,) 446 | } 447 | @Structure.FieldOrder("returnValue", "callStatus") 448 | internal open class UniffiForeignFutureResultI16( 449 | @JvmField internal var `returnValue`: Short = 0.toShort(), 450 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 451 | ) : Structure() { 452 | class UniffiByValue( 453 | `returnValue`: Short = 0.toShort(), 454 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 455 | ): UniffiForeignFutureResultI16(`returnValue`,`callStatus`,), Structure.ByValue 456 | 457 | internal fun uniffiSetValue(other: UniffiForeignFutureResultI16) { 458 | `returnValue` = other.`returnValue` 459 | `callStatus` = other.`callStatus` 460 | } 461 | 462 | } 463 | internal interface UniffiForeignFutureCompleteI16 : com.sun.jna.Callback { 464 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultI16.UniffiByValue,) 465 | } 466 | @Structure.FieldOrder("returnValue", "callStatus") 467 | internal open class UniffiForeignFutureResultU32( 468 | @JvmField internal var `returnValue`: Int = 0, 469 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 470 | ) : Structure() { 471 | class UniffiByValue( 472 | `returnValue`: Int = 0, 473 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 474 | ): UniffiForeignFutureResultU32(`returnValue`,`callStatus`,), Structure.ByValue 475 | 476 | internal fun uniffiSetValue(other: UniffiForeignFutureResultU32) { 477 | `returnValue` = other.`returnValue` 478 | `callStatus` = other.`callStatus` 479 | } 480 | 481 | } 482 | internal interface UniffiForeignFutureCompleteU32 : com.sun.jna.Callback { 483 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultU32.UniffiByValue,) 484 | } 485 | @Structure.FieldOrder("returnValue", "callStatus") 486 | internal open class UniffiForeignFutureResultI32( 487 | @JvmField internal var `returnValue`: Int = 0, 488 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 489 | ) : Structure() { 490 | class UniffiByValue( 491 | `returnValue`: Int = 0, 492 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 493 | ): UniffiForeignFutureResultI32(`returnValue`,`callStatus`,), Structure.ByValue 494 | 495 | internal fun uniffiSetValue(other: UniffiForeignFutureResultI32) { 496 | `returnValue` = other.`returnValue` 497 | `callStatus` = other.`callStatus` 498 | } 499 | 500 | } 501 | internal interface UniffiForeignFutureCompleteI32 : com.sun.jna.Callback { 502 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultI32.UniffiByValue,) 503 | } 504 | @Structure.FieldOrder("returnValue", "callStatus") 505 | internal open class UniffiForeignFutureResultU64( 506 | @JvmField internal var `returnValue`: Long = 0.toLong(), 507 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 508 | ) : Structure() { 509 | class UniffiByValue( 510 | `returnValue`: Long = 0.toLong(), 511 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 512 | ): UniffiForeignFutureResultU64(`returnValue`,`callStatus`,), Structure.ByValue 513 | 514 | internal fun uniffiSetValue(other: UniffiForeignFutureResultU64) { 515 | `returnValue` = other.`returnValue` 516 | `callStatus` = other.`callStatus` 517 | } 518 | 519 | } 520 | internal interface UniffiForeignFutureCompleteU64 : com.sun.jna.Callback { 521 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultU64.UniffiByValue,) 522 | } 523 | @Structure.FieldOrder("returnValue", "callStatus") 524 | internal open class UniffiForeignFutureResultI64( 525 | @JvmField internal var `returnValue`: Long = 0.toLong(), 526 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 527 | ) : Structure() { 528 | class UniffiByValue( 529 | `returnValue`: Long = 0.toLong(), 530 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 531 | ): UniffiForeignFutureResultI64(`returnValue`,`callStatus`,), Structure.ByValue 532 | 533 | internal fun uniffiSetValue(other: UniffiForeignFutureResultI64) { 534 | `returnValue` = other.`returnValue` 535 | `callStatus` = other.`callStatus` 536 | } 537 | 538 | } 539 | internal interface UniffiForeignFutureCompleteI64 : com.sun.jna.Callback { 540 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultI64.UniffiByValue,) 541 | } 542 | @Structure.FieldOrder("returnValue", "callStatus") 543 | internal open class UniffiForeignFutureResultF32( 544 | @JvmField internal var `returnValue`: Float = 0.0f, 545 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 546 | ) : Structure() { 547 | class UniffiByValue( 548 | `returnValue`: Float = 0.0f, 549 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 550 | ): UniffiForeignFutureResultF32(`returnValue`,`callStatus`,), Structure.ByValue 551 | 552 | internal fun uniffiSetValue(other: UniffiForeignFutureResultF32) { 553 | `returnValue` = other.`returnValue` 554 | `callStatus` = other.`callStatus` 555 | } 556 | 557 | } 558 | internal interface UniffiForeignFutureCompleteF32 : com.sun.jna.Callback { 559 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultF32.UniffiByValue,) 560 | } 561 | @Structure.FieldOrder("returnValue", "callStatus") 562 | internal open class UniffiForeignFutureResultF64( 563 | @JvmField internal var `returnValue`: Double = 0.0, 564 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 565 | ) : Structure() { 566 | class UniffiByValue( 567 | `returnValue`: Double = 0.0, 568 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 569 | ): UniffiForeignFutureResultF64(`returnValue`,`callStatus`,), Structure.ByValue 570 | 571 | internal fun uniffiSetValue(other: UniffiForeignFutureResultF64) { 572 | `returnValue` = other.`returnValue` 573 | `callStatus` = other.`callStatus` 574 | } 575 | 576 | } 577 | internal interface UniffiForeignFutureCompleteF64 : com.sun.jna.Callback { 578 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultF64.UniffiByValue,) 579 | } 580 | @Structure.FieldOrder("returnValue", "callStatus") 581 | internal open class UniffiForeignFutureResultRustBuffer( 582 | @JvmField internal var `returnValue`: RustBuffer.ByValue = RustBuffer.ByValue(), 583 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 584 | ) : Structure() { 585 | class UniffiByValue( 586 | `returnValue`: RustBuffer.ByValue = RustBuffer.ByValue(), 587 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 588 | ): UniffiForeignFutureResultRustBuffer(`returnValue`,`callStatus`,), Structure.ByValue 589 | 590 | internal fun uniffiSetValue(other: UniffiForeignFutureResultRustBuffer) { 591 | `returnValue` = other.`returnValue` 592 | `callStatus` = other.`callStatus` 593 | } 594 | 595 | } 596 | internal interface UniffiForeignFutureCompleteRustBuffer : com.sun.jna.Callback { 597 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultRustBuffer.UniffiByValue,) 598 | } 599 | @Structure.FieldOrder("callStatus") 600 | internal open class UniffiForeignFutureResultVoid( 601 | @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 602 | ) : Structure() { 603 | class UniffiByValue( 604 | `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), 605 | ): UniffiForeignFutureResultVoid(`callStatus`,), Structure.ByValue 606 | 607 | internal fun uniffiSetValue(other: UniffiForeignFutureResultVoid) { 608 | `callStatus` = other.`callStatus` 609 | } 610 | 611 | } 612 | internal interface UniffiForeignFutureCompleteVoid : com.sun.jna.Callback { 613 | fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultVoid.UniffiByValue,) 614 | } 615 | 616 | // A JNA Library to expose the extern-C FFI definitions. 617 | // This is an implementation detail which will be called internally by the public API. 618 | 619 | // For large crates we prevent `MethodTooLargeException` (see #2340) 620 | // N.B. the name of the extension is very misleading, since it is 621 | // rather `InterfaceTooLargeException`, caused by too many methods 622 | // in the interface for large crates. 623 | // 624 | // By splitting the otherwise huge interface into two parts 625 | // * UniffiLib (this) 626 | // * IntegrityCheckingUniffiLib 627 | // And all checksum methods are put into `IntegrityCheckingUniffiLib` 628 | // we allow for ~2x as many methods in the UniffiLib interface. 629 | // 630 | // Note: above all written when we used JNA's `loadIndirect` etc. 631 | // We now use JNA's "direct mapping" - unclear if same considerations apply exactly. 632 | internal object IntegrityCheckingUniffiLib { 633 | init { 634 | Native.register(IntegrityCheckingUniffiLib::class.java, findLibraryName(componentName = "matrix_sdk_ui")) 635 | uniffiCheckContractApiVersion(this) 636 | uniffiCheckApiChecksums(this) 637 | } 638 | external fun ffi_matrix_sdk_ui_uniffi_contract_version( 639 | ): Int 640 | 641 | 642 | } 643 | 644 | internal object UniffiLib { 645 | 646 | 647 | init { 648 | Native.register(UniffiLib::class.java, findLibraryName(componentName = "matrix_sdk_ui")) 649 | 650 | } 651 | external fun ffi_matrix_sdk_ui_rustbuffer_alloc(`size`: Long,uniffi_out_err: UniffiRustCallStatus, 652 | ): RustBuffer.ByValue 653 | external fun ffi_matrix_sdk_ui_rustbuffer_from_bytes(`bytes`: ForeignBytes.ByValue,uniffi_out_err: UniffiRustCallStatus, 654 | ): RustBuffer.ByValue 655 | external fun ffi_matrix_sdk_ui_rustbuffer_free(`buf`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, 656 | ): Unit 657 | external fun ffi_matrix_sdk_ui_rustbuffer_reserve(`buf`: RustBuffer.ByValue,`additional`: Long,uniffi_out_err: UniffiRustCallStatus, 658 | ): RustBuffer.ByValue 659 | external fun ffi_matrix_sdk_ui_rust_future_poll_u8(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 660 | ): Unit 661 | external fun ffi_matrix_sdk_ui_rust_future_cancel_u8(`handle`: Long, 662 | ): Unit 663 | external fun ffi_matrix_sdk_ui_rust_future_free_u8(`handle`: Long, 664 | ): Unit 665 | external fun ffi_matrix_sdk_ui_rust_future_complete_u8(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 666 | ): Byte 667 | external fun ffi_matrix_sdk_ui_rust_future_poll_i8(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 668 | ): Unit 669 | external fun ffi_matrix_sdk_ui_rust_future_cancel_i8(`handle`: Long, 670 | ): Unit 671 | external fun ffi_matrix_sdk_ui_rust_future_free_i8(`handle`: Long, 672 | ): Unit 673 | external fun ffi_matrix_sdk_ui_rust_future_complete_i8(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 674 | ): Byte 675 | external fun ffi_matrix_sdk_ui_rust_future_poll_u16(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 676 | ): Unit 677 | external fun ffi_matrix_sdk_ui_rust_future_cancel_u16(`handle`: Long, 678 | ): Unit 679 | external fun ffi_matrix_sdk_ui_rust_future_free_u16(`handle`: Long, 680 | ): Unit 681 | external fun ffi_matrix_sdk_ui_rust_future_complete_u16(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 682 | ): Short 683 | external fun ffi_matrix_sdk_ui_rust_future_poll_i16(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 684 | ): Unit 685 | external fun ffi_matrix_sdk_ui_rust_future_cancel_i16(`handle`: Long, 686 | ): Unit 687 | external fun ffi_matrix_sdk_ui_rust_future_free_i16(`handle`: Long, 688 | ): Unit 689 | external fun ffi_matrix_sdk_ui_rust_future_complete_i16(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 690 | ): Short 691 | external fun ffi_matrix_sdk_ui_rust_future_poll_u32(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 692 | ): Unit 693 | external fun ffi_matrix_sdk_ui_rust_future_cancel_u32(`handle`: Long, 694 | ): Unit 695 | external fun ffi_matrix_sdk_ui_rust_future_free_u32(`handle`: Long, 696 | ): Unit 697 | external fun ffi_matrix_sdk_ui_rust_future_complete_u32(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 698 | ): Int 699 | external fun ffi_matrix_sdk_ui_rust_future_poll_i32(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 700 | ): Unit 701 | external fun ffi_matrix_sdk_ui_rust_future_cancel_i32(`handle`: Long, 702 | ): Unit 703 | external fun ffi_matrix_sdk_ui_rust_future_free_i32(`handle`: Long, 704 | ): Unit 705 | external fun ffi_matrix_sdk_ui_rust_future_complete_i32(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 706 | ): Int 707 | external fun ffi_matrix_sdk_ui_rust_future_poll_u64(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 708 | ): Unit 709 | external fun ffi_matrix_sdk_ui_rust_future_cancel_u64(`handle`: Long, 710 | ): Unit 711 | external fun ffi_matrix_sdk_ui_rust_future_free_u64(`handle`: Long, 712 | ): Unit 713 | external fun ffi_matrix_sdk_ui_rust_future_complete_u64(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 714 | ): Long 715 | external fun ffi_matrix_sdk_ui_rust_future_poll_i64(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 716 | ): Unit 717 | external fun ffi_matrix_sdk_ui_rust_future_cancel_i64(`handle`: Long, 718 | ): Unit 719 | external fun ffi_matrix_sdk_ui_rust_future_free_i64(`handle`: Long, 720 | ): Unit 721 | external fun ffi_matrix_sdk_ui_rust_future_complete_i64(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 722 | ): Long 723 | external fun ffi_matrix_sdk_ui_rust_future_poll_f32(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 724 | ): Unit 725 | external fun ffi_matrix_sdk_ui_rust_future_cancel_f32(`handle`: Long, 726 | ): Unit 727 | external fun ffi_matrix_sdk_ui_rust_future_free_f32(`handle`: Long, 728 | ): Unit 729 | external fun ffi_matrix_sdk_ui_rust_future_complete_f32(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 730 | ): Float 731 | external fun ffi_matrix_sdk_ui_rust_future_poll_f64(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 732 | ): Unit 733 | external fun ffi_matrix_sdk_ui_rust_future_cancel_f64(`handle`: Long, 734 | ): Unit 735 | external fun ffi_matrix_sdk_ui_rust_future_free_f64(`handle`: Long, 736 | ): Unit 737 | external fun ffi_matrix_sdk_ui_rust_future_complete_f64(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 738 | ): Double 739 | external fun ffi_matrix_sdk_ui_rust_future_poll_rust_buffer(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 740 | ): Unit 741 | external fun ffi_matrix_sdk_ui_rust_future_cancel_rust_buffer(`handle`: Long, 742 | ): Unit 743 | external fun ffi_matrix_sdk_ui_rust_future_free_rust_buffer(`handle`: Long, 744 | ): Unit 745 | external fun ffi_matrix_sdk_ui_rust_future_complete_rust_buffer(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 746 | ): RustBuffer.ByValue 747 | external fun ffi_matrix_sdk_ui_rust_future_poll_void(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, 748 | ): Unit 749 | external fun ffi_matrix_sdk_ui_rust_future_cancel_void(`handle`: Long, 750 | ): Unit 751 | external fun ffi_matrix_sdk_ui_rust_future_free_void(`handle`: Long, 752 | ): Unit 753 | external fun ffi_matrix_sdk_ui_rust_future_complete_void(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, 754 | ): Unit 755 | 756 | 757 | } 758 | 759 | private fun uniffiCheckContractApiVersion(lib: IntegrityCheckingUniffiLib) { 760 | // Get the bindings contract version from our ComponentInterface 761 | val bindings_contract_version = 30 762 | // Get the scaffolding contract version by calling the into the dylib 763 | val scaffolding_contract_version = lib.ffi_matrix_sdk_ui_uniffi_contract_version() 764 | if (bindings_contract_version != scaffolding_contract_version) { 765 | throw RuntimeException("UniFFI contract version mismatch: try cleaning and rebuilding your project") 766 | } 767 | } 768 | @Suppress("UNUSED_PARAMETER") 769 | private fun uniffiCheckApiChecksums(lib: IntegrityCheckingUniffiLib) { 770 | } 771 | 772 | /** 773 | * @suppress 774 | */ 775 | public fun uniffiEnsureInitialized() { 776 | IntegrityCheckingUniffiLib 777 | // UniffiLib() initialized as objects are used, but we still need to explicitly 778 | // reference it so initialization across crates works as expected. 779 | UniffiLib 780 | } 781 | 782 | // Async support 783 | 784 | // Public interface members begin here. 785 | 786 | 787 | // Interface implemented by anything that can contain an object reference. 788 | // 789 | // Such types expose a `destroy()` method that must be called to cleanly 790 | // dispose of the contained objects. Failure to call this method may result 791 | // in memory leaks. 792 | // 793 | // The easiest way to ensure this method is called is to use the `.use` 794 | // helper method to execute a block and destroy the object at the end. 795 | interface Disposable { 796 | fun destroy() 797 | companion object { 798 | fun destroy(vararg args: Any?) { 799 | for (arg in args) { 800 | when (arg) { 801 | is Disposable -> arg.destroy() 802 | is ArrayList<*> -> { 803 | for (idx in arg.indices) { 804 | val element = arg[idx] 805 | if (element is Disposable) { 806 | element.destroy() 807 | } 808 | } 809 | } 810 | is Map<*, *> -> { 811 | for (element in arg.values) { 812 | if (element is Disposable) { 813 | element.destroy() 814 | } 815 | } 816 | } 817 | is Iterable<*> -> { 818 | for (element in arg) { 819 | if (element is Disposable) { 820 | element.destroy() 821 | } 822 | } 823 | } 824 | } 825 | } 826 | } 827 | } 828 | } 829 | 830 | /** 831 | * @suppress 832 | */ 833 | inline fun T.use(block: (T) -> R) = 834 | try { 835 | block(this) 836 | } finally { 837 | try { 838 | // N.B. our implementation is on the nullable type `Disposable?`. 839 | this?.destroy() 840 | } catch (e: Throwable) { 841 | // swallow 842 | } 843 | } 844 | 845 | /** 846 | * Placeholder object used to signal that we're constructing an interface with a FFI handle. 847 | * 848 | * This is the first argument for interface constructors that input a raw handle. It exists is that 849 | * so we can avoid signature conflicts when an interface has a regular constructor than inputs a 850 | * Long. 851 | * 852 | * @suppress 853 | * */ 854 | object UniffiWithHandle 855 | 856 | /** 857 | * Used to instantiate an interface without an actual pointer, for fakes in tests, mostly. 858 | * 859 | * @suppress 860 | * */ 861 | object NoHandle 862 | 863 | /** 864 | * @suppress 865 | */ 866 | public object FfiConverterBoolean: FfiConverter { 867 | override fun lift(value: Byte): Boolean { 868 | return value.toInt() != 0 869 | } 870 | 871 | override fun read(buf: ByteBuffer): Boolean { 872 | return lift(buf.get()) 873 | } 874 | 875 | override fun lower(value: Boolean): Byte { 876 | return if (value) 1.toByte() else 0.toByte() 877 | } 878 | 879 | override fun allocationSize(value: Boolean) = 1UL 880 | 881 | override fun write(value: Boolean, buf: ByteBuffer) { 882 | buf.put(lower(value)) 883 | } 884 | } 885 | 886 | /** 887 | * @suppress 888 | */ 889 | public object FfiConverterString: FfiConverter { 890 | // Note: we don't inherit from FfiConverterRustBuffer, because we use a 891 | // special encoding when lowering/lifting. We can use `RustBuffer.len` to 892 | // store our length and avoid writing it out to the buffer. 893 | override fun lift(value: RustBuffer.ByValue): String { 894 | try { 895 | val byteArr = ByteArray(value.len.toInt()) 896 | value.asByteBuffer()!!.get(byteArr) 897 | return byteArr.toString(Charsets.UTF_8) 898 | } finally { 899 | RustBuffer.free(value) 900 | } 901 | } 902 | 903 | override fun read(buf: ByteBuffer): String { 904 | val len = buf.getInt() 905 | val byteArr = ByteArray(len) 906 | buf.get(byteArr) 907 | return byteArr.toString(Charsets.UTF_8) 908 | } 909 | 910 | fun toUtf8(value: String): ByteBuffer { 911 | // Make sure we don't have invalid UTF-16, check for lone surrogates. 912 | return Charsets.UTF_8.newEncoder().run { 913 | onMalformedInput(CodingErrorAction.REPORT) 914 | encode(CharBuffer.wrap(value)) 915 | } 916 | } 917 | 918 | override fun lower(value: String): RustBuffer.ByValue { 919 | val byteBuf = toUtf8(value) 920 | // Ideally we'd pass these bytes to `ffi_bytebuffer_from_bytes`, but doing so would require us 921 | // to copy them into a JNA `Memory`. So we might as well directly copy them into a `RustBuffer`. 922 | val rbuf = RustBuffer.alloc(byteBuf.limit().toULong()) 923 | rbuf.asByteBuffer()!!.put(byteBuf) 924 | return rbuf 925 | } 926 | 927 | // We aren't sure exactly how many bytes our string will be once it's UTF-8 928 | // encoded. Allocate 3 bytes per UTF-16 code unit which will always be 929 | // enough. 930 | override fun allocationSize(value: String): ULong { 931 | val sizeForLength = 4UL 932 | val sizeForString = value.length.toULong() * 3UL 933 | return sizeForLength + sizeForString 934 | } 935 | 936 | override fun write(value: String, buf: ByteBuffer) { 937 | val byteBuf = toUtf8(value) 938 | buf.putInt(byteBuf.limit()) 939 | buf.put(byteBuf) 940 | } 941 | } 942 | 943 | 944 | 945 | /** 946 | * Where this event came. 947 | */ 948 | 949 | enum class EventItemOrigin { 950 | 951 | /** 952 | * The event was created locally. 953 | */ 954 | LOCAL, 955 | /** 956 | * The event came from a sync response. 957 | */ 958 | SYNC, 959 | /** 960 | * The event came from pagination. 961 | */ 962 | PAGINATION, 963 | /** 964 | * The event came from a cache. 965 | */ 966 | CACHE; 967 | 968 | 969 | 970 | 971 | companion object 972 | } 973 | 974 | 975 | /** 976 | * @suppress 977 | */ 978 | public object FfiConverterTypeEventItemOrigin: FfiConverterRustBuffer { 979 | override fun read(buf: ByteBuffer) = try { 980 | EventItemOrigin.values()[buf.getInt() - 1] 981 | } catch (e: IndexOutOfBoundsException) { 982 | throw RuntimeException("invalid enum value, something is very wrong!!", e) 983 | } 984 | 985 | override fun allocationSize(value: EventItemOrigin) = 4UL 986 | 987 | override fun write(value: EventItemOrigin, buf: ByteBuffer) { 988 | buf.putInt(value.ordinal + 1) 989 | } 990 | } 991 | 992 | 993 | 994 | 995 | 996 | /** 997 | * The type of change between the previous and current pinned events. 998 | */ 999 | 1000 | enum class RoomPinnedEventsChange { 1001 | 1002 | /** 1003 | * Only new event ids were added. 1004 | */ 1005 | ADDED, 1006 | /** 1007 | * Only event ids were removed. 1008 | */ 1009 | REMOVED, 1010 | /** 1011 | * Some change other than only adding or only removing ids happened. 1012 | */ 1013 | CHANGED; 1014 | 1015 | 1016 | 1017 | 1018 | companion object 1019 | } 1020 | 1021 | 1022 | /** 1023 | * @suppress 1024 | */ 1025 | public object FfiConverterTypeRoomPinnedEventsChange: FfiConverterRustBuffer { 1026 | override fun read(buf: ByteBuffer) = try { 1027 | RoomPinnedEventsChange.values()[buf.getInt() - 1] 1028 | } catch (e: IndexOutOfBoundsException) { 1029 | throw RuntimeException("invalid enum value, something is very wrong!!", e) 1030 | } 1031 | 1032 | override fun allocationSize(value: RoomPinnedEventsChange) = 4UL 1033 | 1034 | override fun write(value: RoomPinnedEventsChange, buf: ByteBuffer) { 1035 | buf.putInt(value.ordinal + 1) 1036 | } 1037 | } 1038 | 1039 | 1040 | 1041 | 1042 | 1043 | sealed class SpaceRoomListPaginationState { 1044 | 1045 | data class Idle( 1046 | val `endReached`: kotlin.Boolean) : SpaceRoomListPaginationState() 1047 | 1048 | { 1049 | 1050 | 1051 | companion object 1052 | } 1053 | 1054 | object Loading : SpaceRoomListPaginationState() 1055 | 1056 | 1057 | 1058 | 1059 | 1060 | 1061 | 1062 | 1063 | 1064 | companion object 1065 | } 1066 | 1067 | /** 1068 | * @suppress 1069 | */ 1070 | public object FfiConverterTypeSpaceRoomListPaginationState : FfiConverterRustBuffer{ 1071 | override fun read(buf: ByteBuffer): SpaceRoomListPaginationState { 1072 | return when(buf.getInt()) { 1073 | 1 -> SpaceRoomListPaginationState.Idle( 1074 | FfiConverterBoolean.read(buf), 1075 | ) 1076 | 2 -> SpaceRoomListPaginationState.Loading 1077 | else -> throw RuntimeException("invalid enum value, something is very wrong!!") 1078 | } 1079 | } 1080 | 1081 | override fun allocationSize(value: SpaceRoomListPaginationState) = when(value) { 1082 | is SpaceRoomListPaginationState.Idle -> { 1083 | // Add the size for the Int that specifies the variant plus the size needed for all fields 1084 | ( 1085 | 4UL 1086 | + FfiConverterBoolean.allocationSize(value.`endReached`) 1087 | ) 1088 | } 1089 | is SpaceRoomListPaginationState.Loading -> { 1090 | // Add the size for the Int that specifies the variant plus the size needed for all fields 1091 | ( 1092 | 4UL 1093 | ) 1094 | } 1095 | } 1096 | 1097 | override fun write(value: SpaceRoomListPaginationState, buf: ByteBuffer) { 1098 | when(value) { 1099 | is SpaceRoomListPaginationState.Idle -> { 1100 | buf.putInt(1) 1101 | FfiConverterBoolean.write(value.`endReached`, buf) 1102 | Unit 1103 | } 1104 | is SpaceRoomListPaginationState.Loading -> { 1105 | buf.putInt(2) 1106 | Unit 1107 | } 1108 | }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } 1109 | } 1110 | } 1111 | 1112 | 1113 | 1114 | 1115 | 1116 | /** 1117 | * The level of read receipt tracking for the timeline. 1118 | */ 1119 | 1120 | enum class TimelineReadReceiptTracking { 1121 | 1122 | /** 1123 | * Track read receipts for all events. 1124 | */ 1125 | ALL_EVENTS, 1126 | /** 1127 | * Track read receipts only for message-like events. 1128 | */ 1129 | MESSAGE_LIKE_EVENTS, 1130 | /** 1131 | * Disable read receipt tracking. 1132 | */ 1133 | DISABLED; 1134 | 1135 | 1136 | 1137 | 1138 | companion object 1139 | } 1140 | 1141 | 1142 | /** 1143 | * @suppress 1144 | */ 1145 | public object FfiConverterTypeTimelineReadReceiptTracking: FfiConverterRustBuffer { 1146 | override fun read(buf: ByteBuffer) = try { 1147 | TimelineReadReceiptTracking.values()[buf.getInt() - 1] 1148 | } catch (e: IndexOutOfBoundsException) { 1149 | throw RuntimeException("invalid enum value, something is very wrong!!", e) 1150 | } 1151 | 1152 | override fun allocationSize(value: TimelineReadReceiptTracking) = 4UL 1153 | 1154 | override fun write(value: TimelineReadReceiptTracking, buf: ByteBuffer) { 1155 | buf.putInt(value.ordinal + 1) 1156 | } 1157 | } 1158 | 1159 | 1160 | 1161 | --------------------------------------------------------------------------------