Implement safe interface for unowned NdbNotes
This commit introduces a new interface that makes it easier and safer to handle unowned NostrDB notes, by leveraging new non-copyable and borrow features from modern Swift. Changelog-None Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit is contained in:
@@ -1090,6 +1090,10 @@
|
|||||||
D72E127A2BEEEED000F4F781 /* NostrFilterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D72E12792BEEEED000F4F781 /* NostrFilterTests.swift */; };
|
D72E127A2BEEEED000F4F781 /* NostrFilterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D72E12792BEEEED000F4F781 /* NostrFilterTests.swift */; };
|
||||||
D7315A2A2ACDF3B70036E30A /* DamusCacheManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7315A292ACDF3B70036E30A /* DamusCacheManager.swift */; };
|
D7315A2A2ACDF3B70036E30A /* DamusCacheManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7315A292ACDF3B70036E30A /* DamusCacheManager.swift */; };
|
||||||
D7315A2C2ACDF4DA0036E30A /* DamusCacheManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7315A2B2ACDF4DA0036E30A /* DamusCacheManagerTests.swift */; };
|
D7315A2C2ACDF4DA0036E30A /* DamusCacheManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7315A2B2ACDF4DA0036E30A /* DamusCacheManagerTests.swift */; };
|
||||||
|
D733F9E52D92C76100317B11 /* UnownedNdbNote.swift in Sources */ = {isa = PBXBuildFile; fileRef = D733F9E42D92C75C00317B11 /* UnownedNdbNote.swift */; };
|
||||||
|
D733F9E62D92C76100317B11 /* UnownedNdbNote.swift in Sources */ = {isa = PBXBuildFile; fileRef = D733F9E42D92C75C00317B11 /* UnownedNdbNote.swift */; };
|
||||||
|
D733F9E72D92C76100317B11 /* UnownedNdbNote.swift in Sources */ = {isa = PBXBuildFile; fileRef = D733F9E42D92C75C00317B11 /* UnownedNdbNote.swift */; };
|
||||||
|
D733F9E82D92C76100317B11 /* UnownedNdbNote.swift in Sources */ = {isa = PBXBuildFile; fileRef = D733F9E42D92C75C00317B11 /* UnownedNdbNote.swift */; };
|
||||||
D734B1452CCC19B1000B5C97 /* DamusFullScreenCover.swift in Sources */ = {isa = PBXBuildFile; fileRef = D734B1442CCC19B1000B5C97 /* DamusFullScreenCover.swift */; };
|
D734B1452CCC19B1000B5C97 /* DamusFullScreenCover.swift in Sources */ = {isa = PBXBuildFile; fileRef = D734B1442CCC19B1000B5C97 /* DamusFullScreenCover.swift */; };
|
||||||
D734B1462CCC19B1000B5C97 /* DamusFullScreenCover.swift in Sources */ = {isa = PBXBuildFile; fileRef = D734B1442CCC19B1000B5C97 /* DamusFullScreenCover.swift */; };
|
D734B1462CCC19B1000B5C97 /* DamusFullScreenCover.swift in Sources */ = {isa = PBXBuildFile; fileRef = D734B1442CCC19B1000B5C97 /* DamusFullScreenCover.swift */; };
|
||||||
D7373BA62B688EA300F7783D /* DamusPurpleTranslationSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7373BA52B688EA200F7783D /* DamusPurpleTranslationSetupView.swift */; };
|
D7373BA62B688EA300F7783D /* DamusPurpleTranslationSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7373BA52B688EA200F7783D /* DamusPurpleTranslationSetupView.swift */; };
|
||||||
@@ -2477,6 +2481,7 @@
|
|||||||
D72E12792BEEEED000F4F781 /* NostrFilterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NostrFilterTests.swift; sourceTree = "<group>"; };
|
D72E12792BEEEED000F4F781 /* NostrFilterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NostrFilterTests.swift; sourceTree = "<group>"; };
|
||||||
D7315A292ACDF3B70036E30A /* DamusCacheManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusCacheManager.swift; sourceTree = "<group>"; };
|
D7315A292ACDF3B70036E30A /* DamusCacheManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusCacheManager.swift; sourceTree = "<group>"; };
|
||||||
D7315A2B2ACDF4DA0036E30A /* DamusCacheManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusCacheManagerTests.swift; sourceTree = "<group>"; };
|
D7315A2B2ACDF4DA0036E30A /* DamusCacheManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusCacheManagerTests.swift; sourceTree = "<group>"; };
|
||||||
|
D733F9E42D92C75C00317B11 /* UnownedNdbNote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnownedNdbNote.swift; sourceTree = "<group>"; };
|
||||||
D734B1442CCC19B1000B5C97 /* DamusFullScreenCover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusFullScreenCover.swift; sourceTree = "<group>"; };
|
D734B1442CCC19B1000B5C97 /* DamusFullScreenCover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusFullScreenCover.swift; sourceTree = "<group>"; };
|
||||||
D7373BA52B688EA200F7783D /* DamusPurpleTranslationSetupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusPurpleTranslationSetupView.swift; sourceTree = "<group>"; };
|
D7373BA52B688EA200F7783D /* DamusPurpleTranslationSetupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusPurpleTranslationSetupView.swift; sourceTree = "<group>"; };
|
||||||
D7373BA72B68974500F7783D /* DamusPurpleNewUserOnboardingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusPurpleNewUserOnboardingView.swift; sourceTree = "<group>"; };
|
D7373BA72B68974500F7783D /* DamusPurpleNewUserOnboardingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusPurpleNewUserOnboardingView.swift; sourceTree = "<group>"; };
|
||||||
@@ -3359,6 +3364,7 @@
|
|||||||
4C9054862A6AEB4500811EEC /* nostrdb */ = {
|
4C9054862A6AEB4500811EEC /* nostrdb */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
D733F9E42D92C75C00317B11 /* UnownedNdbNote.swift */,
|
||||||
4C47928D2A9939BD00489948 /* flatcc */,
|
4C47928D2A9939BD00489948 /* flatcc */,
|
||||||
4C478E2A2A9935D300489948 /* bindings */,
|
4C478E2A2A9935D300489948 /* bindings */,
|
||||||
4CE9FBBB2A6B3D9C007E485C /* Test */,
|
4CE9FBBB2A6B3D9C007E485C /* Test */,
|
||||||
@@ -4927,6 +4933,7 @@
|
|||||||
4C9AA14A2A4587A6003F49FD /* NotificationStatusModel.swift in Sources */,
|
4C9AA14A2A4587A6003F49FD /* NotificationStatusModel.swift in Sources */,
|
||||||
D7100C5C2B77016700C59298 /* IAPProductStateView.swift in Sources */,
|
D7100C5C2B77016700C59298 /* IAPProductStateView.swift in Sources */,
|
||||||
4CB9D4A72992D02B00A9A7E4 /* ProfileNameView.swift in Sources */,
|
4CB9D4A72992D02B00A9A7E4 /* ProfileNameView.swift in Sources */,
|
||||||
|
D733F9E82D92C76100317B11 /* UnownedNdbNote.swift in Sources */,
|
||||||
D74EA0902D2E271E002290DD /* ErrorView.swift in Sources */,
|
D74EA0902D2E271E002290DD /* ErrorView.swift in Sources */,
|
||||||
4CE4F0F429D779B5005914DB /* PostBox.swift in Sources */,
|
4CE4F0F429D779B5005914DB /* PostBox.swift in Sources */,
|
||||||
BA37598E2ABCCE500018D73B /* VideoCaptureProcessor.swift in Sources */,
|
BA37598E2ABCCE500018D73B /* VideoCaptureProcessor.swift in Sources */,
|
||||||
@@ -5292,6 +5299,7 @@
|
|||||||
82D6FBBA2CD99F7900C925F4 /* NostrRequest.swift in Sources */,
|
82D6FBBA2CD99F7900C925F4 /* NostrRequest.swift in Sources */,
|
||||||
82D6FBBB2CD99F7900C925F4 /* Profiles.swift in Sources */,
|
82D6FBBB2CD99F7900C925F4 /* Profiles.swift in Sources */,
|
||||||
82D6FBBC2CD99F7900C925F4 /* NostrKind.swift in Sources */,
|
82D6FBBC2CD99F7900C925F4 /* NostrKind.swift in Sources */,
|
||||||
|
D733F9E62D92C76100317B11 /* UnownedNdbNote.swift in Sources */,
|
||||||
82D6FBBD2CD99F7900C925F4 /* NostrLink.swift in Sources */,
|
82D6FBBD2CD99F7900C925F4 /* NostrLink.swift in Sources */,
|
||||||
82D6FBBE2CD99F7900C925F4 /* WebSocket.swift in Sources */,
|
82D6FBBE2CD99F7900C925F4 /* WebSocket.swift in Sources */,
|
||||||
82D6FBBF2CD99F7900C925F4 /* ReferencedId.swift in Sources */,
|
82D6FBBF2CD99F7900C925F4 /* ReferencedId.swift in Sources */,
|
||||||
@@ -5604,6 +5612,7 @@
|
|||||||
D73E5E882C6A97F4007EB227 /* StoreObserver.swift in Sources */,
|
D73E5E882C6A97F4007EB227 /* StoreObserver.swift in Sources */,
|
||||||
D73E5E892C6A97F4007EB227 /* DamusPurpleURL.swift in Sources */,
|
D73E5E892C6A97F4007EB227 /* DamusPurpleURL.swift in Sources */,
|
||||||
D73E5E8A2C6A97F4007EB227 /* PurpleStoreKitManager.swift in Sources */,
|
D73E5E8A2C6A97F4007EB227 /* PurpleStoreKitManager.swift in Sources */,
|
||||||
|
D733F9E72D92C76100317B11 /* UnownedNdbNote.swift in Sources */,
|
||||||
D73E5E8E2C6A97F4007EB227 /* ImageResizer.swift in Sources */,
|
D73E5E8E2C6A97F4007EB227 /* ImageResizer.swift in Sources */,
|
||||||
D78F080E2D7F78EF00FC6C75 /* Request.swift in Sources */,
|
D78F080E2D7F78EF00FC6C75 /* Request.swift in Sources */,
|
||||||
D73E5E8F2C6A97F4007EB227 /* PhotoCaptureProcessor.swift in Sources */,
|
D73E5E8F2C6A97F4007EB227 /* PhotoCaptureProcessor.swift in Sources */,
|
||||||
@@ -5989,6 +5998,7 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
4C8FA7242BED58A900798A6A /* ThreadReply.swift in Sources */,
|
4C8FA7242BED58A900798A6A /* ThreadReply.swift in Sources */,
|
||||||
|
D733F9E52D92C76100317B11 /* UnownedNdbNote.swift in Sources */,
|
||||||
D798D21F2B0858D600234419 /* MigratedTypes.swift in Sources */,
|
D798D21F2B0858D600234419 /* MigratedTypes.swift in Sources */,
|
||||||
D7CE1B472B0BE719002EDAD4 /* NativeObject.swift in Sources */,
|
D7CE1B472B0BE719002EDAD4 /* NativeObject.swift in Sources */,
|
||||||
D71AD9002CEC176A002E2C3C /* AppAccessibilityIdentifiers.swift in Sources */,
|
D71AD9002CEC176A002E2C3C /* AppAccessibilityIdentifiers.swift in Sources */,
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ extension NIP65 {
|
|||||||
// MARK: - Initialization
|
// MARK: - Initialization
|
||||||
|
|
||||||
init(event: NdbNote) throws(NIP65DecodingError) {
|
init(event: NdbNote) throws(NIP65DecodingError) {
|
||||||
|
try self.init(event: UnownedNdbNote(event))
|
||||||
|
}
|
||||||
|
|
||||||
|
init(event: borrowing UnownedNdbNote) throws(NIP65DecodingError) {
|
||||||
guard event.known_kind == .relay_list else { throw .notRelayList }
|
guard event.known_kind == .relay_list else { throw .notRelayList }
|
||||||
var relays: [RelayItem] = []
|
var relays: [RelayItem] = []
|
||||||
for tag in event.tags {
|
for tag in event.tags {
|
||||||
|
|||||||
78
nostrdb/UnownedNdbNote.swift
Normal file
78
nostrdb/UnownedNdbNote.swift
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
//
|
||||||
|
// UnownedNdbNote.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by Daniel D’Aquino on 2025-03-25.
|
||||||
|
//
|
||||||
|
|
||||||
|
/// A function that allows an unowned NdbNote to be lent out temporarily
|
||||||
|
///
|
||||||
|
/// Use this to provide access to NostrDB unowned notes in a way that has much better compile-time safety guarantees.
|
||||||
|
///
|
||||||
|
/// # Usage examples
|
||||||
|
///
|
||||||
|
/// ## Lending out or providing Ndb notes
|
||||||
|
///
|
||||||
|
/// ```swift
|
||||||
|
/// // Define the lender
|
||||||
|
/// let lender: NdbNoteLender = { lend in
|
||||||
|
/// guard let ndbNoteTxn = ndb.lookup_note(noteId) else { // Note: Must have access to `Ndb`
|
||||||
|
/// throw NdbNoteLenderError.errorLoadingNote // Throw errors if loading fails
|
||||||
|
/// }
|
||||||
|
/// guard let unownedNote = UnownedNdbNote(ndbNoteTxn) else {
|
||||||
|
/// throw NdbNoteLenderError.errorLoadingNote
|
||||||
|
/// }
|
||||||
|
/// lend(unownedNote) // Lend out the Unowned Ndb note
|
||||||
|
/// }
|
||||||
|
/// return lender // Return or pass the lender to another class
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## Borrowing Ndb notes
|
||||||
|
///
|
||||||
|
/// Assuming you are given a lender, here is how you can use it:
|
||||||
|
///
|
||||||
|
/// ```swift
|
||||||
|
/// let borrow: NdbNoteLender = functionThatProvidesALender()
|
||||||
|
/// try? borrow { note in // You can optionally handle errors if borrowing fails
|
||||||
|
/// self.date = note.createdAt // You can do things with the note without copying it over
|
||||||
|
/// // self.note = note // Not allowed by the compiler
|
||||||
|
/// self.note = note.toOwned() // You can copy the note if needed
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
typealias NdbNoteLender = ((_: borrowing UnownedNdbNote) -> Void) throws -> Void
|
||||||
|
|
||||||
|
enum NdbNoteLenderError: Error {
|
||||||
|
case errorLoadingNote
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// A wrapper to NdbNote that allows unowned NdbNotes to be safely handled
|
||||||
|
struct UnownedNdbNote: ~Copyable {
|
||||||
|
private let _ndbNote: NdbNote
|
||||||
|
|
||||||
|
init(_ txn: NdbTxn<NdbNote>) {
|
||||||
|
self._ndbNote = txn.unsafeUnownedValue
|
||||||
|
}
|
||||||
|
|
||||||
|
init?(_ txn: NdbTxn<NdbNote?>) {
|
||||||
|
guard let note = txn.unsafeUnownedValue else { return nil }
|
||||||
|
self._ndbNote = note
|
||||||
|
}
|
||||||
|
|
||||||
|
init(_ ndbNote: NdbNote) {
|
||||||
|
self._ndbNote = ndbNote
|
||||||
|
}
|
||||||
|
|
||||||
|
var kind: UInt32 { _ndbNote.kind }
|
||||||
|
var known_kind: NostrKind? { _ndbNote.known_kind }
|
||||||
|
var content: String { _ndbNote.content }
|
||||||
|
var tags: TagsSequence { _ndbNote.tags }
|
||||||
|
var pubkey: Pubkey { _ndbNote.pubkey }
|
||||||
|
var createdAt: UInt32 { _ndbNote.created_at }
|
||||||
|
var id: NoteId { _ndbNote.id }
|
||||||
|
var sig: Signature { _ndbNote.sig }
|
||||||
|
|
||||||
|
func toOwned() -> NdbNote {
|
||||||
|
return _ndbNote.to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user