Handle TimelineDiff as an enum with associated values. (#4379)

* Handle TimelineDiff as a true enum.

* Update the SDK.

* Silence some warnings.
This commit is contained in:
Doug
2025-08-05 09:23:22 +01:00
committed by GitHub
parent 514c7808e2
commit e182940844
8 changed files with 31 additions and 667 deletions
+1 -1
View File
@@ -9052,7 +9052,7 @@
repositoryURL = "https://github.com/element-hq/matrix-rust-components-swift";
requirement = {
kind = exactVersion;
version = 25.08.01;
version = 25.08.04;
};
};
701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */ = {
@@ -158,8 +158,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/element-hq/matrix-rust-components-swift",
"state" : {
"revision" : "7e51369bc9407e15295bfa94b96703063c7b7156",
"version" : "25.8.1"
"revision" : "5de28310ff9673b8ba1ccdc0e4e00701a0d16535",
"version" : "25.8.4"
}
},
{
@@ -23855,602 +23855,6 @@ open class TimelineSDKMock: MatrixRustSDK.Timeline, @unchecked Sendable {
}
}
}
open class TimelineDiffSDKMock: MatrixRustSDK.TimelineDiff, @unchecked Sendable {
init() {
super.init(noPointer: .init())
}
public required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) {
fatalError("init(unsafeFromRawPointer:) has not been implemented")
}
fileprivate var pointer: UnsafeMutableRawPointer!
//MARK: - append
var appendUnderlyingCallsCount = 0
open var appendCallsCount: Int {
get {
if Thread.isMainThread {
return appendUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = appendUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
appendUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
appendUnderlyingCallsCount = newValue
}
}
}
}
open var appendCalled: Bool {
return appendCallsCount > 0
}
var appendUnderlyingReturnValue: [TimelineItem]?
open var appendReturnValue: [TimelineItem]? {
get {
if Thread.isMainThread {
return appendUnderlyingReturnValue
} else {
var returnValue: [TimelineItem]?? = nil
DispatchQueue.main.sync {
returnValue = appendUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
appendUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
appendUnderlyingReturnValue = newValue
}
}
}
}
open var appendClosure: (() -> [TimelineItem]?)?
open override func append() -> [TimelineItem]? {
appendCallsCount += 1
if let appendClosure = appendClosure {
return appendClosure()
} else {
return appendReturnValue
}
}
//MARK: - change
var changeUnderlyingCallsCount = 0
open var changeCallsCount: Int {
get {
if Thread.isMainThread {
return changeUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = changeUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
changeUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
changeUnderlyingCallsCount = newValue
}
}
}
}
open var changeCalled: Bool {
return changeCallsCount > 0
}
var changeUnderlyingReturnValue: TimelineChange!
open var changeReturnValue: TimelineChange! {
get {
if Thread.isMainThread {
return changeUnderlyingReturnValue
} else {
var returnValue: TimelineChange? = nil
DispatchQueue.main.sync {
returnValue = changeUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
changeUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
changeUnderlyingReturnValue = newValue
}
}
}
}
open var changeClosure: (() -> TimelineChange)?
open override func change() -> TimelineChange {
changeCallsCount += 1
if let changeClosure = changeClosure {
return changeClosure()
} else {
return changeReturnValue
}
}
//MARK: - insert
var insertUnderlyingCallsCount = 0
open var insertCallsCount: Int {
get {
if Thread.isMainThread {
return insertUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = insertUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
insertUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
insertUnderlyingCallsCount = newValue
}
}
}
}
open var insertCalled: Bool {
return insertCallsCount > 0
}
var insertUnderlyingReturnValue: InsertData?
open var insertReturnValue: InsertData? {
get {
if Thread.isMainThread {
return insertUnderlyingReturnValue
} else {
var returnValue: InsertData?? = nil
DispatchQueue.main.sync {
returnValue = insertUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
insertUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
insertUnderlyingReturnValue = newValue
}
}
}
}
open var insertClosure: (() -> InsertData?)?
open override func insert() -> InsertData? {
insertCallsCount += 1
if let insertClosure = insertClosure {
return insertClosure()
} else {
return insertReturnValue
}
}
//MARK: - pushBack
var pushBackUnderlyingCallsCount = 0
open var pushBackCallsCount: Int {
get {
if Thread.isMainThread {
return pushBackUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = pushBackUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
pushBackUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
pushBackUnderlyingCallsCount = newValue
}
}
}
}
open var pushBackCalled: Bool {
return pushBackCallsCount > 0
}
var pushBackUnderlyingReturnValue: TimelineItem?
open var pushBackReturnValue: TimelineItem? {
get {
if Thread.isMainThread {
return pushBackUnderlyingReturnValue
} else {
var returnValue: TimelineItem?? = nil
DispatchQueue.main.sync {
returnValue = pushBackUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
pushBackUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
pushBackUnderlyingReturnValue = newValue
}
}
}
}
open var pushBackClosure: (() -> TimelineItem?)?
open override func pushBack() -> TimelineItem? {
pushBackCallsCount += 1
if let pushBackClosure = pushBackClosure {
return pushBackClosure()
} else {
return pushBackReturnValue
}
}
//MARK: - pushFront
var pushFrontUnderlyingCallsCount = 0
open var pushFrontCallsCount: Int {
get {
if Thread.isMainThread {
return pushFrontUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = pushFrontUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
pushFrontUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
pushFrontUnderlyingCallsCount = newValue
}
}
}
}
open var pushFrontCalled: Bool {
return pushFrontCallsCount > 0
}
var pushFrontUnderlyingReturnValue: TimelineItem?
open var pushFrontReturnValue: TimelineItem? {
get {
if Thread.isMainThread {
return pushFrontUnderlyingReturnValue
} else {
var returnValue: TimelineItem?? = nil
DispatchQueue.main.sync {
returnValue = pushFrontUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
pushFrontUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
pushFrontUnderlyingReturnValue = newValue
}
}
}
}
open var pushFrontClosure: (() -> TimelineItem?)?
open override func pushFront() -> TimelineItem? {
pushFrontCallsCount += 1
if let pushFrontClosure = pushFrontClosure {
return pushFrontClosure()
} else {
return pushFrontReturnValue
}
}
//MARK: - remove
var removeUnderlyingCallsCount = 0
open var removeCallsCount: Int {
get {
if Thread.isMainThread {
return removeUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = removeUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
removeUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
removeUnderlyingCallsCount = newValue
}
}
}
}
open var removeCalled: Bool {
return removeCallsCount > 0
}
var removeUnderlyingReturnValue: UInt32?
open var removeReturnValue: UInt32? {
get {
if Thread.isMainThread {
return removeUnderlyingReturnValue
} else {
var returnValue: UInt32?? = nil
DispatchQueue.main.sync {
returnValue = removeUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
removeUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
removeUnderlyingReturnValue = newValue
}
}
}
}
open var removeClosure: (() -> UInt32?)?
open override func remove() -> UInt32? {
removeCallsCount += 1
if let removeClosure = removeClosure {
return removeClosure()
} else {
return removeReturnValue
}
}
//MARK: - reset
var resetUnderlyingCallsCount = 0
open var resetCallsCount: Int {
get {
if Thread.isMainThread {
return resetUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = resetUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
resetUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
resetUnderlyingCallsCount = newValue
}
}
}
}
open var resetCalled: Bool {
return resetCallsCount > 0
}
var resetUnderlyingReturnValue: [TimelineItem]?
open var resetReturnValue: [TimelineItem]? {
get {
if Thread.isMainThread {
return resetUnderlyingReturnValue
} else {
var returnValue: [TimelineItem]?? = nil
DispatchQueue.main.sync {
returnValue = resetUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
resetUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
resetUnderlyingReturnValue = newValue
}
}
}
}
open var resetClosure: (() -> [TimelineItem]?)?
open override func reset() -> [TimelineItem]? {
resetCallsCount += 1
if let resetClosure = resetClosure {
return resetClosure()
} else {
return resetReturnValue
}
}
//MARK: - set
var setUnderlyingCallsCount = 0
open var setCallsCount: Int {
get {
if Thread.isMainThread {
return setUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = setUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
setUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
setUnderlyingCallsCount = newValue
}
}
}
}
open var setCalled: Bool {
return setCallsCount > 0
}
var setUnderlyingReturnValue: SetData?
open var setReturnValue: SetData? {
get {
if Thread.isMainThread {
return setUnderlyingReturnValue
} else {
var returnValue: SetData?? = nil
DispatchQueue.main.sync {
returnValue = setUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
setUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
setUnderlyingReturnValue = newValue
}
}
}
}
open var setClosure: (() -> SetData?)?
open override func set() -> SetData? {
setCallsCount += 1
if let setClosure = setClosure {
return setClosure()
} else {
return setReturnValue
}
}
//MARK: - truncate
var truncateUnderlyingCallsCount = 0
open var truncateCallsCount: Int {
get {
if Thread.isMainThread {
return truncateUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = truncateUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
truncateUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
truncateUnderlyingCallsCount = newValue
}
}
}
}
open var truncateCalled: Bool {
return truncateCallsCount > 0
}
var truncateUnderlyingReturnValue: UInt32?
open var truncateReturnValue: UInt32? {
get {
if Thread.isMainThread {
return truncateUnderlyingReturnValue
} else {
var returnValue: UInt32?? = nil
DispatchQueue.main.sync {
returnValue = truncateUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
truncateUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
truncateUnderlyingReturnValue = newValue
}
}
}
}
open var truncateClosure: (() -> UInt32?)?
open override func truncate() -> UInt32? {
truncateCallsCount += 1
if let truncateClosure = truncateClosure {
return truncateClosure()
} else {
return truncateReturnValue
}
}
}
open class TimelineEventSDKMock: MatrixRustSDK.TimelineEvent, @unchecked Sendable {
init() {
super.init(noPointer: .init())
@@ -33,14 +33,11 @@ class AutoUpdatingTimelineItemProviderMock: TimelineItemProvider {
for _ in 0...100 {
try? await Task.sleep(for: .seconds(1))
let diff = TimelineDiffSDKMock()
diff.changeReturnValue = .append
let timelineItem = TimelineItemSDKMock()
timelineItem.asEventReturnValue = EventTimelineItem.mockMessage
timelineItem.uniqueIdReturnValue = .init(id: UUID().uuidString)
diff.appendReturnValue = [timelineItem]
let diff = TimelineDiff.append(values: [timelineItem])
await Self.timelineListener?.onUpdate(diff: [diff])
}
@@ -107,14 +107,11 @@ class TimelineItemProvider: TimelineItemProviderProtocol {
}
}
// swiftlint:disable:next cyclomatic_complexity
private func buildDiff(from diff: TimelineDiff, on itemProxies: [TimelineItemProxy]) -> CollectionDifference<TimelineItemProxy>? {
var changes = [CollectionDifference<TimelineItemProxy>.Change]()
switch diff.change() {
case .append:
guard let items = diff.append() else { fatalError() }
switch diff {
case .append(let items):
for (index, item) in items.enumerated() {
let itemProxy = TimelineItemProxy(item: item)
@@ -128,11 +125,9 @@ class TimelineItemProvider: TimelineItemProviderProtocol {
for (index, itemProxy) in itemProxies.enumerated() {
changes.append(.remove(offset: index, element: itemProxy, associatedWith: nil))
}
case .insert:
guard let update = diff.insert() else { fatalError() }
let itemProxy = TimelineItemProxy(item: update.item)
changes.append(.insert(offset: Int(update.index), element: itemProxy, associatedWith: nil))
case .insert(let index, let item):
let itemProxy = TimelineItemProxy(item: item)
changes.append(.insert(offset: Int(index), element: itemProxy, associatedWith: nil))
case .popBack:
guard let itemProxy = itemProxies.last else { fatalError() }
@@ -141,9 +136,7 @@ class TimelineItemProvider: TimelineItemProviderProtocol {
guard let itemProxy = itemProxies.first else { fatalError() }
changes.append(.remove(offset: 0, element: itemProxy, associatedWith: nil))
case .pushBack:
guard let item = diff.pushBack() else { fatalError() }
case .pushBack(let item):
let itemProxy = TimelineItemProxy(item: item)
if itemProxy.isMembershipChange {
@@ -151,20 +144,15 @@ class TimelineItemProvider: TimelineItemProviderProtocol {
}
changes.append(.insert(offset: Int(itemProxies.count), element: itemProxy, associatedWith: nil))
case .pushFront:
guard let item = diff.pushFront() else { fatalError() }
case .pushFront(let item):
let itemProxy = TimelineItemProxy(item: item)
changes.append(.insert(offset: 0, element: itemProxy, associatedWith: nil))
case .remove:
guard let index = diff.remove() else { fatalError() }
case .remove(let index):
let itemProxy = itemProxies[Int(index)]
changes.append(.remove(offset: Int(index), element: itemProxy, associatedWith: nil))
case .reset:
guard let items = diff.reset() else { fatalError() }
case .reset(let items):
for (index, itemProxy) in itemProxies.enumerated() {
changes.append(.remove(offset: index, element: itemProxy, associatedWith: nil))
}
@@ -172,12 +160,10 @@ class TimelineItemProvider: TimelineItemProviderProtocol {
for (index, timelineItem) in items.enumerated() {
changes.append(.insert(offset: index, element: TimelineItemProxy(item: timelineItem), associatedWith: nil))
}
case .set:
guard let update = diff.set() else { fatalError() }
let itemProxy = TimelineItemProxy(item: update.item)
changes.append(.remove(offset: Int(update.index), element: itemProxy, associatedWith: nil))
changes.append(.insert(offset: Int(update.index), element: itemProxy, associatedWith: nil))
case .set(let index, let item):
let itemProxy = TimelineItemProxy(item: item)
changes.append(.remove(offset: Int(index), element: itemProxy, associatedWith: nil))
changes.append(.insert(offset: Int(index), element: itemProxy, associatedWith: nil))
case .truncate:
break
}
@@ -223,26 +209,17 @@ private extension Array where Element == TimelineDiff {
extension TimelineDiff: @retroactive CustomDebugStringConvertible {
public var debugDescription: String {
switch change() {
case .append:
guard let update = append() else {
fatalError()
}
return "Append(\(update.count))"
switch self {
case .append(let items):
return "Append(\(items.count))"
case .clear:
return "Clear"
case .insert:
return "Insert"
case .set:
guard let update = set() else {
fatalError()
}
return "Set(\(update.index))"
case .remove:
guard let update = remove() else {
fatalError()
}
return "Remove(\(update)"
case .set(let index, _):
return "Set(\(index))"
case .remove(let index):
return "Remove(\(index)"
case .pushBack:
return "PushBack"
case .pushFront:
@@ -251,16 +228,10 @@ extension TimelineDiff: @retroactive CustomDebugStringConvertible {
return "PopBack"
case .popFront:
return "PopFront"
case .truncate:
guard let update = truncate() else {
fatalError()
}
return "Truncate(\(update))"
case .reset:
guard let update = reset() else {
fatalError()
}
return "Reset(\(update.count)@\(update.startIndex)-\(update.endIndex))"
case .truncate(let length):
return "Truncate(\(length))"
case .reset(let items):
return "Reset(\(items.count)@\(items.startIndex)-\(items.endIndex))"
}
}
}
@@ -106,10 +106,6 @@ class UserSessionStore: UserSessionStoreProtocol {
}
private func restorePreviousLogin(_ credentials: KeychainCredentials) async -> Result<ClientProxyProtocol, UserSessionStoreError> {
if credentials.restorationToken.passphrase != nil {
MXLog.info("Restoring client with encrypted store.")
}
guard credentials.restorationToken.sessionDirectories.isNonTransientUserDataValid() else {
MXLog.error("Failed restoring login, missing non-transient user data")
return .failure(.failedRestoringLogin)
-4
View File
@@ -47,11 +47,7 @@ final class NSEUserSession {
appHooks: AppHooks,
appSettings: CommonSettingsProtocol) async throws {
sessionDirectories = credentials.restorationToken.sessionDirectories
userID = credentials.userID
if credentials.restorationToken.passphrase != nil {
MXLog.info("Restoring client with encrypted store.")
}
let homeserverURL = credentials.restorationToken.session.homeserverUrl
let clientBuilder = ClientBuilder
+1 -1
View File
@@ -68,7 +68,7 @@ packages:
# Element/Matrix dependencies
MatrixRustSDK:
url: https://github.com/element-hq/matrix-rust-components-swift
exactVersion: 25.08.01
exactVersion: 25.08.04
# path: ../matrix-rust-sdk
Compound:
url: https://github.com/element-hq/compound-ios