/*
* Copyright (C) 2016 The Android Open Source Project
*
* 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.
*/
package androidx.room.solver.types
import androidx.room.compiler.codegen.CodeLanguage
import androidx.room.compiler.codegen.XCodeBlock
import androidx.room.compiler.codegen.XTypeName
import androidx.room.compiler.codegen.XTypeName.Companion.PRIMITIVE_BYTE
import androidx.room.compiler.codegen.XTypeName.Companion.PRIMITIVE_CHAR
import androidx.room.compiler.codegen.XTypeName.Companion.PRIMITIVE_DOUBLE
import androidx.room.compiler.codegen.XTypeName.Companion.PRIMITIVE_FLOAT
import androidx.room.compiler.codegen.XTypeName.Companion.PRIMITIVE_INT
import androidx.room.compiler.codegen.XTypeName.Companion.PRIMITIVE_LONG
import androidx.room.compiler.codegen.XTypeName.Companion.PRIMITIVE_SHORT
import androidx.room.compiler.processing.XProcessingEnv
import androidx.room.compiler.processing.XType
import androidx.room.parser.SQLTypeAffinity
import androidx.room.solver.CodeGenScope
/**
* Adapters for all primitives that has direct cursor mappings.
*/
class PrimitiveColumnTypeAdapter(
out: XType,
typeAffinity: SQLTypeAffinity,
val primitive: Primitive,
) : ColumnTypeAdapter(out, typeAffinity) {
companion object {
enum class Primitive(
val typeName: XTypeName,
val cursorGetter: String,
val stmtSetter: String,
) {
INT(PRIMITIVE_INT, "getInt", "bindLong"),
SHORT(PRIMITIVE_SHORT, "getShort", "bindLong"),
BYTE(PRIMITIVE_BYTE, "getShort", "bindLong"),
LONG(PRIMITIVE_LONG, "getLong", "bindLong"),
CHAR(PRIMITIVE_CHAR, "getInt", "bindLong"),
FLOAT(PRIMITIVE_FLOAT, "getFloat", "bindDouble"),
DOUBLE(PRIMITIVE_DOUBLE, "getDouble", "bindDouble"),
}
private fun getAffinity(primitive: Primitive) = when (primitive) {
Primitive.INT, Primitive.SHORT, Primitive.BYTE, Primitive.LONG, Primitive.CHAR ->
SQLTypeAffinity.INTEGER
Primitive.FLOAT, Primitive.DOUBLE ->
SQLTypeAffinity.REAL
}
fun createPrimitiveAdapters(
processingEnvironment: XProcessingEnv
): List<PrimitiveColumnTypeAdapter> {
return Primitive.values().map {
PrimitiveColumnTypeAdapter(
out = processingEnvironment.requireType(it.typeName),
typeAffinity = getAffinity(it),
primitive = it
)
}
}
}
private val cursorGetter = primitive.cursorGetter
private val stmtSetter = primitive.stmtSetter
override fun bindToStmt(
stmtName: String,
indexVarName: String,
valueVarName: String,
scope: CodeGenScope
) {
scope.builder
.addStatement("%L.%L(%L, %L)", stmtName, stmtSetter, indexVarName, valueVarName)
}
override fun readFromCursor(
outVarName: String,
cursorVarName: String,
indexVarName: String,
scope: CodeGenScope
) {
scope.builder.addStatement(
"%L = %L",
outVarName,
XCodeBlock.of(
scope.language,
"%L.%L(%L)",
cursorVarName,
cursorGetter,
indexVarName
).let {
// These primitives don't have an exact cursor getter.
val castFunction = when (primitive) {
Primitive.BYTE -> "toByte"
Primitive.CHAR -> "toChar"
else -> null
} ?: return@let it
when (it.language) {
// For Java a cast will suffice
CodeLanguage.JAVA -> {
XCodeBlock.ofCast(it.language, out.asTypeName(), it)
}
// For Kotlin a converter function is emitted
CodeLanguage.KOTLIN -> {
XCodeBlock.of(it.language, "%L.%L()", it, castFunction)
}
}
}
)
}
}