Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
package kotlinx.rpc.codegen.checkers

import kotlinx.rpc.codegen.FirRpcPredicates
import kotlinx.rpc.codegen.FirVersionSpecificApiImpl.toClassSymbolVS
import kotlinx.rpc.codegen.checkers.diagnostics.FirGrpcDiagnostics
import kotlinx.rpc.codegen.common.RpcClassId
import kotlinx.rpc.codegen.vsApi
Expand All @@ -20,7 +19,7 @@ import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId
import org.jetbrains.kotlin.fir.declarations.getKClassArgument
import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider
import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.resolve.getSuperTypes
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.classId
Expand Down Expand Up @@ -55,9 +54,7 @@ object FirWithCodecDeclarationChecker {
"for declaration: ${declaration.symbol.classId.asSingleFqName()}"
)

val codecTargetClass = codecClassSymbol.findMessageCodecSuperType(context.session)
.typeArguments.first().type
?: error("Unexpected unresolved type argument for @WithCodec annotation")
val codecTargetClass = codecClassSymbol.resolveMessageCodecTypeArgument(context.session)

if (codecTargetClass.classId != declaration.symbol.classId) {
reporter.reportOn(
Expand All @@ -78,12 +75,13 @@ object FirWithCodecDeclarationChecker {
}
}

private fun FirClassSymbol<*>.findMessageCodecSuperType(session: FirSession): ConeKotlinType = vsApi {
return resolvedSuperTypes.find {
it.classId == RpcClassId.messageCodec
} ?: resolvedSuperTypes.firstNotNullOf {
it.toClassSymbolVS(session)?.findMessageCodecSuperType(session)
}
private fun FirClassSymbol<*>.resolveMessageCodecTypeArgument(session: FirSession): ConeKotlinType = vsApi {
val superTypes = getSuperTypes(session, recursive = true, lookupInterfaces = true, substituteSuperTypes = true)

return superTypes
.find { it.classId == RpcClassId.messageCodec }
?.typeArguments?.single()?.type
?: error("'MessageCodec' supertype not found for $classId")
}

private val CODEC_ARGUMENT_NAME = Name.identifier("codec")
Expand Down
4 changes: 0 additions & 4 deletions core/api/core.api
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,6 @@ public abstract interface class kotlinx/rpc/descriptor/RpcInvokator$FlowResponse
public abstract fun call (Ljava/lang/Object;[Ljava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
}

public abstract interface class kotlinx/rpc/descriptor/RpcInvokator$Method : kotlinx/rpc/descriptor/RpcInvokator {
public abstract fun call (Ljava/lang/Object;[Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}

public abstract interface class kotlinx/rpc/descriptor/RpcInvokator$UnaryResponse : kotlinx/rpc/descriptor/RpcInvokator {
public abstract fun call (Ljava/lang/Object;[Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
public final class kotlinx/rpc/grpc/codec/kotlinx/serialization/KotlinxSerializationCodecResolver : kotlinx/rpc/grpc/codec/MessageCodecResolver {
public fun <init> (Lkotlinx/serialization/SerialFormat;)V
public fun resolve (Lkotlin/reflect/KType;)Lkotlinx/rpc/grpc/codec/MessageCodec;
public fun resolveOrNull (Lkotlin/reflect/KType;)Lkotlinx/rpc/grpc/codec/MessageCodec;
}

public final class kotlinx/rpc/grpc/codec/kotlinx/serialization/KotlinxSerializationCodecResolverKt {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
final class kotlinx.rpc.grpc.codec.kotlinx.serialization/KotlinxSerializationCodecResolver : kotlinx.rpc.grpc.codec/MessageCodecResolver { // kotlinx.rpc.grpc.codec.kotlinx.serialization/KotlinxSerializationCodecResolver|null[0]
constructor <init>(kotlinx.serialization/SerialFormat) // kotlinx.rpc.grpc.codec.kotlinx.serialization/KotlinxSerializationCodecResolver.<init>|<init>(kotlinx.serialization.SerialFormat){}[0]

final fun resolve(kotlin.reflect/KType): kotlinx.rpc.grpc.codec/MessageCodec<*> // kotlinx.rpc.grpc.codec.kotlinx.serialization/KotlinxSerializationCodecResolver.resolve|resolve(kotlin.reflect.KType){}[0]
final fun resolveOrNull(kotlin.reflect/KType): kotlinx.rpc.grpc.codec/MessageCodec<*>? // kotlinx.rpc.grpc.codec.kotlinx.serialization/KotlinxSerializationCodecResolver.resolveOrNull|resolveOrNull(kotlin.reflect.KType){}[0]
}

final fun (kotlinx.serialization/SerialFormat).kotlinx.rpc.grpc.codec.kotlinx.serialization/asCodecResolver(): kotlinx.rpc.grpc.codec/MessageCodecResolver // kotlinx.rpc.grpc.codec.kotlinx.serialization/asCodecResolver|[email protected](){}[0]
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ import kotlinx.io.readString
import kotlinx.io.writeString
import kotlinx.rpc.grpc.codec.MessageCodec
import kotlinx.rpc.grpc.codec.MessageCodecResolver
import kotlinx.rpc.grpc.codec.SourcedMessageCodec
import kotlinx.rpc.internal.utils.ExperimentalRpcApi
import kotlinx.serialization.BinaryFormat
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialFormat
import kotlinx.serialization.StringFormat
import kotlinx.serialization.serializer
import kotlinx.serialization.serializerOrNull
import kotlin.reflect.KType

Expand All @@ -36,8 +36,8 @@ public fun SerialFormat.asCodecResolver(): MessageCodecResolver =
private class KotlinxSerializationCodec<T>(
private val serializer: KSerializer<T>,
private val serialFormat: SerialFormat,
) : MessageCodec<T> {
override fun encode(value: T): Source {
) : SourcedMessageCodec<T> {
override fun encodeToSource(value: T): Source {
return when (serialFormat) {
is StringFormat -> {
val stringValue = serialFormat.encodeToString(serializer, value)
Expand All @@ -59,7 +59,7 @@ private class KotlinxSerializationCodec<T>(
}
}

override fun decode(stream: Source): T {
override fun decodeFromSource(stream: Source): T {
return when (serialFormat) {
is StringFormat -> {
serialFormat.decodeFromString(serializer, stream.readString())
Expand Down
24 changes: 20 additions & 4 deletions grpc/grpc-codec/api/grpc-codec.api
Original file line number Diff line number Diff line change
@@ -1,15 +1,31 @@
public final class kotlinx/rpc/grpc/codec/EmptyMessageCodecResolver : kotlinx/rpc/grpc/codec/MessageCodecResolver {
public static final field INSTANCE Lkotlinx/rpc/grpc/codec/EmptyMessageCodecResolver;
public fun resolve (Lkotlin/reflect/KType;)Lkotlinx/rpc/grpc/codec/MessageCodec;
public fun resolveOrNull (Lkotlin/reflect/KType;)Lkotlinx/rpc/grpc/codec/MessageCodec;
}

public abstract interface class kotlinx/rpc/grpc/codec/MessageCodec {
public abstract fun decode (Lkotlinx/io/Source;)Ljava/lang/Object;
public abstract fun encode (Ljava/lang/Object;)Lkotlinx/io/Source;
public abstract fun decode (Ljava/io/InputStream;)Ljava/lang/Object;
public abstract fun encode (Ljava/lang/Object;)Ljava/io/InputStream;
}

public final class kotlinx/rpc/grpc/codec/MessageCodecKt {
public static final fun plus (Lkotlinx/rpc/grpc/codec/MessageCodecResolver;Lkotlinx/rpc/grpc/codec/MessageCodecResolver;)Lkotlinx/rpc/grpc/codec/MessageCodecResolver;
}

public abstract interface class kotlinx/rpc/grpc/codec/MessageCodecResolver {
public abstract fun resolve (Lkotlin/reflect/KType;)Lkotlinx/rpc/grpc/codec/MessageCodec;
public abstract fun resolveOrNull (Lkotlin/reflect/KType;)Lkotlinx/rpc/grpc/codec/MessageCodec;
}

public abstract interface class kotlinx/rpc/grpc/codec/SourcedMessageCodec : kotlinx/rpc/grpc/codec/MessageCodec {
public abstract fun decode (Ljava/io/InputStream;)Ljava/lang/Object;
public abstract fun decodeFromSource (Lkotlinx/io/Source;)Ljava/lang/Object;
public abstract fun encode (Ljava/lang/Object;)Ljava/io/InputStream;
public abstract fun encodeToSource (Ljava/lang/Object;)Lkotlinx/io/Source;
}

public final class kotlinx/rpc/grpc/codec/SourcedMessageCodec$DefaultImpls {
public static fun decode (Lkotlinx/rpc/grpc/codec/SourcedMessageCodec;Ljava/io/InputStream;)Ljava/lang/Object;
public static fun encode (Lkotlinx/rpc/grpc/codec/SourcedMessageCodec;Ljava/lang/Object;)Ljava/io/InputStream;
}

public abstract interface annotation class kotlinx/rpc/grpc/codec/WithCodec : java/lang/annotation/Annotation {
Expand Down
37 changes: 33 additions & 4 deletions grpc/grpc-codec/api/grpc-codec.klib.api
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Klib ABI Dump
// Targets: [iosArm64, iosSimulatorArm64, iosX64, js, linuxArm64, linuxX64, macosArm64, macosX64, mingwX64, tvosArm64, tvosSimulatorArm64, tvosX64, wasmJs, wasmWasi, watchosArm32, watchosArm64, watchosDeviceArm64, watchosSimulatorArm64, watchosX64]
// Alias: native => [iosArm64, iosSimulatorArm64, iosX64, linuxArm64, linuxX64, macosArm64, macosX64, mingwX64, tvosArm64, tvosSimulatorArm64, tvosX64, watchosArm32, watchosArm64, watchosDeviceArm64, watchosSimulatorArm64, watchosX64]
// Rendering settings:
// - Signature version: 2
// - Show manifest properties: true
Expand All @@ -14,14 +15,42 @@ open annotation class kotlinx.rpc.grpc.codec/WithCodec : kotlin/Annotation { //
}

abstract fun interface kotlinx.rpc.grpc.codec/MessageCodecResolver { // kotlinx.rpc.grpc.codec/MessageCodecResolver|null[0]
abstract fun resolve(kotlin.reflect/KType): kotlinx.rpc.grpc.codec/MessageCodec<*> // kotlinx.rpc.grpc.codec/MessageCodecResolver.resolve|resolve(kotlin.reflect.KType){}[0]
abstract fun resolveOrNull(kotlin.reflect/KType): kotlinx.rpc.grpc.codec/MessageCodec<*>? // kotlinx.rpc.grpc.codec/MessageCodecResolver.resolveOrNull|resolveOrNull(kotlin.reflect.KType){}[0]
}

abstract interface <#A: kotlin/Any?> kotlinx.rpc.grpc.codec/MessageCodec { // kotlinx.rpc.grpc.codec/MessageCodec|null[0]
abstract fun decode(kotlinx.io/Source): #A // kotlinx.rpc.grpc.codec/MessageCodec.decode|decode(kotlinx.io.Source){}[0]
abstract fun encode(#A): kotlinx.io/Source // kotlinx.rpc.grpc.codec/MessageCodec.encode|encode(1:0){}[0]
// Targets: [native]
abstract fun decode(kotlinx.rpc.protobuf.input.stream/BufferInputStream): #A // kotlinx.rpc.grpc.codec/MessageCodec.decode|decode(kotlinx.rpc.protobuf.input.stream.BufferInputStream){}[0]

// Targets: [native]
abstract fun encode(#A): kotlinx.rpc.protobuf.input.stream/BufferInputStream // kotlinx.rpc.grpc.codec/MessageCodec.encode|encode(1:0){}[0]

// Targets: [js, wasmJs, wasmWasi]
abstract fun decode(kotlinx.rpc.protobuf.input.stream/InputStream): #A // kotlinx.rpc.grpc.codec/MessageCodec.decode|decode(kotlinx.rpc.protobuf.input.stream.InputStream){}[0]

// Targets: [js, wasmJs, wasmWasi]
abstract fun encode(#A): kotlinx.rpc.protobuf.input.stream/InputStream // kotlinx.rpc.grpc.codec/MessageCodec.encode|encode(1:0){}[0]
}

abstract interface <#A: kotlin/Any?> kotlinx.rpc.grpc.codec/SourcedMessageCodec : kotlinx.rpc.grpc.codec/MessageCodec<#A> { // kotlinx.rpc.grpc.codec/SourcedMessageCodec|null[0]
abstract fun decodeFromSource(kotlinx.io/Source): #A // kotlinx.rpc.grpc.codec/SourcedMessageCodec.decodeFromSource|decodeFromSource(kotlinx.io.Source){}[0]
abstract fun encodeToSource(#A): kotlinx.io/Source // kotlinx.rpc.grpc.codec/SourcedMessageCodec.encodeToSource|encodeToSource(1:0){}[0]

// Targets: [native]
open fun decode(kotlinx.rpc.protobuf.input.stream/BufferInputStream): #A // kotlinx.rpc.grpc.codec/SourcedMessageCodec.decode|decode(kotlinx.rpc.protobuf.input.stream.BufferInputStream){}[0]

// Targets: [native]
open fun encode(#A): kotlinx.rpc.protobuf.input.stream/BufferInputStream // kotlinx.rpc.grpc.codec/SourcedMessageCodec.encode|encode(1:0){}[0]

// Targets: [js, wasmJs, wasmWasi]
open fun decode(kotlinx.rpc.protobuf.input.stream/InputStream): #A // kotlinx.rpc.grpc.codec/SourcedMessageCodec.decode|decode(kotlinx.rpc.protobuf.input.stream.InputStream){}[0]

// Targets: [js, wasmJs, wasmWasi]
open fun encode(#A): kotlinx.rpc.protobuf.input.stream/InputStream // kotlinx.rpc.grpc.codec/SourcedMessageCodec.encode|encode(1:0){}[0]
}

final object kotlinx.rpc.grpc.codec/EmptyMessageCodecResolver : kotlinx.rpc.grpc.codec/MessageCodecResolver { // kotlinx.rpc.grpc.codec/EmptyMessageCodecResolver|null[0]
final fun resolve(kotlin.reflect/KType): kotlinx.rpc.grpc.codec/MessageCodec<*> // kotlinx.rpc.grpc.codec/EmptyMessageCodecResolver.resolve|resolve(kotlin.reflect.KType){}[0]
final fun resolveOrNull(kotlin.reflect/KType): kotlinx.rpc.grpc.codec/MessageCodec<*>? // kotlinx.rpc.grpc.codec/EmptyMessageCodecResolver.resolveOrNull|resolveOrNull(kotlin.reflect.KType){}[0]
}

final fun (kotlinx.rpc.grpc.codec/MessageCodecResolver).kotlinx.rpc.grpc.codec/plus(kotlinx.rpc.grpc.codec/MessageCodecResolver): kotlinx.rpc.grpc.codec/MessageCodecResolver // kotlinx.rpc.grpc.codec/plus|[email protected](kotlinx.rpc.grpc.codec.MessageCodecResolver){}[0]
5 changes: 5 additions & 0 deletions grpc/grpc-codec/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@ plugins {
}

kotlin {
compilerOptions {
freeCompilerArgs.add("-Xexpect-actual-classes")
}

sourceSets {
commonMain {
dependencies {
api(projects.utils)
api(projects.protobuf.protobufInputStream)
api(libs.kotlinx.io.core)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ package kotlinx.rpc.grpc.codec
import kotlinx.io.Source
import kotlinx.rpc.internal.utils.ExperimentalRpcApi
import kotlinx.rpc.internal.utils.InternalRpcApi
import kotlinx.rpc.protobuf.input.stream.InputStream
import kotlinx.rpc.protobuf.input.stream.asInputStream
import kotlinx.rpc.protobuf.input.stream.asSource
import kotlin.reflect.KType

@ExperimentalRpcApi
Expand All @@ -30,8 +33,22 @@ public operator fun MessageCodecResolver.plus(other: MessageCodecResolver): Mess

@ExperimentalRpcApi
public interface MessageCodec<T> {
public fun encode(value: T): Source
public fun decode(stream: Source): T
public fun encode(value: T): InputStream
public fun decode(stream: InputStream): T
}

@ExperimentalRpcApi
public interface SourcedMessageCodec<T> : MessageCodec<T> {
public fun encodeToSource(value: T): Source
public fun decodeFromSource(stream: Source): T

override fun encode(value: T): InputStream {
return encodeToSource(value).asInputStream()
}

override fun decode(stream: InputStream): T {
return decodeFromSource(stream.asSource())
}
}

@InternalRpcApi
Expand Down
10 changes: 0 additions & 10 deletions grpc/grpc-core/api/grpc-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,3 @@ public final class kotlinx/rpc/grpc/Status_jvmKt {
public abstract interface annotation class kotlinx/rpc/grpc/annotations/Grpc : java/lang/annotation/Annotation {
}

public abstract interface class kotlinx/rpc/grpc/descriptor/GrpcClientDelegate {
public abstract fun call (Lkotlinx/rpc/RpcCall;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun callServerStreaming (Lkotlinx/rpc/RpcCall;)Lkotlinx/coroutines/flow/Flow;
}

public abstract interface class kotlinx/rpc/grpc/descriptor/GrpcDelegate {
public abstract fun clientProvider (Lkotlinx/rpc/grpc/ManagedChannel;)Lkotlinx/rpc/grpc/descriptor/GrpcClientDelegate;
public abstract fun definitionFor (Ljava/lang/Object;)Lio/grpc/ServerServiceDefinition;
}

9 changes: 1 addition & 8 deletions grpc/grpc-core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ kotlin {
implementation(libs.serialization.json)

implementation(projects.grpc.grpcCodecKotlinxSerialization)
implementation(projects.protobuf.protobufCore)
}
}

Expand Down Expand Up @@ -76,12 +77,4 @@ kotlin {
}
}

protoSourceSets {
commonTest {
proto {
exclude("exclude/**")
}
}
}

configureLocalProtocGenDevelopmentDependency()
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package kotlinx.rpc.grpc

import kotlinx.atomicfu.atomic
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.Flow
Expand Down Expand Up @@ -52,7 +53,7 @@ public class GrpcServer internal constructor(
parentContext: CoroutineContext = EmptyCoroutineContext,
configure: ServerBuilder<*>.() -> Unit,
) : RpcServer, Server {
private val internalContext = SupervisorJob(parentContext.job)
private val internalContext = SupervisorJob(parentContext[Job])
private val internalScope = CoroutineScope(parentContext + internalContext)

private val messageCodecResolver = messageCodecResolver + ThrowingMessageCodecResolver
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ package kotlinx.rpc.grpc.internal

import kotlinx.rpc.grpc.codec.MessageCodec
import kotlinx.rpc.internal.utils.InternalRpcApi

@InternalRpcApi
public expect abstract class InputStream
import kotlinx.rpc.protobuf.input.stream.InputStream

@InternalRpcApi
public expect class MethodDescriptor<Request, Response> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,21 @@ import kotlinx.io.Source
import kotlinx.io.readString
import kotlinx.io.writeString
import kotlinx.rpc.grpc.annotations.Grpc
import kotlinx.rpc.grpc.codec.MessageCodec
import kotlinx.rpc.grpc.codec.MessageCodecResolver
import kotlinx.rpc.grpc.codec.SourcedMessageCodec
import kotlinx.rpc.grpc.codec.WithCodec
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals

@WithCodec(Message.Companion::class)
class Message(val value: String) {
companion object : MessageCodec<Message> {
override fun encode(value: Message): Source {
companion object : SourcedMessageCodec<Message> {
override fun encodeToSource(value: Message): Source {
return Buffer().apply { writeString(value.value) }
}

override fun decode(stream: Source): Message {
override fun decodeFromSource(stream: Source): Message {
return Message(stream.readString())
}
}
Expand Down Expand Up @@ -135,22 +135,22 @@ class CustomResolverGrpcServiceTest : BaseGrpcServiceTest() {
}
}

val stringCodec = object : MessageCodec<String> {
override fun encode(value: String): Source {
val stringCodec = object : SourcedMessageCodec<String> {
override fun encodeToSource(value: String): Source {
return Buffer().apply { writeString(value) }
}

override fun decode(stream: Source): String {
override fun decodeFromSource(stream: Source): String {
return stream.readString()
}
}

val unitCodec = object : MessageCodec<Unit> {
override fun encode(value: Unit): Source {
val unitCodec = object : SourcedMessageCodec<Unit> {
override fun encodeToSource(value: Unit): Source {
return Buffer()
}

override fun decode(stream: Source) {
override fun decodeFromSource(stream: Source) {
check(stream.exhausted())
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import kotlinx.rpc.grpc.ManagedChannelBuilder
import kotlinx.rpc.grpc.Server
import kotlinx.rpc.grpc.ServerBuilder
import kotlinx.rpc.grpc.buildChannel
import kotlinx.rpc.grpc.codec.MessageCodec
import kotlinx.rpc.grpc.codec.SourcedMessageCodec
import kotlinx.rpc.grpc.internal.GrpcChannel
import kotlinx.rpc.grpc.internal.MethodDescriptor
import kotlinx.rpc.grpc.internal.MethodType
Expand Down Expand Up @@ -151,12 +151,12 @@ class RawClientServerTest {
companion object {
private const val SERVICE_NAME = "TestService"

private val simpleCodec = object : MessageCodec<String> {
override fun encode(value: String): Source {
private val simpleCodec = object : SourcedMessageCodec<String> {
override fun encodeToSource(value: String): Source {
return Buffer().apply { writeString(value) }
}

override fun decode(stream: Source): String {
override fun decodeFromSource(stream: Source): String {
return stream.readString()
}
}
Expand Down
Loading
Loading