From f4fe39747829201491c57d054a2c7f710c0ec556 Mon Sep 17 00:00:00 2001 From: Leon Zhao Date: Mon, 3 Mar 2025 11:55:52 +0800 Subject: [PATCH 1/2] fix: nil as input --- Sources/Loro/Container.swift | 28 ++++++++++++++++++++++++++-- Sources/Loro/Value.swift | 10 ++++++++++ Tests/LoroTests/LoroTests.swift | 15 +++++++++++++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/Sources/Loro/Container.swift b/Sources/Loro/Container.swift index 49512ae..7bf1523 100644 --- a/Sources/Loro/Container.swift +++ b/Sources/Loro/Container.swift @@ -129,8 +129,6 @@ extension LoroMovableList: ContainerLike{ return typedResult } } -extension LoroCounter: ContainerLike{} -extension LoroUnknown: ContainerLike{} extension LoroList: ContainerLike{ @@ -163,5 +161,31 @@ extension LoroList: ContainerLike{ } } +extension LoroCounter: ContainerLike{} +extension LoroUnknown: ContainerLike{} + +// Extension for handling nil input +// Although we extend Optional, we still need to specify the type explicitly +// e.g. `nil as String?`. This is not convenient in some scenarios. +extension LoroList{ + public func insert(pos: UInt32, v: LoroValueLike?) throws { + try self.insert(pos: pos, v: v?.asLoroValue() ?? .null) + } +} + +extension LoroMap{ + public func insert(key: String, v: LoroValueLike?) throws { + try self.insert(key: key, v: v?.asLoroValue() ?? .null) + } +} +extension LoroMovableList{ + public func insert(pos: UInt32, v: LoroValueLike?) throws { + try self.insert(pos: pos, v: v?.asLoroValue() ?? .null) + } + + public func set(pos: UInt32, v: LoroValueLike?) throws { + try self.set(pos: pos, value: v?.asLoroValue() ?? .null) + } +} diff --git a/Sources/Loro/Value.swift b/Sources/Loro/Value.swift index 5c07098..6737485 100644 --- a/Sources/Loro/Value.swift +++ b/Sources/Loro/Value.swift @@ -12,6 +12,16 @@ extension LoroValue: LoroValueLike { } } +extension Optional: LoroValueLike where Wrapped: LoroValueLike { + public func asLoroValue() -> LoroValue { + if let value = self { + return value.asLoroValue() + } else { + return .null + } + } +} + extension Bool: LoroValueLike{ public func asLoroValue() -> LoroValue { return LoroValue.bool(value: self) diff --git a/Tests/LoroTests/LoroTests.swift b/Tests/LoroTests/LoroTests.swift index 7db63b6..952001a 100644 --- a/Tests/LoroTests/LoroTests.swift +++ b/Tests/LoroTests/LoroTests.swift @@ -14,6 +14,21 @@ final class LoroTests: XCTestCase { sub.detach() XCTAssertEqual(num, 1) } + + func testOptional(){ + let doc = LoroDoc() + let list = doc.getList(id: "list") + try! list.insert(pos: 0, v: nil) + let map = doc.getMap(id: "map") + try! map.insert(key: "key", v: nil) + let movableList = doc.getMovableList(id: "movableList") + try! movableList.insert(pos: 0, v: nil) + try! movableList.set(pos: 0, v: nil) + doc.commit() + XCTAssertEqual(list.get(index: 0)!.asValue()!, LoroValue.null) + XCTAssertEqual(map.get(key: "key")!.asValue()!, LoroValue.null) + XCTAssertEqual(movableList.get(index: 0)!.asValue()!, LoroValue.null) + } func testText(){ let doc = LoroDoc() From 495a1b43a12388d1565cdd152e55c184c7b7e7f5 Mon Sep 17 00:00:00 2001 From: Leon Zhao Date: Mon, 3 Mar 2025 13:39:21 +0800 Subject: [PATCH 2/2] fix: more nil loro value --- Sources/Loro/Container.swift | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Sources/Loro/Container.swift b/Sources/Loro/Container.swift index 7bf1523..4ba57bf 100644 --- a/Sources/Loro/Container.swift +++ b/Sources/Loro/Container.swift @@ -171,6 +171,10 @@ extension LoroList{ public func insert(pos: UInt32, v: LoroValueLike?) throws { try self.insert(pos: pos, v: v?.asLoroValue() ?? .null) } + + public func push(v: LoroValueLike?) throws { + try self.push(v: v?.asLoroValue() ?? .null) + } } extension LoroMap{ @@ -184,8 +188,23 @@ extension LoroMovableList{ try self.insert(pos: pos, v: v?.asLoroValue() ?? .null) } + public func push(v: LoroValueLike?) throws { + try self.push(v: v?.asLoroValue() ?? .null) + } + public func set(pos: UInt32, v: LoroValueLike?) throws { try self.set(pos: pos, value: v?.asLoroValue() ?? .null) } } +extension LoroText{ + public func mark(from: UInt32, to: UInt32, key: String, value: LoroValueLike?) throws { + try self.mark(from: from, to: to, key: key, value: value?.asLoroValue() ?? .null) + } +} + +extension Awareness{ + public func setLocalState(value: LoroValueLike?){ + self.setLocalState(value: value?.asLoroValue() ?? .null) + } +}