Skip to content

Commit

Permalink
feat: added factories support
Browse files Browse the repository at this point in the history
  • Loading branch information
y9san9 committed Dec 22, 2023
1 parent 42b0035 commit 9e84c30
Show file tree
Hide file tree
Showing 17 changed files with 638 additions and 60 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.idea
build
.gradle
.kotlin
kotlin-js-store
local.properties
**/.DS_Store
Expand Down
6 changes: 0 additions & 6 deletions build-logic/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,6 @@ plugins {
`kotlin-dsl`
}

repositories {
mavenCentral()
gradlePluginPortal()
google()
}

dependencies {
api(libs.kotlinPlugin)
api(libs.androidPlugin)
Expand Down
2 changes: 0 additions & 2 deletions build-logic/src/main/kotlin/kmp-library-convention.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
@file:Suppress("UNUSED_VARIABLE")

plugins {
kotlin("multiplatform")
id("publication-convention")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,61 @@
@file:Suppress("UNUSED_VARIABLE")

package app.meetacy.di.android.compose.viewmodel

import androidx.compose.runtime.Composable
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import app.meetacy.di.DI
import app.meetacy.di.builder.DIBuilder
import app.meetacy.di.builder.di
import app.meetacy.di.dependency.Dependency
import app.meetacy.di.factory.create
import app.meetacy.di.factory.factory0
import kotlinx.coroutines.CoroutineScope
import kotlin.reflect.typeOf

val DI.viewModelScope: CoroutineScope by Dependency

@Composable
inline fun <reified T : Any> DI.viewModel(name: String? = null) = viewModel { get<T>(name) }
inline fun <reified R : Any> DI.viewModel(name: String? = null) = viewModel { create<R>(name) }

@Composable
inline fun <reified T1, reified R : Any> DI.viewModel(
arg1: T1,
name: String? = null
): R = viewModel { create<T1, R>(arg1, name) }

@Composable
inline fun <reified T1, reified T2, reified R : Any> DI.viewModel(
arg1: T1,
arg2: T2,
name: String? = null
): R = viewModel { app.meetacy.di.factory.create<T1, T2, R>(arg1, arg2, name) }

@Composable
inline fun <reified T1, reified T2, reified T3, reified R : Any> DI.viewModel(
arg1: T1,
arg2: T2,
arg3: T3,
name: String? = null
): R = viewModel { app.meetacy.di.factory.create<T1, T2, T3, R>(arg1, arg2, arg3, name) }

@Composable
inline fun <reified T1, reified T2, reified T3, reified T4, reified R : Any> DI.viewModel(
arg1: T1,
arg2: T2,
arg3: T3,
arg4: T4,
name: String? = null
): R = viewModel { app.meetacy.di.factory.create<T1, T2, T3, T4, R>(arg1, arg2, arg3, arg4, name) }

@Composable
inline fun <reified T1, reified T2, reified T3, reified T4, reified T5, reified R : Any> DI.viewModel(
arg1: T1,
arg2: T2,
arg3: T3,
arg4: T4,
arg5: T5,
name: String? = null
): R = viewModel { app.meetacy.di.factory.create<T1, T2, T3, T4, T5, R>(arg1, arg2, arg3, arg4, arg5, name) }

@Composable
inline fun <reified T : Any> DI.viewModel(crossinline factory: DI.() -> T): T {
Expand All @@ -35,3 +76,7 @@ inline fun <reified T : Any> DI.viewModel(crossinline factory: DI.() -> T): T {
internal open class DIViewModel<T : Any> : ViewModel() {
lateinit var underlying: T
}

fun DIBuilder.users() {
val userViewModel by factory0(fun DI.() = 0)
}
2 changes: 0 additions & 2 deletions core/src/commonMain/kotlin/app/meetacy/di/DI.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package app.meetacy.di

import app.meetacy.di.annotation.DIDsl
import app.meetacy.di.builder.DIBuilder
import app.meetacy.di.builder.di
import app.meetacy.di.dependency.*
import kotlin.reflect.KType
import kotlin.reflect.typeOf
Expand Down
35 changes: 11 additions & 24 deletions core/src/commonMain/kotlin/app/meetacy/di/builder/DIBuilder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,21 @@ public class DIBuilder(dependencies: Dependencies) {
)
}

public inline fun <reified T> register(
name: String? = null,
provider: DependencyProvider<T>
) {
register(
key = DependencyKey(typeOf<T>(), name),
provider = provider
)
}

public inline fun <reified T> constant(
name: String,
value: T
) {
factory(name) { value }
register<T>(name) { value }
}

public inline fun <reified T> constant(value: T): DIBuilderConstantDelegate<T> {
Expand Down Expand Up @@ -79,29 +89,6 @@ public class DIBuilder(dependencies: Dependencies) {
)
}


public inline fun <reified T> factory(
name: String? = null,
crossinline factory: DI.() -> T
) {
val key = DependencyKey<T>(
type = typeOf<T>(),
name = name
)
val provider = DependencyProvider { di -> di.factory() }
register(key, provider)
}

public inline fun <reified T> factory(
noinline factory: DI.() -> T
): DIBuilderFactoryDelegate<T> {
return DIBuilderFactoryDelegate(
di = this,
type = typeOf<T>(),
factory = factory
)
}

public fun build(): DI = DI(
dependencies = Dependencies(dependencies.toList())
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,23 +46,3 @@ public class DIBuilderSingletonDelegate<T>(
return ReadOnlyProperty { _, _ -> }
}
}

public class DIBuilderFactoryDelegate<T>(
private val di: DIBuilder,
private val type: KType,
private val factory: DI.() -> T
) {
public operator fun provideDelegate(
thisRef: Any?,
property: KProperty<*>
): ReadOnlyProperty<Any?, Unit> {
di.register(
key = DependencyKey(
type = type,
name = property.name
),
provider = { di -> di.factory() }
)
return ReadOnlyProperty { _, _ -> }
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package app.meetacy.di.dependency

import app.meetacy.di.DI
import app.meetacy.di.internal.LazyFactory
import kotlin.reflect.KProperty
import kotlin.reflect.KType
import kotlin.reflect.typeOf

public object Dependency {
Expand All @@ -11,9 +13,16 @@ public object Dependency {
): T = thisRef.get(typeOf<T>(), property.name)
}

@Suppress("UNCHECKED_CAST")
public class InnerDependency(public val di: DI) {
private val lazy = LazyFactory<Any?>()

public fun <T> getValue(property: KProperty<*>, type: KType): T {
return lazy.get { di.get(type, property.name) } as T
}

public inline operator fun <reified T> getValue(
thisRef: Any?,
property: KProperty<*>
): T = di.get(typeOf<T>(), property.name)
): T = getValue(property, typeOf<T>())
}
61 changes: 61 additions & 0 deletions core/src/commonMain/kotlin/app/meetacy/di/factory/Factory0.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package app.meetacy.di.factory

import app.meetacy.di.DI
import app.meetacy.di.builder.DIBuilder
import app.meetacy.di.builder.DIBuilderSingletonDelegate
import app.meetacy.di.internal.LazyFactory
import kotlin.reflect.KProperty
import kotlin.reflect.KType
import kotlin.reflect.typeOf

public fun interface Factory0<R> {
public fun create(): R
}

// DI Extensions

public fun <R> DI.create(
factoryType: KType,
name: String? = null
): R = get<Factory0<R>>(factoryType, name).create()

public inline fun <reified R> DI.create(
name: String? = null
): R = create(typeOf<Factory0<R>>(), name)

// DI Delegates

public inline fun <reified R> DI.creating(): Factory0Dependency<R> =
Factory0Dependency(
di = this,
factoryType = typeOf<Factory0<R>>()
)

public class Factory0Dependency<R>(
private val di: DI,
private val factoryType: KType
) {
private val lazy = LazyFactory<R>()

public operator fun getValue(
thisRef: Any?,
property: KProperty<*>
): R = lazy.get { di.create(factoryType, property.name) }
}

// DIBuilder Extensions

public inline fun <reified R> DIBuilder.factory0(
name: String? = null,
crossinline factory: DI.() -> R
) {
singleton(name) {
Factory0 { factory() }
}
}

public inline fun <reified R> DIBuilder.factory0(
crossinline factory: DI.() -> R
): DIBuilderSingletonDelegate<Factory0<R>> = singleton {
Factory0 { factory() }
}
79 changes: 79 additions & 0 deletions core/src/commonMain/kotlin/app/meetacy/di/factory/Factory1.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package app.meetacy.di.factory

import app.meetacy.di.DI
import app.meetacy.di.builder.DIBuilder
import app.meetacy.di.builder.DIBuilderSingletonDelegate
import app.meetacy.di.internal.LazyFactory
import kotlin.reflect.KProperty
import kotlin.reflect.KType
import kotlin.reflect.typeOf

public fun interface Factory1<R1, T> {
public fun create(arg1: R1): T
}

// DI Extensions

public fun <T1, R> DI.create(
factoryType: KType,
arg1: T1,
name: String? = null
): R = get<Factory1<T1, R>>(
type = factoryType,
name = name
).create(arg1)

public inline fun <reified T1, reified R> DI.create(
arg1: T1,
name: String? = null
): R = create(
factoryType = typeOf<Factory1<T1, R>>(),
arg1 = arg1,
name = name
)

// DI Delegates

public inline fun <reified T1, reified R> DI.creating(
arg1: T1
): Factory1Dependency<T1, R> = Factory1Dependency(
di = this,
arg1 = arg1,
factoryType = typeOf<Factory1<T1, R>>()
)

public class Factory1Dependency<T1, R>(
private val di: DI,
private val arg1: T1,
private val factoryType: KType
) {
private val lazy = LazyFactory<R>()

public operator fun getValue(
thisRef: Any?,
property: KProperty<*>
): R = lazy.get {
di.create(
factoryType = factoryType,
arg1 = arg1,
name = property.name
)
}
}

// DIBuilder Extensions

public inline fun <reified T1, reified R> DIBuilder.factory1(
name: String? = null,
crossinline factory: DI.(arg1: T1) -> R
) {
singleton(name) {
Factory1 { arg1: T1 -> factory(arg1) }
}
}

public inline fun <reified T1, reified R> DIBuilder.factory1(
crossinline factory: DI.(arg1: T1) -> R
): DIBuilderSingletonDelegate<Factory1<T1, R>> = singleton {
Factory1 { arg1: T1 -> factory(arg1) }
}
Loading

0 comments on commit 9e84c30

Please sign in to comment.