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

Add support for Set<T> (#15) #16

Merged
merged 4 commits into from
May 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,14 +219,15 @@ Apart from that if you want to controll range / legnth / size of the values bein
- Kotlin Objects
- `Enum`
- `List`
- `Set`
- `Map`
- `Pair`
- Nullable types
- Properties with **unsupported** types which are nullable are allowed, and the generated value would always be null
- Properties with default values can have *any type*, as they are not considered while generating code
- Types in the above mentioned list having generic type parameters (like `List` and `Map`) can only have `@Dowel` supported types as their type parameters. Like `List<String>`, `Map<String, @Dowel class>`
- As far as a type is in above mentioned supported list, there are no practical limitations on how many times they may be nested.
Like `List<Map<String, List<@Dowel class>>>`
Like `List<Map<Set<String>, List<@Dowel class>>>`

## `Dowel` ships with `lint` rules
`Dowel` ships with `lint` rules which cover all of the basic validation scenarios, and it will warn you even before you might compile the code if any improper usage is detected.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@ data class Person(
val meta: SomeStaticInfo,
val customType: UnsupportedType = UnsupportedType.SomeType,
@Size(value = 2) val locations: List<Location>,
@Size(value = 3) val uniqueLocations: Set<Location>,
val isExpanded: State<Boolean>,
@Size(value = 1) val preferences: Map<Long, Location>,
@Size(value = 2) val preferredLocations: Map<Long, Set<Location>>,
val title: Char,
@Size(value = 1) val interests: List<Float>,
val onClick: suspend (a: Person, b: Int) -> Unit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,9 @@ internal class DowelGenerator(
is ClassRepresentation.ParameterSpec.ListSpec ->
spec.elementSpec.getAllSupportingProvidersRecursively()

is ClassRepresentation.ParameterSpec.SetSpec ->
spec.elementSpec.getAllSupportingProvidersRecursively()

is ClassRepresentation.ParameterSpec.MapSpec ->
spec.keySpec.getAllSupportingProvidersRecursively() +
spec.valueSpec.getAllSupportingProvidersRecursively()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ internal class ObjectConstructor {

is StateSpec -> spec.getStateAssigner() // This would be a recursive call
is ListSpec -> spec.getListAssigner() // This would be a recursive call
is SetSpec -> spec.getSetAssigner() // This would be a recursive call
is MapSpec -> spec.getMapAssigner() // This would be a recursive call
is FlowSpec -> spec.getFlowAssigner() // This would be a recursive call
is PairSpec -> spec.getPairAssigner() // This would be a recursive call
Expand Down Expand Up @@ -214,6 +215,33 @@ internal class ObjectConstructor {
}
}

private fun SetSpec.getSetAssigner(): CodeBlock {

val spec = this

val setSize = spec.size.value.toSafeRangeInt()

if (setSize == 0) {
return buildCodeBlock { add("setOf()") }
}

val modSetSize: Int = if (setSize != -1) setSize
else Random.nextLong(
from = spec.size.min,
until = spec.size.max,
).toSafeRangeInt()

return buildCodeBlock {
add("setOf(\n")
withIndent {
repeat(modSetSize) {
add("%L,\n", spec.elementSpec.getAssigner())
}
}
add(")")
}
}

private fun MapSpec.getMapAssigner(): CodeBlock {

val spec = this
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ internal data class ClassRepresentation(
val elementSpec: ParameterSpec,
) : ParameterSpec

data class SetSpec(
val size: Size,
val elementSpec: ParameterSpec,
) : ParameterSpec

data class MapSpec(
val size: Size,
val keySpec: ParameterSpec,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ internal class ClassRepresentationMapper(
val ksName = resolver.getKSNameFromString(List::class.qualifiedName!!)
resolver.getClassDeclarationByName(ksName)!!.asStarProjectedType()
}
private val setDeclaration: KSType by unsafeLazy {
val ksName = resolver.getKSNameFromString(Set::class.qualifiedName!!)
resolver.getClassDeclarationByName(ksName)!!.asStarProjectedType()
}
private val mapDeclaration: KSType by unsafeLazy {
val ksName = resolver.getKSNameFromString(Map::class.qualifiedName!!)
resolver.getClassDeclarationByName(ksName)!!.asStarProjectedType()
Expand Down Expand Up @@ -175,6 +179,9 @@ internal class ClassRepresentationMapper(
// List
listDeclaration.isAssignableFrom(propType) -> propType.getListSpec(annotations)

// Set
setDeclaration.isAssignableFrom(propType) -> propType.getSetSpec(annotations)

// Map
mapDeclaration.isAssignableFrom(propType) -> propType.getMapSpec(annotations)

Expand Down Expand Up @@ -369,6 +376,33 @@ internal class ClassRepresentationMapper(
}
}

private fun KSType.getSetSpec(
annotations: List<KSAnnotation>,
): MaybeSpec<SetSpec> {

val size: Size = Size.find(
annotations = annotations.toList(),
defaultValue = DefaultRange.DEFAULT_LIST_LEN_VALUE,
defaultMin = DefaultRange.DEFAULT_LIST_LEN_MIN,
defaultMax = DefaultRange.DEFAULT_LIST_LEN_MAX,
)

require(this.arguments.size == 1) { "Set must have have exactly one type argument. Current size = ${this.arguments.size}" }

val arg = this.arguments.first()
val resolvedType = arg.type!!.resolve()
val spec = resolvedType.getSpec(
annotations = arg.annotations.toList(),
)

return either {
SetSpec(
size = size,
elementSpec = spec.bind(),
)
}
}

private fun KSType.getMapSpec(
annotations: List<KSAnnotation>,
): MaybeSpec<MapSpec> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,13 @@ internal class DowelWholeEnchiladaProcessingTest {
val latLon: Pair<Long, Long>,
val info: SomeStaticInfo,
@Size(value = 2) val locations: List<Location>,
@Size(value = 3) val uniqueLocations: Set<Location>,
val isExpanded: State<Boolean>,
@Size(value = 1) val preferences: Map<Long, Location>,
@Size(value = 2) val preferredLocations: Map<Long, Set<Location>>,
val title: Char,
@Size(value = 1) val interests: List<Float>,
@Size(value = 2) val uniqueInterests: Set<Float>,
val meta : MetaInfo,
val subjects : Subjects,
val onClick: suspend (a: Person, b: Int) -> Unit,
Expand Down