Skip to content

Commit

Permalink
chore: Add VssDataType enum for mapping VSS types to Kotlin/Java types
Browse files Browse the repository at this point in the history
  • Loading branch information
Chrylo committed Mar 19, 2024
1 parent aecb9e4 commit 767a785
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 64 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2023 Contributors to the Eclipse Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/

@file:OptIn(ExperimentalUnsignedTypes::class)

package org.eclipse.kuksa.vssprocessor.spec

import kotlin.reflect.KClass

/**
* The [dataType] is the compatible Kotlin representation of the VSS type. The [stringRepresentation] is the string
* literal which was used by the VSS standard. The [defaultValue] returns a valid default values as a string literal.
* Use the [valueDataType] if Java compatibility needs to be ensured because some [dataType]s are using Kotlin inline
* types which are not supported by Java e.g. [UInt].
*/
enum class VssDataType(
val dataType: KClass<*>,
val stringRepresentation: String,
val defaultValue: String,
val valueDataType: KClass<*> = dataType,
) {
UNKNOWN(Any::class, "Any", "null"),
STRING(String::class, "string", "\"\""),
BOOL(Boolean::class, "boolean", "false"),
INT8(Int::class, "int8", "0"),
INT16(Int::class, "int16", "0"),
INT32(Int::class, "int32", "0"),
INT64(Long::class, "int64", "0L"),
UINT8(Int::class, "uint8", "0", Int::class),
UINT16(UInt::class, "uint16", "0", Int::class),
UINT32(UInt::class, "uint32", "0", Int::class),
UINT64(ULong::class, "uint64", "0L", Long::class),
FLOAT(Float::class, "float", "0f"),
DOUBLE(Double::class, "double", "0.0"),
STRING_ARRAY(Array<String>::class, "string[]", "emptyArray<String>()"),
BOOL_ARRAY(BooleanArray::class, "boolean[]", "BooleanArray(0)"),
INT8_ARRAY(IntArray::class, "int8[]", "IntArray(0)"),
INT16_ARRAY(IntArray::class, "int16[]", "IntArray(0)"),
INT32_ARRAY(IntArray::class, "int32[]", "IntArray(0)"),
INT64_ARRAY(LongArray::class, "int64[]", "LongArray(0)"),
UINT8_ARRAY(UIntArray::class, "uint8[]", "IntArray(0)", IntArray::class),
UINT16_ARRAY(UIntArray::class, "uint16[]", "IntArray(0)", IntArray::class),
UINT32_ARRAY(UIntArray::class, "uint32[]", "IntArray(0)", IntArray::class),
UINT64_ARRAY(ULongArray::class, "uint64[]", "LongArray(0)", LongArray::class),
FLOAT_ARRAY(FloatArray::class, "float[]", "FloatArray(0)"),
DOUBLE_ARRAY(DoubleArray::class, "double[]", "DoubleArray(0)"),
;

companion object {
/**
* Find the correct [VssDataType] by the given [stringRepresentation]. Returns [UNKNOWN] for undefined
* [stringRepresentation]s.
*/
fun find(stringRepresentation: String): VssDataType {
return entries.find { it.stringRepresentation == stringRepresentation } ?: UNKNOWN
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,70 +63,26 @@ internal class VssNodeSpecModel(
private val genericClassTypeName = KClass::class.asClassName().parameterizedBy(STAR)
private val genericClassTypeNameNullable = KClass::class.asClassName().parameterizedBy(STAR).copy(nullable = true)

@OptIn(ExperimentalUnsignedTypes::class)
private val vssDataType by lazy { VssDataType.find(datatype) }

private val datatypeTypeName: TypeName
get() {
return when (datatype) {
"string" -> String::class.asTypeName()
"boolean" -> Boolean::class.asTypeName()
"uint8", "uint16", "uint32" -> UInt::class.asTypeName()
"uint64" -> ULong::class.asTypeName()
"int8", "int16", "int32" -> Int::class.asTypeName()
"int64" -> Long::class.asTypeName()
"float" -> Float::class.asTypeName()
"double" -> Double::class.asTypeName()
"string[]" -> Array::class.parameterizedBy(String::class)
"boolean[]" -> BooleanArray::class.asTypeName()
"int8[]", "int16[]", "int32[]" -> IntArray::class.asTypeName()
"uint8[]", "uint16[]", "uint32[]" -> UIntArray::class.asTypeName()
"int64[]" -> LongArray::class.asTypeName()
"uint64[]" -> ULongArray::class.asTypeName()
"float[]" -> FloatArray::class.asTypeName()
"double[]" -> DoubleArray::class.asTypeName()
else -> Any::class.asTypeName()
return when (vssDataType) {
VssDataType.STRING_ARRAY -> vssDataType.dataType.parameterizedBy(String::class)
else -> vssDataType.dataType.asTypeName()
}
}

@OptIn(ExperimentalUnsignedTypes::class)
private val valueTypeName: TypeName
get() {
return when (datatypeTypeName) {
// Convert the following Kotlin types because they are incompatible with the @JvmOverloads annotation
UInt::class.asTypeName() -> Int::class.asTypeName()
ULong::class.asTypeName() -> Long::class.asTypeName()
UIntArray::class.asTypeName() -> IntArray::class.asTypeName()
ULongArray::class.asTypeName() -> LongArray::class.asTypeName()
else -> datatypeTypeName
return when (vssDataType) {
VssDataType.STRING_ARRAY -> vssDataType.valueDataType.parameterizedBy(String::class)
else -> vssDataType.valueDataType.asTypeName()
}
}

/**
* Returns valid default values as string literals.
*/
@OptIn(ExperimentalUnsignedTypes::class)
private val defaultValue: String
get() {
return when (valueTypeName) {
String::class.asTypeName() -> "\"\""
Boolean::class.asTypeName() -> "false"
Float::class.asTypeName() -> "0f"
Double::class.asTypeName() -> "0.0"
Int::class.asTypeName() -> "0"
Long::class.asTypeName() -> "0L"
UInt::class.asTypeName() -> "0u"
ULong::class.asTypeName() -> "0u"
Array::class.parameterizedBy(String::class) -> "emptyArray<String>()"
IntArray::class.asTypeName() -> "IntArray(0)"
BooleanArray::class.asTypeName() -> "BooleanArray(0)"
FloatArray::class.asTypeName() -> "FloatArray(0)"
LongArray::class.asTypeName() -> "LongArray(0)"
DoubleArray::class.asTypeName() -> "DoubleArray(0)"
ULongArray::class.asTypeName() -> "ULongArray(0)"
UIntArray::class.asTypeName() -> "UIntArray(0)"

else -> throw IllegalArgumentException("No default value found for $valueTypeName!")
}
}
get() = vssDataType.defaultValue

override fun createClassSpec(
packageName: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

package org.eclipse.kuksa.vssprocessor.spec

import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.BehaviorSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
Expand Down Expand Up @@ -139,12 +138,12 @@ class VssNodeSpecModelTest : BehaviorSpec({
val specModel = VssNodeSpecModel(datatype = "any", vssPath = "Vehicle.IgnitionType")

`when`("creating a class spec") {
val exception = shouldThrow<IllegalArgumentException> {
specModel.createClassSpec("test")
}
val classSpec = specModel.createClassSpec("test")

then("it should have a value with an UNKNOWN (Any) datatype") {
val propertySpec = classSpec.primaryConstructor?.parameters?.find { it.name == "value" }

then("it should throw an exception") {
exception shouldNotBe null
propertySpec.toString() shouldContain "kotlin.Any = null"
}
}
}
Expand All @@ -153,12 +152,12 @@ class VssNodeSpecModelTest : BehaviorSpec({
val specModel = VssNodeSpecModel(vssPath = "Vehicle")

`when`("creating a class spec without children and nested classes") {
val exception = shouldThrow<IllegalArgumentException> {
specModel.createClassSpec("test")
}
val classSpec = specModel.createClassSpec("test")

then("it should have a value with an UNKNOWN (Any) datatype") {
val propertySpec = classSpec.primaryConstructor?.parameters?.find { it.name == "value" }

then("it should throw an exception because it is missing a value") {
exception shouldNotBe null
propertySpec.toString() shouldContain "kotlin.Any = null"
}
}
and("related nodes") {
Expand Down

0 comments on commit 767a785

Please sign in to comment.