Skip to content

Commit 9a93056

Browse files
committed
feat: Reloadable modules in DIScope
fix: Make di close idempotent
1 parent 47b0497 commit 9a93056

File tree

2 files changed

+39
-13
lines changed

2 files changed

+39
-13
lines changed

core/src/commonMain/kotlin/com/mineinabyss/dependencies/DIScope.kt

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import co.touchlab.kermit.Logger
44

55
class DIScope(root: MutableDI.() -> Unit = {}) : DIAware, AutoCloseable {
66
private val _loaded = mutableMapOf<DI.Module.Key, DI>()
7-
val loaded: List<DI.Module> = _loaded.keys.filterIsInstance<DI.Module>()
7+
private val loadOrder = mutableListOf<DI.Module>()
8+
val loaded: List<DI.Module> get() = loadOrder.toList()
89

910
val root = DI.invoke(this) {
1011
single<DIScope>(ignoreOverride = true) { this@DIScope }
@@ -15,7 +16,7 @@ class DIScope(root: MutableDI.() -> Unit = {}) : DIAware, AutoCloseable {
1516
val logger by lazy { getOrNull<Logger>() ?: Logger }
1617

1718
fun <T> load(feature: DI.ModuleWithConfig<T>, configure: T.() -> Unit): DI {
18-
return load(module("$feature-configuration") {
19+
return load(module("${feature.name}-configuration") {
1920
feature.get(singleModule(feature)).configure()
2021
})
2122
}
@@ -25,14 +26,18 @@ class DIScope(root: MutableDI.() -> Unit = {}) : DIAware, AutoCloseable {
2526
if (key in _loaded) return _loaded.getValue(key)
2627
val created = feature.create(root)
2728
_loaded[key] = created
28-
created.addCloseable { _loaded.remove(key) }
29+
loadOrder += feature
30+
created.addCloseable {
31+
_loaded.remove(key)
32+
loadOrder.remove(feature)
33+
logger.i { "Unloaded feature $feature" }
34+
}
35+
logger.i { "Loaded feature $feature" }
2936
return created
3037
}
3138

3239
fun loadCatching(feature: DI.Module): Result<DI> {
33-
return runCatching { load(feature) }.onSuccess {
34-
logger.i { "Loaded feature $feature" }
35-
}.onFailure {
40+
return runCatching { load(feature) }.onFailure {
3641
if (it is IllegalArgumentException) {
3742
logger.e { "Failed to load feature $feature: ${it.message}" }
3843
} else {
@@ -49,6 +54,25 @@ class DIScope(root: MutableDI.() -> Unit = {}) : DIAware, AutoCloseable {
4954
modules.forEach { loadCatching(it) }
5055
}
5156

57+
fun reload(module: DI.Module) {
58+
val beforeUnload = loadOrder.toList()
59+
unload(module)
60+
val unloadedDependencies = beforeUnload.minus(loadOrder.toSet())
61+
loadAll(*unloadedDependencies.toTypedArray())
62+
}
63+
64+
fun reload(vararg module: DI.Module) {
65+
val beforeUnload = loadOrder.toList()
66+
module.forEach { unload(it) }
67+
val unloadedDependencies = beforeUnload.minus(loadOrder.toSet())
68+
loadAll(*unloadedDependencies.toTypedArray())
69+
}
70+
71+
fun reloadAll() {
72+
val load = loadOrder.toTypedArray()
73+
unloadAll()
74+
loadAll(*load)
75+
}
5276
operator fun get(module: DI.Module): DI? {
5377
return _loaded[module.key]?.di
5478
}
@@ -60,16 +84,15 @@ class DIScope(root: MutableDI.() -> Unit = {}) : DIAware, AutoCloseable {
6084
fun unload(feature: DI.Module) {
6185
val key = feature.key
6286
val feat = _loaded[key] ?: return
63-
runCatching { feat.close() }.onSuccess {
64-
logger.i { "Unloaded feature $feature" }
65-
}.onFailure {
66-
logger.e(it) { "Failed to unload $feature" }
67-
}
68-
_loaded.remove(key)
87+
feat.close()
88+
}
89+
90+
fun unloadAll() {
91+
loadOrder.toList().reversed().forEach { unload(it) }
6992
}
7093

7194
override fun close() {
72-
_loaded.toList().reversed().forEach { unload(it.first as DI.Module) } //TODO no cast
95+
unloadAll()
7396
}
7497

7598
companion object {

core/src/commonMain/kotlin/com/mineinabyss/dependencies/impl/MutableDIImpl.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ class MutableDIImpl(
1111
private val dependsOn = mutableSetOf<DI.Module>()
1212
private val _injected = mutableMapOf<Pair<KType, String?>, InjectedValue<*>>()
1313
override val injected get() = _injected.map { it.key to it.value }
14+
private var closed = false
1415

1516
override fun <T> Put(type: Pair<KType, String?>, property: InjectedValue<T>): InjectedValue<T> {
1617
val existing = _injected[type]
@@ -58,6 +59,8 @@ class MutableDIImpl(
5859
}
5960

6061
override fun close() {
62+
if (closed) return
63+
closed = true
6164
closeables.reversed().forEach { it.close() }
6265
}
6366
}

0 commit comments

Comments
 (0)