diff --git a/Sources/Loro/Container.swift b/Sources/Loro/Container.swift index 49512ae..4ba57bf 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,50 @@ 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) + } + + public func push(v: LoroValueLike?) throws { + try self.push(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 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) + } +} 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()