-
-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow to load multiple modules of the same type (#110)
# Allow to load multiple modules of the same type ## ♻️ Current situation & Problem Currently, Spezi enforces that there is maximum one module of the same type loaded at a time. By allowing the Module system to used much more dynamically via #105, we found that certain types of Modules might exist multiple times in the system (e.g., a Bluetooth device type modeled as a Spezi Module might have two physical devices connected at the same time). This PR makes the necessary infrastructure changes to support loading multiple modules of the same type. A check that the same module can only be loaded once is still in place. Restructuring the `@Dependency` to support multiple modules of the same type is not trivial and will be addressed in a follow-up PR which is tracked in #111. ## ⚙️ Release Notes * Allow to load multiple modules of the same type. ## 📚 Documentation -- ## ✅ Testing Additional unit testing was added to verify behavior. ## 📝 Code of Conduct & Contributing Guidelines By submitting creating this pull request, you agree to follow our [Code of Conduct](https://github.com/StanfordSpezi/.github/blob/main/CODE_OF_CONDUCT.md) and [Contributing Guidelines](https://github.com/StanfordSpezi/.github/blob/main/CONTRIBUTING.md): - [x] I agree to follow the [Code of Conduct](https://github.com/StanfordSpezi/.github/blob/main/CODE_OF_CONDUCT.md) and [Contributing Guidelines](https://github.com/StanfordSpezi/.github/blob/main/CONTRIBUTING.md).
- Loading branch information
Showing
16 changed files
with
345 additions
and
133 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
17 changes: 17 additions & 0 deletions
17
Sources/Spezi/Spezi/KnowledgeSources/ImplicitlyCreatedModulesKey.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// | ||
// This source file is part of the Stanford Spezi open-source project | ||
// | ||
// SPDX-FileCopyrightText: 2024 Stanford University and the project authors (see CONTRIBUTORS.md) | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
|
||
import SpeziFoundation | ||
|
||
|
||
struct ImplicitlyCreatedModulesKey: DefaultProvidingKnowledgeSource { | ||
typealias Value = Set<ModuleReference> | ||
typealias Anchor = SpeziAnchor | ||
|
||
static let defaultValue: Value = [] | ||
} |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// | ||
// This source file is part of the Stanford Spezi open-source project | ||
// | ||
// SPDX-FileCopyrightText: 2024 Stanford University and the project authors (see CONTRIBUTORS.md) | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
|
||
import SpeziFoundation | ||
|
||
|
||
/// A ``SharedRepository`` implementation that is anchored to ``SpeziAnchor``. | ||
/// | ||
/// This represents the central ``Spezi/Spezi`` storage module. | ||
@_documentation(visibility: internal) | ||
public typealias SpeziStorage = ValueRepository<SpeziAnchor> |
83 changes: 83 additions & 0 deletions
83
Sources/Spezi/Spezi/KnowledgeSources/StoredModulesKey.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
// | ||
// This source file is part of the Stanford Spezi open-source project | ||
// | ||
// SPDX-FileCopyrightText: 2024 Stanford University and the project authors (see CONTRIBUTORS.md) | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
|
||
import OrderedCollections | ||
import SpeziFoundation | ||
|
||
|
||
protocol AnyStoredModules { | ||
var anyModules: [any Module] { get } | ||
|
||
func removeNilReferences<Repository: SharedRepository<SpeziAnchor>>(in storage: inout Repository) | ||
} | ||
|
||
|
||
struct StoredModulesKey<M: Module>: KnowledgeSource { | ||
typealias Anchor = SpeziAnchor | ||
typealias Value = Self | ||
|
||
var modules: OrderedDictionary<ModuleReference, DynamicReference<M>> | ||
|
||
var isEmpty: Bool { | ||
modules.isEmpty | ||
} | ||
|
||
init(_ module: DynamicReference<M>, forKey key: ModuleReference) { | ||
modules = [key: module] | ||
} | ||
|
||
func contains(_ key: ModuleReference) -> Bool { | ||
modules[key] != nil | ||
} | ||
|
||
func retrieveFirstAvailable() -> M? { | ||
for (_, value) in modules { | ||
guard let element = value.element else { | ||
continue | ||
} | ||
return element | ||
} | ||
return nil | ||
} | ||
|
||
@discardableResult | ||
mutating func updateValue(_ module: DynamicReference<M>, forKey key: ModuleReference) -> DynamicReference<M>? { | ||
modules.updateValue(module, forKey: key) | ||
} | ||
|
||
@discardableResult | ||
mutating func removeValue(forKey key: ModuleReference) -> DynamicReference<M>? { | ||
modules.removeValue(forKey: key) | ||
} | ||
} | ||
|
||
|
||
extension StoredModulesKey: AnyStoredModules { | ||
var anyModules: [any Module] { | ||
modules.reduce(into: []) { partialResult, entry in | ||
guard let element = entry.value.element else { | ||
return | ||
} | ||
partialResult.append(element) | ||
} | ||
} | ||
|
||
func removeNilReferences<Repository: SharedRepository<SpeziAnchor>>(in storage: inout Repository) { | ||
guard modules.contains(where: { $0.value.element == nil }) else { | ||
return // no weak references | ||
} | ||
|
||
var value = self | ||
|
||
value.modules.removeAll { _, value in | ||
value.element == nil | ||
} | ||
|
||
storage[Self.self] = value | ||
} | ||
} |
Oops, something went wrong.