Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Swift6 mode #199

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,860 changes: 1,430 additions & 1,430 deletions AutomergeUniffi/automerge.swift

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions CollectionBenchmarks/Sources/CollectionBenchmarks/main.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Automerge
import CollectionsBenchmark
import Foundation
import Automerge
import Loro

// NOTE(heckj): collections-benchmark implementations can be a bit hard to understand
Expand Down Expand Up @@ -124,7 +124,7 @@ benchmark.addSimple(
_ = try! text.splice(pos: stringLength, len: 0, s: strChar)
stringLength = text.lenUnicode()
}

let resultingString = text.toString()
// precondition(stringLength == input.count) // NOT VALID - difference in UTF-8 codepoints and how strings represent
// lengths
Expand Down
7 changes: 4 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ if ProcessInfo.processInfo.environment["LOCAL_BUILD"] != nil {
} else {
FFIbinaryTarget = .binaryTarget(
name: "automergeFFI",
url: "https://github.com/automerge/automerge-swift/releases/download/0.5.17/automergeFFI.xcframework.zip",
checksum: "fb2a6fc45b427c87f39d11cf749c6f59052579996eae3b4881df69b1c25cbd5f"
url: "https://github.com/automerge/automerge-swift/releases/download/0.5.19/automergeFFI.xcframework.zip",
checksum: "93ec4afb778d36d057a360d57af114e2d6e1f5c70c0df4c3c930c8c03aabae2d"
)
}

Expand Down Expand Up @@ -102,5 +102,6 @@ let package = Package(
dependencies: ["Automerge", "AutomergeUtilities"],
exclude: ["Fixtures"]
),
]
],
swiftLanguageVersions: [.version("6"), .v5]
)
8 changes: 3 additions & 5 deletions Sources/Automerge/Document.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ public final class Document: @unchecked Sendable {
try work()
}
#endif

#if canImport(Combine)
private let objectDidChangeSubject: PassthroughSubject<(), Never> = .init()
private let objectDidChangeSubject: PassthroughSubject<Void, Never> = .init()

/// A publisher that emits after the document has changed.
///
Expand All @@ -48,9 +48,7 @@ public final class Document: @unchecked Sendable {
/// processChanges(changes)
/// }
/// }.store(in: &cancellables)
public lazy var objectDidChange: AnyPublisher<(), Never> = {
objectDidChangeSubject.eraseToAnyPublisher()
}()
public lazy var objectDidChange: AnyPublisher<Void, Never> = objectDidChangeSubject.eraseToAnyPublisher()
#endif

var reportingLogLevel: LogVerbosity
Expand Down
11 changes: 0 additions & 11 deletions Sources/Automerge/Errors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,6 @@ public struct DocError: LocalizedError {
}
}

extension FfiDocError: LocalizedError {
public var errorDescription: String? {
switch self {
case let .WrongObjectType(message: msg):
return "WrongObjectType: \(msg)"
case let .Internal(message: msg):
return "AutomergeCore Internal Error: \(msg)"
}
}
}

/// An error that indicates the synchronisation state could not be decoded.
///
/// The error is specific to the Rust language binding infrastructure.
Expand Down
33 changes: 25 additions & 8 deletions Tests/AutomergeTests/BoundTypeTests/TestCounter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,24 +39,42 @@ class CounterTestCase: XCTestCase {
_ = doc2.save()

let counter1 = try doc1.get(obj: ObjId.ROOT, key: "counter")
assertNonFatal(counter1 == Value.Scalar(.Counter(3)), "Test failure illustrating put doesn't merge the same as increment [\(counter1!) != \(Value.Scalar(.Counter(3)))]")
assertNonFatal(
counter1 == Value.Scalar(.Counter(3)),
"Test failure illustrating put doesn't merge the same as increment [\(counter1!) != \(Value.Scalar(.Counter(3)))]"
)
let counter2 = try doc2.get(obj: ObjId.ROOT, key: "counter")
assertNonFatal(counter2 == Value.Scalar(.Counter(-1)), "Test failure illustrating put doesn't merge the same as increment [\(counter2!) != \(Value.Scalar(.Counter(-1)))]")
assertNonFatal(
counter2 == Value.Scalar(.Counter(-1)),
"Test failure illustrating put doesn't merge the same as increment [\(counter2!) != \(Value.Scalar(.Counter(-1)))]"
)

try doc1.merge(other: doc2)

let counter3 = try doc1.get(obj: ObjId.ROOT, key: "counter")
assertNonFatal(counter3 == Value.Scalar(.Counter(2)), "Test failure illustrating put doesn't merge the same as increment [\(counter3!) != \(Value.Scalar(.Counter(2)))]")
assertNonFatal(
counter3 == Value.Scalar(.Counter(2)),
"Test failure illustrating put doesn't merge the same as increment [\(counter3!) != \(Value.Scalar(.Counter(2)))]"
)
let counter4 = try doc2.get(obj: ObjId.ROOT, key: "counter")
assertNonFatal(counter4 == Value.Scalar(.Counter(-1)), "Test failure illustrating put doesn't merge the same as increment [\(counter4!) != \(Value.Scalar(.Counter(-1)))]")

assertNonFatal(
counter4 == Value.Scalar(.Counter(-1)),
"Test failure illustrating put doesn't merge the same as increment [\(counter4!) != \(Value.Scalar(.Counter(-1)))]"
)

try doc2.merge(other: doc1)

let counter5 = try doc1.get(obj: ObjId.ROOT, key: "counter")
assertNonFatal(counter5 == Value.Scalar(.Counter(2)), "Test failure illustrating put doesn't merge the same as increment [\(counter5!) != \(Value.Scalar(.Counter(2)))]")
assertNonFatal(
counter5 == Value.Scalar(.Counter(2)),
"Test failure illustrating put doesn't merge the same as increment [\(counter5!) != \(Value.Scalar(.Counter(2)))]"
)

let counter6 = try doc2.get(obj: ObjId.ROOT, key: "counter")
assertNonFatal(counter6 == Value.Scalar(.Counter(2)), "Test failure illustrating put doesn't merge the same as increment [\(counter6!) != \(Value.Scalar(.Counter(2)))]")
assertNonFatal(
counter6 == Value.Scalar(.Counter(2)),
"Test failure illustrating put doesn't merge the same as increment [\(counter6!) != \(Value.Scalar(.Counter(2)))]"
)
}
}

Expand All @@ -66,4 +84,3 @@ private extension XCTestCase {
print("\(message) at \(file):\(line)")
}
}

59 changes: 59 additions & 0 deletions Tests/AutomergeTests/CheckForMemoryLeaksTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS)
import Automerge
import XCTest

class MemoryLeakTests: XCTestCase {
@MainActor func testMemoryLeakOnSyncTwoDocs() {
let doc1 = Document()
trackForMemoryLeak(instance: doc1)
let syncState1 = SyncState()

let doc2 = Document()
trackForMemoryLeak(instance: doc2)
let syncState2 = SyncState()

try! doc1.put(obj: ObjId.ROOT, key: "key1", value: .String("value1"))
try! doc2.put(obj: ObjId.ROOT, key: "key2", value: .String("value2"))

sync(doc1, syncState1, doc2, syncState2)

for doc in [doc1, doc2] {
XCTAssertEqual(try! doc.get(obj: ObjId.ROOT, key: "key1")!, .Scalar(.String("value1")))
XCTAssertEqual(try! doc.get(obj: ObjId.ROOT, key: "key2")!, .Scalar(.String("value2")))
}

XCTAssertNotNil(syncState1.theirHeads)
}

@MainActor func testEncodeDoesntLeak() throws {
let doc = Document()
trackForMemoryLeak(instance: doc)

struct SimpleStruct: Codable, Equatable {
let name: String
let notes: AutomergeText
}

let automergeEncoder = AutomergeEncoder(doc: doc)
let automergeDecoder = AutomergeDecoder(doc: doc)

let sample = SimpleStruct(
name: "henry",
notes: AutomergeText("Something wicked this way comes.")
)

let pathToTry: [AnyCodingKey] = [
AnyCodingKey("example"),
AnyCodingKey(0),
]
try automergeEncoder.encode(sample, at: pathToTry)

XCTAssertNotNil(try doc.get(obj: ObjId.ROOT, key: "example"))
let foo = try doc.lookupPath(path: ".example.[0]")
XCTAssertNotNil(foo)

let decodedStruct = try automergeDecoder.decode(SimpleStruct.self, from: pathToTry)
XCTAssertEqual(decodedStruct, sample)
}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import XCTest
final class AutomergeTargettedEncodeDecodeTests: XCTestCase {
func testSimpleKeyEncode() throws {
let doc = Document()
trackForMemoryLeak(instance: doc)

struct SimpleStruct: Codable, Equatable {
let name: String
Expand Down Expand Up @@ -35,7 +34,6 @@ final class AutomergeTargettedEncodeDecodeTests: XCTestCase {

func testTargetedSingleValueDecode() throws {
let doc = Document()
trackForMemoryLeak(instance: doc)

struct SimpleStruct: Codable, Equatable {
let name: String
Expand Down Expand Up @@ -68,7 +66,6 @@ final class AutomergeTargettedEncodeDecodeTests: XCTestCase {

func testTargetedDecodeOfData() throws {
let doc = Document()
trackForMemoryLeak(instance: doc)

let exampleData = Data("Hello".utf8)
try doc.put(obj: ObjId.ROOT, key: "data", value: .Bytes(exampleData))
Expand All @@ -80,7 +77,6 @@ final class AutomergeTargettedEncodeDecodeTests: XCTestCase {

func testTargetedDecodeOfDate() throws {
let doc = Document()
trackForMemoryLeak(instance: doc)

let earlyDate = Date(timeIntervalSince1970: 0)
try doc.put(obj: ObjId.ROOT, key: "date", value: .Timestamp(earlyDate))
Expand All @@ -92,7 +88,6 @@ final class AutomergeTargettedEncodeDecodeTests: XCTestCase {

func testTargetedDecodeOfCounter() throws {
let doc = Document()
trackForMemoryLeak(instance: doc)

let exampleCounter = Counter(342)
try doc.put(obj: ObjId.ROOT, key: "counter", value: .Counter(342))
Expand All @@ -104,7 +99,6 @@ final class AutomergeTargettedEncodeDecodeTests: XCTestCase {

func testTargetedDecodeOfInts() throws {
let doc = Document()
trackForMemoryLeak(instance: doc)

try doc.put(obj: ObjId.ROOT, key: "int", value: .Int(34))

Expand All @@ -119,7 +113,6 @@ final class AutomergeTargettedEncodeDecodeTests: XCTestCase {

func testTargetedDecodeOfUInts() throws {
let doc = Document()
trackForMemoryLeak(instance: doc)

try doc.put(obj: ObjId.ROOT, key: "int", value: .Uint(34))

Expand All @@ -134,7 +127,6 @@ final class AutomergeTargettedEncodeDecodeTests: XCTestCase {

func testTargetedDecodeOfFloats() throws {
let doc = Document()
trackForMemoryLeak(instance: doc)

try doc.put(obj: ObjId.ROOT, key: "double", value: .F64(3.4))

Expand All @@ -146,7 +138,6 @@ final class AutomergeTargettedEncodeDecodeTests: XCTestCase {

func testTargetedDecodeOfOptionalInt() throws {
let doc = Document()
trackForMemoryLeak(instance: doc)

try doc.put(obj: ObjId.ROOT, key: "int", value: .Int(34))

Expand Down
8 changes: 4 additions & 4 deletions Tests/AutomergeTests/CodableTests/Samples.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import Foundation

public enum Samples {
public static var layered = ExampleModel(title: "Samples", notes: generateSampleNotes())
public static let layered = ExampleModel(title: "Samples", notes: generateSampleNotes())
}

public struct GeoLocation: Hashable, Codable {
public struct GeoLocation: Hashable, Codable, Sendable {
var latitude: Double
var longitude: Double
var altitude: Double?
Expand All @@ -20,7 +20,7 @@ public struct GeoLocation: Hashable, Codable {
}
}

public struct Note: Hashable, Codable {
public struct Note: Hashable, Codable, Sendable {
var timestamp: Date
var description: String
var location: GeoLocation
Expand All @@ -34,7 +34,7 @@ public struct Note: Hashable, Codable {
}
}

public struct ExampleModel: Codable, Equatable {
public struct ExampleModel: Codable, Equatable, Sendable {
var title: String
var notes: [Note]

Expand Down
2 changes: 0 additions & 2 deletions Tests/AutomergeTests/TestSync.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@ import XCTest
class SyncTests: XCTestCase {
func testSyncTwoDocs() {
let doc1 = Document()
trackForMemoryLeak(instance: doc1)
let syncState1 = SyncState()

let doc2 = Document()
trackForMemoryLeak(instance: doc2)
let syncState2 = SyncState()

try! doc1.put(obj: ObjId.ROOT, key: "key1", value: .String("value1"))
Expand Down
1 change: 0 additions & 1 deletion Tests/AutomergeTests/TestWasmIntegrity.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import Automerge
import XCTest

class WasmIntegriy: XCTestCase {

func testTextValueEncodingBetweenPlatforms() throws {
let doc = Document()
let textId = try doc.putObject(obj: .ROOT, key: "text", ty: .Text)
Expand Down
2 changes: 1 addition & 1 deletion Tests/AutomergeTests/XCTestCase+MemoryLeakTracking.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import XCTest

extension XCTestCase {
func trackForMemoryLeak(
@MainActor func trackForMemoryLeak(
instance: AnyObject,
file: StaticString = #filePath,
line: UInt = #line
Expand Down
Loading