diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..bb460e7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+.DS_Store
+/.build
+/Packages
+/*.xcodeproj
+xcuserdata/
+DerivedData/
+.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
diff --git a/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/MatrixSDKFFIWrapper/dummy.m b/MatrixSDKFFIWrapper/dummy.m
new file mode 100644
index 0000000..296ba74
--- /dev/null
+++ b/MatrixSDKFFIWrapper/dummy.m
@@ -0,0 +1 @@
+// Swift Package Manager needs at least one source file.
diff --git a/MatrixSDKFFIWrapper/include/dummy.h b/MatrixSDKFFIWrapper/include/dummy.h
new file mode 100644
index 0000000..11db125
--- /dev/null
+++ b/MatrixSDKFFIWrapper/include/dummy.h
@@ -0,0 +1,4 @@
+// Swift Package Manager needs at least one header to prevent a warning. See
+// https://github.com/mozilla/application-services/issues/4422.
+
+#import "sdkFFI.h"
diff --git a/Package.swift b/Package.swift
new file mode 100644
index 0000000..e5ad3da
--- /dev/null
+++ b/Package.swift
@@ -0,0 +1,41 @@
+// swift-tools-version:5.5
+// The swift-tools-version declares the minimum version of Swift required to build this package.
+
+import PackageDescription
+
+let checksum = "051aa92b9fff0b18e54c6a82ea12231edf4cfa98b49889223870b3c63bf2829b"
+let version = "v1.0.0-alpha"
+let url = "https://github.com/matrix-org/matrix-rust-components-swift/releases/download/\(version)/MatrixSDKFFI.xcframework.zip"
+
+let package = Package(
+ name: "MatrixRustComponentsSwift",
+ products: [
+ .library(
+ name: "MatrixRustComponentsSwift",
+ targets: ["MatrixRustComponentsSwift"]),
+ ],
+ targets: [
+ .binaryTarget(
+ name: "MatrixSDKFFI",
+ url: url,
+ checksum: checksum),
+ /*
+ * A placeholder wrapper for our binaryTarget so that Xcode will ensure this is
+ * downloaded/built before trying to use it in the build process
+ * A bit hacky but necessary for now https://github.com/mozilla/application-services/issues/4422
+ */
+ .target(
+ name: "MatrixSDKFFIWrapper",
+ dependencies: [
+ .target(name: "MatrixSDKFFI")
+ ],
+ path: "MatrixSDKFFIWrapper"
+ ),
+ .target(
+ name: "MatrixRustComponentsSwift",
+ dependencies: ["MatrixSDKFFIWrapper"]),
+ .testTarget(
+ name: "MatrixRustComponentsSwiftTests",
+ dependencies: ["MatrixRustComponentsSwift"]),
+ ]
+)
diff --git a/README.md b/README.md
index 78a1e00..4f72799 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,3 @@
-# .github
-Default metadata files for repos in this org.
+# MatrixRustComponentsSwift
-If you're seeing this readme in your project, your project is configured wrong.
+A description of this package.
diff --git a/Sources/MatrixRustComponentsSwift/ClientError+Error.swift b/Sources/MatrixRustComponentsSwift/ClientError+Error.swift
new file mode 100644
index 0000000..354ecce
--- /dev/null
+++ b/Sources/MatrixRustComponentsSwift/ClientError+Error.swift
@@ -0,0 +1,11 @@
+//
+// ClientError+Error.swift
+// MatrixRustSDK
+//
+// Created by Stefan Ceriu on 09.02.2022.
+//
+
+import Foundation
+
+// Fixes code generation problem from uniffi
+extension ClientError: Error { }
diff --git a/Sources/MatrixRustComponentsSwift/sdk.swift b/Sources/MatrixRustComponentsSwift/sdk.swift
new file mode 100644
index 0000000..5a0dd1c
--- /dev/null
+++ b/Sources/MatrixRustComponentsSwift/sdk.swift
@@ -0,0 +1,768 @@
+// This file was autogenerated by some hot garbage in the `uniffi` crate.
+// Trust me, you don't want to mess with it!
+import Foundation
+import MatrixSDKFFIWrapper
+
+// Depending on the consumer's build setup, the low-level FFI code
+// might be in a separate module, or it might be compiled inline into
+// this module. This is a bit of light hackery to work with both.
+#if canImport(sdkFFI)
+ import sdkFFI
+#endif
+
+private extension RustBuffer {
+ // Allocate a new buffer, copying the contents of a `UInt8` array.
+ init(bytes: [UInt8]) {
+ let rbuf = bytes.withUnsafeBufferPointer { ptr in
+ RustBuffer.from(ptr)
+ }
+ self.init(capacity: rbuf.capacity, len: rbuf.len, data: rbuf.data)
+ }
+
+ static func from(_ ptr: UnsafeBufferPointer) -> RustBuffer {
+ try! rustCall { ffi_sdk_a8d0_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) }
+ }
+
+ // Frees the buffer in place.
+ // The buffer must not be used after this is called.
+ func deallocate() {
+ try! rustCall { ffi_sdk_a8d0_rustbuffer_free(self, $0) }
+ }
+}
+
+private extension ForeignBytes {
+ init(bufferPointer: UnsafeBufferPointer) {
+ self.init(len: Int32(bufferPointer.count), data: bufferPointer.baseAddress)
+ }
+}
+
+// For every type used in the interface, we provide helper methods for conveniently
+// lifting and lowering that type from C-compatible data, and for reading and writing
+// values of that type in a buffer.
+
+// Helper classes/extensions that don't change.
+// Someday, this will be in a libray of its own.
+
+private extension Data {
+ init(rustBuffer: RustBuffer) {
+ // TODO: This copies the buffer. Can we read directly from a
+ // Rust buffer?
+ self.init(bytes: rustBuffer.data!, count: Int(rustBuffer.len))
+ }
+}
+
+// A helper class to read values out of a byte buffer.
+private class Reader {
+ let data: Data
+ var offset: Data.Index
+
+ init(data: Data) {
+ self.data = data
+ offset = 0
+ }
+
+ // Reads an integer at the current offset, in big-endian order, and advances
+ // the offset on success. Throws if reading the integer would move the
+ // offset past the end of the buffer.
+ func readInt() throws -> T {
+ let range = offset ..< offset + MemoryLayout.size
+ guard data.count >= range.upperBound else {
+ throw UniffiInternalError.bufferOverflow
+ }
+ if T.self == UInt8.self {
+ let value = data[offset]
+ offset += 1
+ return value as! T
+ }
+ var value: T = 0
+ let _ = withUnsafeMutableBytes(of: &value) { data.copyBytes(to: $0, from: range) }
+ offset = range.upperBound
+ return value.bigEndian
+ }
+
+ // Reads an arbitrary number of bytes, to be used to read
+ // raw bytes, this is useful when lifting strings
+ func readBytes(count: Int) throws -> [UInt8] {
+ let range = offset ..< (offset + count)
+ guard data.count >= range.upperBound else {
+ throw UniffiInternalError.bufferOverflow
+ }
+ var value = [UInt8](repeating: 0, count: count)
+ value.withUnsafeMutableBufferPointer { buffer in
+ data.copyBytes(to: buffer, from: range)
+ }
+ offset = range.upperBound
+ return value
+ }
+
+ // Reads a float at the current offset.
+ @inlinable
+ func readFloat() throws -> Float {
+ return Float(bitPattern: try readInt())
+ }
+
+ // Reads a float at the current offset.
+ @inlinable
+ func readDouble() throws -> Double {
+ return Double(bitPattern: try readInt())
+ }
+
+ // Indicates if the offset has reached the end of the buffer.
+ @inlinable
+ func hasRemaining() -> Bool {
+ return offset < data.count
+ }
+}
+
+// A helper class to write values into a byte buffer.
+private class Writer {
+ var bytes: [UInt8]
+ var offset: Array.Index
+
+ init() {
+ bytes = []
+ offset = 0
+ }
+
+ func writeBytes(_ byteArr: S) where S: Sequence, S.Element == UInt8 {
+ bytes.append(contentsOf: byteArr)
+ }
+
+ // Writes an integer in big-endian order.
+ //
+ // Warning: make sure what you are trying to write
+ // is in the correct type!
+ func writeInt(_ value: T) {
+ var value = value.bigEndian
+ withUnsafeBytes(of: &value) { bytes.append(contentsOf: $0) }
+ }
+
+ @inlinable
+ func writeFloat(_ value: Float) {
+ writeInt(value.bitPattern)
+ }
+
+ @inlinable
+ func writeDouble(_ value: Double) {
+ writeInt(value.bitPattern)
+ }
+}
+
+// Types conforming to `Serializable` can be read and written in a bytebuffer.
+private protocol Serializable {
+ func write(into: Writer)
+ static func read(from: Reader) throws -> Self
+}
+
+// Types confirming to `ViaFfi` can be transferred back-and-for over the FFI.
+// This is analogous to the Rust trait of the same name.
+private protocol ViaFfi: Serializable {
+ associatedtype FfiType
+ static func lift(_ v: FfiType) throws -> Self
+ func lower() -> FfiType
+}
+
+// Types conforming to `Primitive` pass themselves directly over the FFI.
+private protocol Primitive {}
+
+private extension Primitive {
+ typealias FfiType = Self
+
+ static func lift(_ v: Self) throws -> Self {
+ return v
+ }
+
+ func lower() -> Self {
+ return self
+ }
+}
+
+// Types conforming to `ViaFfiUsingByteBuffer` lift and lower into a bytebuffer.
+// Use this for complex types where it's hard to write a custom lift/lower.
+private protocol ViaFfiUsingByteBuffer: Serializable {}
+
+private extension ViaFfiUsingByteBuffer {
+ typealias FfiType = RustBuffer
+
+ static func lift(_ buf: FfiType) throws -> Self {
+ let reader = Reader(data: Data(rustBuffer: buf))
+ let value = try Self.read(from: reader)
+ if reader.hasRemaining() {
+ throw UniffiInternalError.incompleteData
+ }
+ buf.deallocate()
+ return value
+ }
+
+ func lower() -> FfiType {
+ let writer = Writer()
+ write(into: writer)
+ return RustBuffer(bytes: writer.bytes)
+ }
+}
+
+// An error type for FFI errors. These errors occur at the UniFFI level, not
+// the library level.
+private enum UniffiInternalError: LocalizedError {
+ case bufferOverflow
+ case incompleteData
+ case unexpectedOptionalTag
+ case unexpectedEnumCase
+ case unexpectedNullPointer
+ case unexpectedRustCallStatusCode
+ case unexpectedRustCallError
+ case unexpectedStaleHandle
+ case rustPanic(_ message: String)
+
+ public var errorDescription: String? {
+ switch self {
+ case .bufferOverflow: return "Reading the requested value would read past the end of the buffer"
+ case .incompleteData: return "The buffer still has data after lifting its containing value"
+ case .unexpectedOptionalTag: return "Unexpected optional tag; should be 0 or 1"
+ case .unexpectedEnumCase: return "Raw enum value doesn't match any cases"
+ case .unexpectedNullPointer: return "Raw pointer value was null"
+ case .unexpectedRustCallStatusCode: return "Unexpected RustCallStatus code"
+ case .unexpectedRustCallError: return "CALL_ERROR but no errorClass specified"
+ case .unexpectedStaleHandle: return "The object in the handle map has been dropped already"
+ case let .rustPanic(message): return message
+ }
+ }
+}
+
+private let CALL_SUCCESS: Int8 = 0
+private let CALL_ERROR: Int8 = 1
+private let CALL_PANIC: Int8 = 2
+
+private extension RustCallStatus {
+ init() {
+ self.init(
+ code: CALL_SUCCESS,
+ errorBuf: RustBuffer(
+ capacity: 0,
+ len: 0,
+ data: nil
+ )
+ )
+ }
+}
+
+private func rustCall(_ callback: (UnsafeMutablePointer) -> T) throws -> T {
+ try makeRustCall(callback, errorHandler: {
+ $0.deallocate()
+ return UniffiInternalError.unexpectedRustCallError
+ })
+}
+
+private func rustCallWithError(_: E.Type, _ callback: (UnsafeMutablePointer) -> T) throws -> T {
+ try makeRustCall(callback, errorHandler: { try E.lift($0) })
+}
+
+private func makeRustCall(_ callback: (UnsafeMutablePointer) -> T, errorHandler: (RustBuffer) throws -> Error) throws -> T {
+ var callStatus = RustCallStatus()
+ let returnedVal = callback(&callStatus)
+ switch callStatus.code {
+ case CALL_SUCCESS:
+ return returnedVal
+
+ case CALL_ERROR:
+ throw try errorHandler(callStatus.errorBuf)
+
+ case CALL_PANIC:
+ // When the rust code sees a panic, it tries to construct a RustBuffer
+ // with the message. But if that code panics, then it just sends back
+ // an empty buffer.
+ if callStatus.errorBuf.len > 0 {
+ throw UniffiInternalError.rustPanic(try String.lift(callStatus.errorBuf))
+ } else {
+ callStatus.errorBuf.deallocate()
+ throw UniffiInternalError.rustPanic("Rust panic")
+ }
+
+ default:
+ throw UniffiInternalError.unexpectedRustCallStatusCode
+ }
+}
+
+// Protocols for converters we'll implement in templates
+
+private protocol FfiConverter {
+ associatedtype SwiftType
+ associatedtype FfiType
+
+ static func lift(_ ffiValue: FfiType) throws -> SwiftType
+ static func lower(_ value: SwiftType) -> FfiType
+
+ static func read(from: Reader) throws -> SwiftType
+ static func write(_ value: SwiftType, into: Writer)
+}
+
+private protocol FfiConverterUsingByteBuffer: FfiConverter where FfiType == RustBuffer {
+ // Empty, because we want to declare some helper methods in the extension below.
+}
+
+extension FfiConverterUsingByteBuffer {
+ static func lower(_ value: SwiftType) -> FfiType {
+ let writer = Writer()
+ Self.write(value, into: writer)
+ return RustBuffer(bytes: writer.bytes)
+ }
+
+ static func lift(_ buf: FfiType) throws -> SwiftType {
+ let reader = Reader(data: Data(rustBuffer: buf))
+ let value = try Self.read(from: reader)
+ if reader.hasRemaining() {
+ throw UniffiInternalError.incompleteData
+ }
+ buf.deallocate()
+ return value
+ }
+}
+
+// Helpers for structural types. Note that because of canonical_names, it /should/ be impossible
+// to make another `FfiConverterSequence` etc just using the UDL.
+private enum FfiConverterSequence {
+ static func write(_ value: [T], into buf: Writer, writeItem: (T, Writer) -> Void) {
+ let len = Int32(value.count)
+ buf.writeInt(len)
+ for item in value {
+ writeItem(item, buf)
+ }
+ }
+
+ static func read(from buf: Reader, readItem: (Reader) throws -> T) throws -> [T] {
+ let len: Int32 = try buf.readInt()
+ var seq = [T]()
+ seq.reserveCapacity(Int(len))
+ for _ in 0 ..< len {
+ seq.append(try readItem(buf))
+ }
+ return seq
+ }
+}
+
+private enum FfiConverterOptional {
+ static func write(_ value: T?, into buf: Writer, writeItem: (T, Writer) -> Void) {
+ guard let value = value else {
+ buf.writeInt(Int8(0))
+ return
+ }
+ buf.writeInt(Int8(1))
+ writeItem(value, buf)
+ }
+
+ static func read(from buf: Reader, readItem: (Reader) throws -> T) throws -> T? {
+ switch try buf.readInt() as Int8 {
+ case 0: return nil
+ case 1: return try readItem(buf)
+ default: throw UniffiInternalError.unexpectedOptionalTag
+ }
+ }
+}
+
+private enum FfiConverterDictionary {
+ static func write(_ value: [String: T], into buf: Writer, writeItem: (String, T, Writer) -> Void) {
+ let len = Int32(value.count)
+ buf.writeInt(len)
+ for (key, value) in value {
+ writeItem(key, value, buf)
+ }
+ }
+
+ static func read(from buf: Reader, readItem: (Reader) throws -> (String, T)) throws -> [String: T] {
+ let len: Int32 = try buf.readInt()
+ var dict = [String: T]()
+ dict.reserveCapacity(Int(len))
+ for _ in 0 ..< len {
+ let (key, value) = try readItem(buf)
+ dict[key] = value
+ }
+ return dict
+ }
+}
+
+// Public interface members begin here.
+
+// Note that we don't yet support `indirect` for enums.
+// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion.
+
+public enum ClientError {
+ case generic(msg: String)
+}
+
+extension ClientError: ViaFfiUsingByteBuffer, ViaFfi {
+ fileprivate static func read(from buf: Reader) throws -> ClientError {
+ let variant: Int32 = try buf.readInt()
+ switch variant {
+ case 1: return .generic(
+ msg: try String.read(from: buf)
+ )
+ default: throw UniffiInternalError.unexpectedEnumCase
+ }
+ }
+
+ fileprivate func write(into buf: Writer) {
+ switch self {
+ case let .generic(msg):
+ buf.writeInt(Int32(1))
+ msg.write(into: buf)
+ }
+ }
+}
+
+extension ClientError: Equatable, Hashable {}
+
+public func loginNewClient(basePath: String, username: String, password: String) throws -> Client {
+ let _retval = try
+
+ rustCallWithError(ClientError.self) {
+ sdk_a8d0_login_new_client(basePath.lower(), username.lower(), password.lower(), $0)
+ }
+ return try Client.lift(_retval)
+}
+
+public func guestClient(basePath: String, homeserver: String) throws -> Client {
+ let _retval = try
+
+ rustCallWithError(ClientError.self) {
+ sdk_a8d0_guest_client(basePath.lower(), homeserver.lower(), $0)
+ }
+ return try Client.lift(_retval)
+}
+
+public func loginWithToken(basePath: String, restoreToken: String) throws -> Client {
+ let _retval = try
+
+ rustCallWithError(ClientError.self) {
+ sdk_a8d0_login_with_token(basePath.lower(), restoreToken.lower(), $0)
+ }
+ return try Client.lift(_retval)
+}
+
+public protocol RoomProtocol {
+ func displayName() throws -> String
+ func avatar() throws -> [UInt8]
+}
+
+public class Room: RoomProtocol {
+ fileprivate let pointer: UnsafeMutableRawPointer
+
+ // TODO: We'd like this to be `private` but for Swifty reasons,
+ // we can't implement `ViaFfi` without making this `required` and we can't
+ // make it `required` without making it `public`.
+ required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) {
+ self.pointer = pointer
+ }
+
+ deinit {
+ try! rustCall { ffi_sdk_a8d0_Room_object_free(pointer, $0) }
+ }
+
+ public func displayName() throws -> String {
+ let _retval = try
+ rustCallWithError(ClientError.self) {
+ sdk_a8d0_Room_display_name(self.pointer, $0)
+ }
+ return try String.lift(_retval)
+ }
+
+ public func avatar() throws -> [UInt8] {
+ let _retval = try
+ rustCallWithError(ClientError.self) {
+ sdk_a8d0_Room_avatar(self.pointer, $0)
+ }
+ return try FfiConverterSequenceUInt8.lift(_retval)
+ }
+}
+
+private extension Room {
+ typealias FfiType = UnsafeMutableRawPointer
+
+ static func read(from buf: Reader) throws -> Self {
+ let v: UInt64 = try buf.readInt()
+ // The Rust code won't compile if a pointer won't fit in a UInt64.
+ // We have to go via `UInt` because that's the thing that's the size of a pointer.
+ let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v))
+ if ptr == nil {
+ throw UniffiInternalError.unexpectedNullPointer
+ }
+ return try lift(ptr!)
+ }
+
+ func write(into buf: Writer) {
+ // This fiddling is because `Int` is the thing that's the same size as a pointer.
+ // The Rust code won't compile if a pointer won't fit in a `UInt64`.
+ buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower()))))
+ }
+
+ static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Self {
+ return Self(unsafeFromRawPointer: pointer)
+ }
+
+ func lower() -> UnsafeMutableRawPointer {
+ return pointer
+ }
+}
+
+// Ideally this would be `fileprivate`, but Swift says:
+// """
+// 'private' modifier cannot be used with extensions that declare protocol conformances
+// """
+extension Room: ViaFfi, Serializable {}
+
+public protocol ClientProtocol {
+ func startSync()
+ func restoreToken() throws -> String
+ func isGuest() -> Bool
+ func hasFirstSynced() -> Bool
+ func isSyncing() -> Bool
+ func userId() throws -> String
+ func displayName() throws -> String
+ func deviceId() throws -> String
+ func avatar() throws -> [UInt8]
+ func conversations() -> [Room]
+}
+
+public class Client: ClientProtocol {
+ fileprivate let pointer: UnsafeMutableRawPointer
+
+ // TODO: We'd like this to be `private` but for Swifty reasons,
+ // we can't implement `ViaFfi` without making this `required` and we can't
+ // make it `required` without making it `public`.
+ required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) {
+ self.pointer = pointer
+ }
+
+ deinit {
+ try! rustCall { ffi_sdk_a8d0_Client_object_free(pointer, $0) }
+ }
+
+ public func startSync() {
+ try!
+ rustCall {
+ sdk_a8d0_Client_start_sync(self.pointer, $0)
+ }
+ }
+
+ public func restoreToken() throws -> String {
+ let _retval = try
+ rustCallWithError(ClientError.self) {
+ sdk_a8d0_Client_restore_token(self.pointer, $0)
+ }
+ return try String.lift(_retval)
+ }
+
+ public func isGuest() -> Bool {
+ let _retval = try!
+ rustCall {
+ sdk_a8d0_Client_is_guest(self.pointer, $0)
+ }
+ return try! Bool.lift(_retval)
+ }
+
+ public func hasFirstSynced() -> Bool {
+ let _retval = try!
+ rustCall {
+ sdk_a8d0_Client_has_first_synced(self.pointer, $0)
+ }
+ return try! Bool.lift(_retval)
+ }
+
+ public func isSyncing() -> Bool {
+ let _retval = try!
+ rustCall {
+ sdk_a8d0_Client_is_syncing(self.pointer, $0)
+ }
+ return try! Bool.lift(_retval)
+ }
+
+ public func userId() throws -> String {
+ let _retval = try
+ rustCallWithError(ClientError.self) {
+ sdk_a8d0_Client_user_id(self.pointer, $0)
+ }
+ return try String.lift(_retval)
+ }
+
+ public func displayName() throws -> String {
+ let _retval = try
+ rustCallWithError(ClientError.self) {
+ sdk_a8d0_Client_display_name(self.pointer, $0)
+ }
+ return try String.lift(_retval)
+ }
+
+ public func deviceId() throws -> String {
+ let _retval = try
+ rustCallWithError(ClientError.self) {
+ sdk_a8d0_Client_device_id(self.pointer, $0)
+ }
+ return try String.lift(_retval)
+ }
+
+ public func avatar() throws -> [UInt8] {
+ let _retval = try
+ rustCallWithError(ClientError.self) {
+ sdk_a8d0_Client_avatar(self.pointer, $0)
+ }
+ return try FfiConverterSequenceUInt8.lift(_retval)
+ }
+
+ public func conversations() -> [Room] {
+ let _retval = try!
+ rustCall {
+ sdk_a8d0_Client_conversations(self.pointer, $0)
+ }
+ return try! FfiConverterSequenceObjectRoom.lift(_retval)
+ }
+}
+
+private extension Client {
+ typealias FfiType = UnsafeMutableRawPointer
+
+ static func read(from buf: Reader) throws -> Self {
+ let v: UInt64 = try buf.readInt()
+ // The Rust code won't compile if a pointer won't fit in a UInt64.
+ // We have to go via `UInt` because that's the thing that's the size of a pointer.
+ let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v))
+ if ptr == nil {
+ throw UniffiInternalError.unexpectedNullPointer
+ }
+ return try lift(ptr!)
+ }
+
+ func write(into buf: Writer) {
+ // This fiddling is because `Int` is the thing that's the same size as a pointer.
+ // The Rust code won't compile if a pointer won't fit in a `UInt64`.
+ buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower()))))
+ }
+
+ static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Self {
+ return Self(unsafeFromRawPointer: pointer)
+ }
+
+ func lower() -> UnsafeMutableRawPointer {
+ return pointer
+ }
+}
+
+// Ideally this would be `fileprivate`, but Swift says:
+// """
+// 'private' modifier cannot be used with extensions that declare protocol conformances
+// """
+extension Client: ViaFfi, Serializable {}
+extension UInt8: Primitive, ViaFfi {
+ fileprivate static func read(from buf: Reader) throws -> Self {
+ return try lift(buf.readInt())
+ }
+
+ fileprivate func write(into buf: Writer) {
+ buf.writeInt(lower())
+ }
+}
+
+extension Bool: ViaFfi {
+ fileprivate typealias FfiType = Int8
+
+ fileprivate static func read(from buf: Reader) throws -> Self {
+ return try lift(buf.readInt())
+ }
+
+ fileprivate func write(into buf: Writer) {
+ buf.writeInt(lower())
+ }
+
+ fileprivate static func lift(_ v: FfiType) throws -> Self {
+ return v != 0
+ }
+
+ fileprivate func lower() -> FfiType {
+ return self ? 1 : 0
+ }
+}
+
+extension String: ViaFfi {
+ fileprivate typealias FfiType = RustBuffer
+
+ fileprivate static func lift(_ v: FfiType) throws -> Self {
+ defer {
+ v.deallocate()
+ }
+ if v.data == nil {
+ return String()
+ }
+ let bytes = UnsafeBufferPointer(start: v.data!, count: Int(v.len))
+ return String(bytes: bytes, encoding: String.Encoding.utf8)!
+ }
+
+ fileprivate func lower() -> FfiType {
+ return utf8CString.withUnsafeBufferPointer { ptr in
+ // The swift string gives us int8_t, we want uint8_t.
+ ptr.withMemoryRebound(to: UInt8.self) { ptr in
+ // The swift string gives us a trailing null byte, we don't want it.
+ let buf = UnsafeBufferPointer(rebasing: ptr.prefix(upTo: ptr.count - 1))
+ return RustBuffer.from(buf)
+ }
+ }
+ }
+
+ fileprivate static func read(from buf: Reader) throws -> Self {
+ let len: Int32 = try buf.readInt()
+ return String(bytes: try buf.readBytes(count: Int(len)), encoding: String.Encoding.utf8)!
+ }
+
+ fileprivate func write(into buf: Writer) {
+ let len = Int32(utf8.count)
+ buf.writeInt(len)
+ buf.writeBytes(utf8)
+ }
+}
+
+// Helper code for Client class is found in ObjectTemplate.swift
+// Helper code for Room class is found in ObjectTemplate.swift
+// Helper code for ClientError enum is found in EnumTemplate.swift
+
+private enum FfiConverterSequenceUInt8: FfiConverterUsingByteBuffer {
+ typealias SwiftType = [UInt8]
+
+ static func write(_ value: SwiftType, into buf: Writer) {
+ FfiConverterSequence.write(value, into: buf) { item, buf in
+ item.write(into: buf)
+ }
+ }
+
+ static func read(from buf: Reader) throws -> SwiftType {
+ try FfiConverterSequence.read(from: buf) { buf in
+ try UInt8.read(from: buf)
+ }
+ }
+}
+
+private enum FfiConverterSequenceObjectRoom: FfiConverterUsingByteBuffer {
+ typealias SwiftType = [Room]
+
+ static func write(_ value: SwiftType, into buf: Writer) {
+ FfiConverterSequence.write(value, into: buf) { item, buf in
+ item.write(into: buf)
+ }
+ }
+
+ static func read(from buf: Reader) throws -> SwiftType {
+ try FfiConverterSequence.read(from: buf) { buf in
+ try Room.read(from: buf)
+ }
+ }
+}
+
+/**
+ * Top level initializers and tear down methods.
+ *
+ * This is generated by uniffi.
+ */
+public enum SdkLifecycle {
+ /**
+ * Initialize the FFI and Rust library. This should be only called once per application.
+ */
+ func initialize() {
+ // No initialization code needed
+ }
+}
diff --git a/Tests/MatrixRustComponentsSwiftTests/MatrixRustComponentsSwiftTests.swift b/Tests/MatrixRustComponentsSwiftTests/MatrixRustComponentsSwiftTests.swift
new file mode 100644
index 0000000..e8cb4c9
--- /dev/null
+++ b/Tests/MatrixRustComponentsSwiftTests/MatrixRustComponentsSwiftTests.swift
@@ -0,0 +1,16 @@
+import XCTest
+@testable import MatrixRustComponentsSwift
+
+final class MatrixRustComponentsSwiftTests: XCTestCase {
+ func testExample() throws {
+ do {
+ let client = try loginNewClient(basePath: "", username: "", password: "")
+ let displayName = try client.displayName()
+ print("Display name: \(displayName)")
+ } catch ClientError.generic(let msg) {
+ print("Failed with message \(msg)")
+ } catch {
+ fatalError()
+ }
+ }
+}