blob: cf1701333a9f17c87c7eab66608618243c4f8089 [file] [log] [blame]
/*
* Copyright 2019 the original author or authors.
*
* 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 org.gradle.instantexecution.serialization
import org.gradle.api.internal.project.ProjectInternal
import org.gradle.api.logging.Logger
import org.gradle.instantexecution.serialization.beans.BeanPropertyReader
import org.gradle.instantexecution.serialization.beans.BeanPropertyWriter
import org.gradle.internal.serialize.Decoder
import org.gradle.internal.serialize.Encoder
internal
class DefaultWriteContext(
private
val encodings: EncodingProvider,
private
val encoder: Encoder,
override val logger: Logger,
private
val problemHandler: (PropertyProblem) -> Unit
) : AbstractIsolateContext<WriteIsolate>(), MutableWriteContext, Encoder by encoder {
private
val beanPropertyWriters = hashMapOf<Class<*>, BeanPropertyWriter>()
private
val classes = hashMapOf<Class<*>, Int>()
override fun beanPropertyWriterFor(beanType: Class<*>): BeanPropertyWriter =
beanPropertyWriters.computeIfAbsent(beanType, ::BeanPropertyWriter)
override val isolate: WriteIsolate
get() = getIsolate()
override suspend fun write(value: Any?) {
encodings.run {
encode(value)
}
}
override fun writeClass(type: Class<*>) {
val id = classes[type]
if (id != null) {
writeSmallInt(id)
} else {
val newId = classes.size
classes[type] = newId
writeSmallInt(newId)
writeString(type.name)
}
}
// TODO: consider interning strings
override fun writeString(string: CharSequence) =
encoder.writeString(string)
override fun newIsolate(owner: IsolateOwner): WriteIsolate =
DefaultWriteIsolate(owner)
override fun onProblem(problem: PropertyProblem) {
problemHandler(problem)
}
}
internal
interface EncodingProvider {
suspend fun WriteContext.encode(candidate: Any?)
}
internal
class DefaultReadContext(
private
val decoding: DecodingProvider,
private
val decoder: Decoder,
override val logger: Logger,
private
val beanPropertyReaderFactory: (Class<*>) -> BeanPropertyReader
) : AbstractIsolateContext<ReadIsolate>(), MutableReadContext, Decoder by decoder {
private
val beanPropertyReaders = hashMapOf<Class<*>, BeanPropertyReader>()
private
val classes = hashMapOf<Int, Class<*>>()
private
lateinit var projectProvider: ProjectProvider
override lateinit var classLoader: ClassLoader
internal
fun initClassLoader(classLoader: ClassLoader) {
this.classLoader = classLoader
}
internal
fun initProjectProvider(projectProvider: ProjectProvider) {
this.projectProvider = projectProvider
}
override suspend fun read(): Any? = decoding.run {
decode()
}
override val isolate: ReadIsolate
get() = getIsolate()
override fun beanPropertyReaderFor(beanType: Class<*>): BeanPropertyReader =
beanPropertyReaders.computeIfAbsent(beanType, beanPropertyReaderFactory)
override fun readClass(): Class<*> {
val id = readSmallInt()
val type = classes[id]
if (type != null) {
return type
}
val newType = Class.forName(readString(), false, classLoader)
classes[id] = newType
return newType
}
override fun getProject(path: String): ProjectInternal =
projectProvider(path)
override fun newIsolate(owner: IsolateOwner): ReadIsolate =
DefaultReadIsolate(owner)
override fun onProblem(problem: PropertyProblem) {
// ignore problems
}
}
internal
interface DecodingProvider {
suspend fun ReadContext.decode(): Any?
}
internal
typealias ProjectProvider = (String) -> ProjectInternal
internal
abstract class AbstractIsolateContext<T> : MutableIsolateContext {
private
var currentIsolate: T? = null
var trace: PropertyTrace = PropertyTrace.Unknown
protected
abstract fun newIsolate(owner: IsolateOwner): T
protected
fun getIsolate(): T = currentIsolate.let { isolate ->
require(isolate != null) {
"`isolate` is only available during Task serialization."
}
isolate
}
override fun enterIsolate(owner: IsolateOwner) {
require(currentIsolate === null)
currentIsolate = newIsolate(owner)
}
override fun leaveIsolate() {
require(currentIsolate !== null)
currentIsolate = null
}
}
internal
class DefaultWriteIsolate(override val owner: IsolateOwner) : WriteIsolate {
override val identities: WriteIdentities = WriteIdentities()
}
internal
class DefaultReadIsolate(override val owner: IsolateOwner) : ReadIsolate {
override val identities: ReadIdentities = ReadIdentities()
}