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

Allow to dynamically load and unload Modules #105

Merged
merged 7 commits into from
Jun 5, 2024

Conversation

Supereg
Copy link
Member

@Supereg Supereg commented Jun 4, 2024

Allow to dynamically load and unload Modules

♻️ Current situation & Problem

Currently, the collection of Modules must be defined at application start and cannot be modified later on. This PR modifies the current infrastructure to allow to dynamically load and unload modules. This functionality was identified to be useful with SpeziBluetooth (e.g., making BluetoothDevices automatically conform to Module and allowing native and out of the box support for Spezi property wrappers). Similar SpeziAccount has a similar use case, where the Account instance itself can be made a Module making easy access to the current Account possible outside of the SwiftUI view hierarchy.

Note: @Collect and @Provide properties are a bit tricky with dynamic loading and unloading. However, I think the PR introduces a relatively elegant solution for that. Upon module loading all @Collect properties are updated with new values from the @Provide properties of the loaded module. At the same time, these values are removed again if a module with a @Provide property is unloaded. There is currently no mechanism for Modules to detect if the value of a @Collect property changed and this is generally unexpected as per documentation. Therefore, no module makes use of this. We will need to evaluate if this is a use case at all (e.g., dynamically adding new account services) and if there is maybe generally a better approach for module inter-communication that better flows with dynamic loading and unloading of modules (@Provide and @Collect are currently, to my knowledge, only really used with SpeziAccount).

⚙️ Release Notes

  • Add new @Application(\.spezi) property to access the global Spezi instance.
  • Support dynamic Module loading through the Spezi/loadModule(_:) method.
  • Support dynamic Module unloading through the Spezi/unloadModule(_:) method.

📚 Documentation

Documentation catalog was updated to reflect new symbols. A small example was added in the Spezi type documentation providing an example on how to load a module.

✅ Testing

Unit tests were added to test the new functionality.

📝 Code of Conduct & Contributing Guidelines

By submitting creating this pull request, you agree to follow our Code of Conduct and Contributing Guidelines:

Copy link

codecov bot commented Jun 4, 2024

Codecov Report

Attention: Patch coverage is 94.11765% with 21 lines in your changes missing coverage. Please review.

Project coverage is 87.93%. Comparing base (c43e4fa) to head (f6be572).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #105      +/-   ##
==========================================
+ Coverage   84.97%   87.93%   +2.96%     
==========================================
  Files          41       42       +1     
  Lines         951     1217     +266     
==========================================
+ Hits          808     1070     +262     
- Misses        143      147       +4     
Files Coverage Δ
...pezi/Capabilities/ApplicationPropertyWrapper.swift 91.31% <100.00%> (+7.10%) ⬆️
...ilities/Communication/CollectPropertyWrapper.swift 100.00% <100.00%> (ø)
...ilities/Communication/ProvidePropertyWrapper.swift 100.00% <100.00%> (ø)
...bilities/Communication/StorageValueCollector.swift 100.00% <ø> (ø)
...abilities/Communication/StorageValueProvider.swift 100.00% <ø> (ø)
...Capabilities/Observable/ModelPropertyWrapper.swift 58.07% <100.00%> (+4.50%) ⬆️
...ilities/ViewModifier/ModifierPropertyWrapper.swift 71.43% <100.00%> (+3.43%) ⬆️
...pabilities/ViewModifier/ViewModifierProvider.swift 100.00% <ø> (ø)
...Spezi/Dependencies/Module+DependencyRelation.swift 100.00% <100.00%> (ø)
Sources/Spezi/Dependencies/ModuleReference.swift 100.00% <100.00%> (ø)
... and 15 more

... and 1 file with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c43e4fa...f6be572. Read the comment docs.

@Supereg Supereg marked this pull request as ready for review June 4, 2024 15:57
@Supereg Supereg requested a review from PSchmiedmayer June 4, 2024 16:01
@Supereg Supereg changed the title Allow to dynamically load Modules Allow to dynamically load and unload Modules Jun 4, 2024
@Supereg
Copy link
Member Author

Supereg commented Jun 4, 2024

There is still one oversight where viewModifiers are not removed yet. However, the PR is generally reviewable 👍

Copy link
Member

@PSchmiedmayer PSchmiedmayer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice job; great to see that @Supereg!

Thanks for addressing this and once the view modifiers are removed; great addition to Spezi! 💪

Sources/Spezi/Dependencies/DependencyManager.swift Outdated Show resolved Hide resolved
Sources/Spezi/Spezi/Spezi.swift Show resolved Hide resolved
@Supereg Supereg merged commit 734f90c into main Jun 5, 2024
13 checks passed
@Supereg Supereg deleted the feature/dynamic-module-loading branch June 5, 2024 13:16
Supereg added a commit to StanfordSpezi/SpeziBluetooth that referenced this pull request Jun 5, 2024
# Inject Bluetooth Devices as Spezi Modules

## ♻️ Current situation & Problem

`BluetoothDevice`s were previously inaccessible from Spezi `Module`s
without additional infrastructure.
StanfordSpezi/Spezi#105 introduced functionality
to dynamically load and unload Modules from the Spezi module systems. We
use that new infrastructure to make every `BluetoohtDevice` to be a
Spezi Module.
This allows every `BluetoothDevice` to use the same functionality
available to Spezi Modules. Further, Spezi Modules can seamlessly
interact with `BluetoothDevice` as well.

## ⚙️ Release Notes 
* `BluetoothDevice`s are now Spezi `Module`s.


## 📚 Documentation
Additional documentation section was added.


## ✅ Testing
Verified in Engage.


## 📝 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).
Supereg added a commit that referenced this pull request Jul 23, 2024
# 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).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants