11package com.mineinabyss.dependencies
22
33import co.touchlab.kermit.Logger
4+ import com.mineinabyss.dependencies.exceptions.LoadResult
45
56class DIScope (root : MutableDI .() -> Unit = {}) : DI.Scope, DI, AutoCloseable {
67 private val _loaded = mutableMapOf<DI .Module .Key , DI >()
@@ -35,51 +36,62 @@ class DIScope(root: MutableDI.() -> Unit = {}) : DI.Scope, DI, AutoCloseable {
3536 created.addCloseable {
3637 _loaded .remove(key)
3738 loadOrder.remove(module)
38- logger.i { " Unloaded feature $module " }
39+ logger.i { " Unloaded module $module " }
3940 }
40- logger.i { " Loaded feature $module " }
41+ logger.i { " Loaded module $module " }
4142 return created
4243 }
4344
4445 fun loadAll (vararg modules : DI .Module ) {
4546 modules.forEach { load(it) }
4647 }
4748
48- override fun reload (module : DI .Module ) {
49+ override fun reload (module : DI .Module ): LoadResult {
4950 val beforeUnload = loadOrder.toList()
5051 unload(module)
5152 val unloadedDependencies = beforeUnload.minus(loadOrder.toSet())
52- loadAll (* unloadedDependencies.toTypedArray())
53+ return loadAllCatching (* unloadedDependencies.toTypedArray())
5354 }
5455
55- fun reload (vararg module : DI .Module ) {
56+ fun reload (vararg module : DI .Module ): LoadResult {
5657 val beforeUnload = loadOrder.toList()
5758 module.forEach { unload(it) }
5859 val unloadedDependencies = beforeUnload.minus(loadOrder.toSet())
59- loadAll (* unloadedDependencies.toTypedArray())
60+ return loadAllCatching (* unloadedDependencies.toTypedArray())
6061 }
6162
62- fun reloadAll () {
63+ fun reloadAll (): LoadResult {
6364 val load = loadOrder.toTypedArray()
6465 unloadAll()
65- loadAll (* load)
66+ return loadAllCatching (* load)
6667 }
6768
68- operator fun get (module : DI .Module ): DI ? {
69- return _loaded [module.key]?.di
69+ fun getOrNull (module : DI .Module ): DI ? {
70+ return _loaded [module.key]?.takeIf { it != FailedModule }?. di
7071 }
7172
72- operator fun <T > get (module : DI .ModuleWithConfig <T >): T ? {
73- return _loaded [module.key]?.di?.let { module.get(it) }
73+ fun <T > getOrNull (module : DI .ModuleWithConfig <T >): T ? {
74+ return _loaded [module.key]?.takeIf { it != FailedModule }?.di?.let { module.get(it) }
75+ }
76+
77+ operator fun get (module : DI .Module ): DI {
78+ return getOrNull(module) ? : error(" Failed to get module ${module.name} " )
79+ }
80+
81+ operator fun <T > get (module : DI .ModuleWithConfig <T >): T {
82+ return getOrNull(module) ? : error(" Failed to get module ${module.name} " )
7483 }
7584
7685 override fun unload (module : DI .Module ) {
7786 val key = module.key
7887 val feat = _loaded [key] ? : return
79- feat.close()
80- // Ensure removed in case of FailedModule
81- _loaded .remove(key)
82- loadOrder.remove(module)
88+ try {
89+ feat.close()
90+ } finally {
91+ // Ensure removed in case of FailedModule or error
92+ _loaded .remove(key)
93+ loadOrder.remove(module)
94+ }
8395 }
8496
8597 fun unloadAll () {
@@ -94,13 +106,18 @@ class DIScope(root: MutableDI.() -> Unit = {}) : DI.Scope, DI, AutoCloseable {
94106fun DI.Scope.loadCatching (module : DI .Module ): Result <DI > {
95107 return runCatching { load(module) }.onFailure {
96108 if (it is IllegalArgumentException ) {
97- logger.e { " Failed to load feature $ module : ${it.message} " }
109+ logger.e { " Failed to load module ${ module.name} : ${it.message} " }
98110 } else {
99- logger.e(it) { " Failed to load feature $ module" }
111+ logger.e(it) { " Failed to load module ${ module.name} " }
100112 }
101113 }
102114}
103115
104- fun DI.Scope.loadAllCatching (vararg modules : DI .Module ) {
105- modules.forEach { loadCatching(it) }
116+ /* *
117+ * Loads passed [modules] and their dependencies, printing error messages instead of throwing them when any fail to load.
118+ *
119+ * @return Whether all modules successfully loaded
120+ */
121+ fun DI.Scope.loadAllCatching (vararg modules : DI .Module ): LoadResult {
122+ return LoadResult (modules.associateWith { loadCatching(it) })
106123}
0 commit comments