diff --git a/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/FirWithCodecDeclarationChecker.kt b/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/FirWithCodecDeclarationChecker.kt index 30b0ce601..c63e25bab 100644 --- a/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/FirWithCodecDeclarationChecker.kt +++ b/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/FirWithCodecDeclarationChecker.kt @@ -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 @@ -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 @@ -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( @@ -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") diff --git a/core/api/core.api b/core/api/core.api index 255ae735e..0fe9163b2 100644 --- a/core/api/core.api +++ b/core/api/core.api @@ -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; } diff --git a/grpc/grpc-codec-kotlinx-serialization/api/grpc-codec-kotlinx-serialization.api b/grpc/grpc-codec-kotlinx-serialization/api/grpc-codec-kotlinx-serialization.api index d6fe700f0..fc876894e 100644 --- a/grpc/grpc-codec-kotlinx-serialization/api/grpc-codec-kotlinx-serialization.api +++ b/grpc/grpc-codec-kotlinx-serialization/api/grpc-codec-kotlinx-serialization.api @@ -1,6 +1,6 @@ public final class kotlinx/rpc/grpc/codec/kotlinx/serialization/KotlinxSerializationCodecResolver : kotlinx/rpc/grpc/codec/MessageCodecResolver { public fun (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 { diff --git a/grpc/grpc-codec-kotlinx-serialization/api/grpc-codec-kotlinx-serialization.klib.api b/grpc/grpc-codec-kotlinx-serialization/api/grpc-codec-kotlinx-serialization.klib.api index dae678f54..d071eec92 100644 --- a/grpc/grpc-codec-kotlinx-serialization/api/grpc-codec-kotlinx-serialization.klib.api +++ b/grpc/grpc-codec-kotlinx-serialization/api/grpc-codec-kotlinx-serialization.klib.api @@ -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 (kotlinx.serialization/SerialFormat) // kotlinx.rpc.grpc.codec.kotlinx.serialization/KotlinxSerializationCodecResolver.|(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|asCodecResolver@kotlinx.serialization.SerialFormat(){}[0] diff --git a/grpc/grpc-codec-kotlinx-serialization/src/commonMain/kotlin/kotlinx/rpc/grpc/codec/kotlinx/serialization/KotlinxSerializationCodecResolver.kt b/grpc/grpc-codec-kotlinx-serialization/src/commonMain/kotlin/kotlinx/rpc/grpc/codec/kotlinx/serialization/KotlinxSerializationCodecResolver.kt index a67dae17f..1688dd10c 100644 --- a/grpc/grpc-codec-kotlinx-serialization/src/commonMain/kotlin/kotlinx/rpc/grpc/codec/kotlinx/serialization/KotlinxSerializationCodecResolver.kt +++ b/grpc/grpc-codec-kotlinx-serialization/src/commonMain/kotlin/kotlinx/rpc/grpc/codec/kotlinx/serialization/KotlinxSerializationCodecResolver.kt @@ -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 @@ -36,8 +36,8 @@ public fun SerialFormat.asCodecResolver(): MessageCodecResolver = private class KotlinxSerializationCodec( private val serializer: KSerializer, private val serialFormat: SerialFormat, -) : MessageCodec { - override fun encode(value: T): Source { +) : SourcedMessageCodec { + override fun encodeToSource(value: T): Source { return when (serialFormat) { is StringFormat -> { val stringValue = serialFormat.encodeToString(serializer, value) @@ -59,7 +59,7 @@ private class KotlinxSerializationCodec( } } - override fun decode(stream: Source): T { + override fun decodeFromSource(stream: Source): T { return when (serialFormat) { is StringFormat -> { serialFormat.decodeFromString(serializer, stream.readString()) diff --git a/grpc/grpc-codec/api/grpc-codec.api b/grpc/grpc-codec/api/grpc-codec.api index 600645acc..4927c8476 100644 --- a/grpc/grpc-codec/api/grpc-codec.api +++ b/grpc/grpc-codec/api/grpc-codec.api @@ -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 { diff --git a/grpc/grpc-codec/api/grpc-codec.klib.api b/grpc/grpc-codec/api/grpc-codec.klib.api index c0a41b9f6..e425162aa 100644 --- a/grpc/grpc-codec/api/grpc-codec.klib.api +++ b/grpc/grpc-codec/api/grpc-codec.klib.api @@ -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 @@ -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|plus@kotlinx.rpc.grpc.codec.MessageCodecResolver(kotlinx.rpc.grpc.codec.MessageCodecResolver){}[0] diff --git a/grpc/grpc-codec/build.gradle.kts b/grpc/grpc-codec/build.gradle.kts index b03c7ee5f..b1b745dc2 100644 --- a/grpc/grpc-codec/build.gradle.kts +++ b/grpc/grpc-codec/build.gradle.kts @@ -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) } } diff --git a/grpc/grpc-codec/src/commonMain/kotlin/kotlinx/rpc/grpc/codec/MessageCodec.kt b/grpc/grpc-codec/src/commonMain/kotlin/kotlinx/rpc/grpc/codec/MessageCodec.kt index 2ade94cab..99fffe465 100644 --- a/grpc/grpc-codec/src/commonMain/kotlin/kotlinx/rpc/grpc/codec/MessageCodec.kt +++ b/grpc/grpc-codec/src/commonMain/kotlin/kotlinx/rpc/grpc/codec/MessageCodec.kt @@ -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 @@ -30,8 +33,22 @@ public operator fun MessageCodecResolver.plus(other: MessageCodecResolver): Mess @ExperimentalRpcApi public interface MessageCodec { - 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 : MessageCodec { + 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 diff --git a/grpc/grpc-core/api/grpc-core.api b/grpc/grpc-core/api/grpc-core.api index e11157918..4454d346b 100644 --- a/grpc/grpc-core/api/grpc-core.api +++ b/grpc/grpc-core/api/grpc-core.api @@ -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; -} - diff --git a/grpc/grpc-core/build.gradle.kts b/grpc/grpc-core/build.gradle.kts index 7fcd3dad7..b6c4a6fc4 100644 --- a/grpc/grpc-core/build.gradle.kts +++ b/grpc/grpc-core/build.gradle.kts @@ -41,6 +41,7 @@ kotlin { implementation(libs.serialization.json) implementation(projects.grpc.grpcCodecKotlinxSerialization) + implementation(projects.protobuf.protobufCore) } } @@ -76,12 +77,4 @@ kotlin { } } -protoSourceSets { - commonTest { - proto { - exclude("exclude/**") - } - } -} - configureLocalProtocGenDevelopmentDependency() diff --git a/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/GrpcServer.kt b/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/GrpcServer.kt index bfc19f700..eb1e3abb7 100644 --- a/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/GrpcServer.kt +++ b/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/GrpcServer.kt @@ -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 @@ -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 diff --git a/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/internal/MethodDescriptor.kt b/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/internal/MethodDescriptor.kt index f66632002..189c0782b 100644 --- a/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/internal/MethodDescriptor.kt +++ b/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/internal/MethodDescriptor.kt @@ -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 { diff --git a/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/CustomResolverGrpcServiceTest.kt b/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/CustomResolverGrpcServiceTest.kt index eb8ee4d63..7fcc9af5e 100644 --- a/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/CustomResolverGrpcServiceTest.kt +++ b/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/CustomResolverGrpcServiceTest.kt @@ -13,8 +13,8 @@ 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 @@ -22,12 +22,12 @@ import kotlin.test.assertEquals @WithCodec(Message.Companion::class) class Message(val value: String) { - companion object : MessageCodec { - override fun encode(value: Message): Source { + companion object : SourcedMessageCodec { + 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()) } } @@ -135,22 +135,22 @@ class CustomResolverGrpcServiceTest : BaseGrpcServiceTest() { } } - val stringCodec = object : MessageCodec { - override fun encode(value: String): Source { + val stringCodec = object : SourcedMessageCodec { + 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 { - override fun encode(value: Unit): Source { + val unitCodec = object : SourcedMessageCodec { + override fun encodeToSource(value: Unit): Source { return Buffer() } - override fun decode(stream: Source) { + override fun decodeFromSource(stream: Source) { check(stream.exhausted()) } } diff --git a/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/RawClientServerTest.kt b/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/RawClientServerTest.kt index 4d5257274..2702d32a2 100644 --- a/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/RawClientServerTest.kt +++ b/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/RawClientServerTest.kt @@ -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 @@ -151,12 +151,12 @@ class RawClientServerTest { companion object { private const val SERVICE_NAME = "TestService" - private val simpleCodec = object : MessageCodec { - override fun encode(value: String): Source { + private val simpleCodec = object : SourcedMessageCodec { + 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() } } diff --git a/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/proto/GrpcProtoTest.kt b/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/proto/GrpcProtoTest.kt new file mode 100644 index 000000000..88e370dad --- /dev/null +++ b/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/proto/GrpcProtoTest.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.grpc.test.proto + +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import kotlinx.coroutines.test.runTest +import kotlinx.rpc.RpcServer +import kotlinx.rpc.grpc.GrpcClient +import kotlinx.rpc.grpc.GrpcServer + +abstract class GrpcProtoTest { + private val serverMutex = Mutex() + + abstract fun RpcServer.registerServices() + + protected fun runGrpcTest(test: suspend (GrpcClient) -> Unit, ) = runTest { + serverMutex.withLock { + val grpcClient = GrpcClient("localhost", 8080) { + usePlaintext() + } + + val grpcServer = GrpcServer(8080, builder = { + registerServices() + }) + + grpcServer.start() + test(grpcClient) + grpcServer.shutdown() + grpcServer.awaitTermination() + grpcClient.shutdown() + grpcClient.awaitTermination() + } + } +} diff --git a/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/proto/GrpcServerTest.kt b/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/proto/GrpcServerTest.kt deleted file mode 100644 index d233b29d8..000000000 --- a/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/proto/GrpcServerTest.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. - */ - -package kotlinx.rpc.grpc.core.test - -//import kotlinx.coroutines.sync.Mutex -//import kotlinx.coroutines.sync.withLock -//import kotlinx.coroutines.test.runTest -//import kotlinx.rpc.RpcServer -//import kotlinx.rpc.grpc.GrpcClient -//import kotlinx.rpc.grpc.GrpcServer -// -//abstract class GrpcServerTest { -// private val serverMutex = Mutex() -// -// abstract fun RpcServer.registerServices() -// -// protected fun runGrpcTest(test: suspend (GrpcClient) -> Unit, ) = runTest { -// serverMutex.withLock { -// val grpcClient = GrpcClient("localhost", 8080) { -// usePlaintext() -// } -// -// val grpcServer = GrpcServer(8080, builder = { -// registerServices() -// }) -// -// grpcServer.start() -// test(grpcClient) -// grpcServer.shutdown() -// grpcServer.awaitTermination() -// grpcClient.shutdown() -// grpcClient.awaitTermination() -// } -// } -//} diff --git a/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/proto/StreamingTest.kt b/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/proto/StreamingTest.kt index 9649ea829..de83de539 100644 --- a/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/proto/StreamingTest.kt +++ b/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/proto/StreamingTest.kt @@ -2,79 +2,81 @@ * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ -package kotlinx.rpc.grpc.core.test +package kotlinx.rpc.grpc.test.proto -//import StreamingTestService -//import kotlinx.coroutines.flow.* -//import kotlinx.rpc.RpcServer -//import kotlinx.rpc.withService -//import kotlin.test.Test -//import kotlin.test.assertEquals -// -//class StreamingTestServiceImpl : StreamingTestService { -// override fun Server(message: kotlinx.rpc.grpc.test.References): Flow { -// return flow { emit(message); emit(message); emit(message) } -// } -// -// override suspend fun Client(message: Flow): kotlinx.rpc.grpc.test.References { -// return message.last() -// } -// -// override fun Bidi(message: Flow): Flow { -// return message -// } -//} -// -//class StreamingTest : GrpcServerTest() { -// override fun RpcServer.registerServices() { -// registerService { StreamingTestServiceImpl() } -// } -// -// @Test -// fun testServerStreaming() = runGrpcTest { grpcClient -> -// val service = grpcClient.withService() -// service.Server(kotlinx.rpc.grpc.test.References { -// other = kotlinx.rpc.grpc.test.Other { -// field = 42 -// } -// }).toList().run { -// assertEquals(3, size) -// -// forEach { -// assertEquals(42, it.other.field) -// } -// } -// } -// -// @Test -// fun testClientStreaming() = runGrpcTest { grpcClient -> -// val service = grpcClient.withService() -// val result = service.Client(flow { -// repeat(3) { -// emit(kotlinx.rpc.grpc.test.References { -// other = kotlinx.rpc.grpc.test.Other { -// field = 42 + it -// } -// }) -// } -// }) -// -// assertEquals(44, result.other.field) -// } -// -// @Test -// fun testBidiStreaming() = runGrpcTest { grpcClient -> -// val service = grpcClient.withService() -// service.Bidi(flow { -// repeat(3) { -// emit(kotlinx.rpc.grpc.test.References { -// other = kotlinx.rpc.grpc.test.Other { -// field = 42 + it -// } -// }) -// } -// }).collectIndexed { i, it -> -// assertEquals(42 + i, it.other.field) -// } -// } -//} +import StreamingTestService +import kotlinx.coroutines.flow.* +import kotlinx.rpc.RpcServer +import kotlinx.rpc.grpc.test.invoke +import kotlinx.rpc.registerService +import kotlinx.rpc.withService +import kotlin.test.Test +import kotlin.test.assertEquals + +class StreamingTestServiceImpl : StreamingTestService { + override fun Server(message: kotlinx.rpc.grpc.test.References): Flow { + return flow { emit(message); emit(message); emit(message) } + } + + override suspend fun Client(message: Flow): kotlinx.rpc.grpc.test.References { + return message.last() + } + + override fun Bidi(message: Flow): Flow { + return message + } +} + +class StreamingTest : GrpcProtoTest() { + override fun RpcServer.registerServices() { + registerService { StreamingTestServiceImpl() } + } + + @Test + fun testServerStreaming() = runGrpcTest { grpcClient -> + val service = grpcClient.withService() + service.Server(kotlinx.rpc.grpc.test.References { + other = kotlinx.rpc.grpc.test.Other { + field = 42 + } + }).toList().run { + assertEquals(3, size) + + forEach { + assertEquals(42, it.other.field) + } + } + } + + @Test + fun testClientStreaming() = runGrpcTest { grpcClient -> + val service = grpcClient.withService() + val result = service.Client(flow { + repeat(3) { + emit(kotlinx.rpc.grpc.test.References { + other = kotlinx.rpc.grpc.test.Other { + field = 42 + it + } + }) + } + }) + + assertEquals(44, result.other.field) + } + + @Test + fun testBidiStreaming() = runGrpcTest { grpcClient -> + val service = grpcClient.withService() + service.Bidi(flow { + repeat(3) { + emit(kotlinx.rpc.grpc.test.References { + other = kotlinx.rpc.grpc.test.Other { + field = 42 + it + } + }) + } + }).collectIndexed { i, it -> + assertEquals(42 + i, it.other.field) + } + } +} diff --git a/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/proto/TestPrimitiveService.kt b/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/proto/TestPrimitiveService.kt index ef4875a01..d6dc495e6 100644 --- a/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/proto/TestPrimitiveService.kt +++ b/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/proto/TestPrimitiveService.kt @@ -2,33 +2,35 @@ * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ -package kotlinx.rpc.grpc.core.test +package kotlinx.rpc.grpc.test.proto -//import kotlinx.rpc.RpcServer -//import kotlinx.rpc.grpc.test.AllPrimitives -//import kotlinx.rpc.grpc.test.PrimitiveService -//import kotlinx.rpc.withService -//import kotlin.test.Test -//import kotlin.test.assertEquals +import kotlinx.rpc.RpcServer +import kotlinx.rpc.grpc.test.AllPrimitives +import kotlinx.rpc.grpc.test.PrimitiveService +import kotlinx.rpc.grpc.test.invoke +import kotlinx.rpc.registerService +import kotlinx.rpc.withService +import kotlin.test.Test +import kotlin.test.assertEquals -//class PrimitiveServiceImpl : PrimitiveService { -// override suspend fun Echo(message: AllPrimitives): AllPrimitives { -// return message -// } -//} -// -//class TestPrimitiveService : GrpcServerTest() { -// override fun RpcServer.registerServices() { -// registerService { PrimitiveServiceImpl() } -// } -// -// @Test -// fun testPrimitive(): Unit = runGrpcTest { grpcClient -> -// val service = grpcClient.withService() -// val result = service.Echo(AllPrimitives { -// int32 = 42 -// }) -// -// assertEquals(42, result.int32) -// } -//} +class PrimitiveServiceImpl : PrimitiveService { + override suspend fun Echo(message: AllPrimitives): AllPrimitives { + return message + } +} + +class TestPrimitiveService : GrpcProtoTest() { + override fun RpcServer.registerServices() { + registerService { PrimitiveServiceImpl() } + } + + @Test + fun testPrimitive() = runGrpcTest { grpcClient -> + val service = grpcClient.withService() + val result = service.Echo(AllPrimitives { + int32 = 42 + }) + + assertEquals(42, result.int32) + } +} diff --git a/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/proto/TestReferenceService.kt b/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/proto/TestReferenceService.kt index 983d62507..70d4c9e52 100644 --- a/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/proto/TestReferenceService.kt +++ b/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/proto/TestReferenceService.kt @@ -2,281 +2,278 @@ * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ -package kotlinx.rpc.grpc.core.test - -//import Other -//import ReferenceTestService -//import References -//import kotlinx.rpc.RpcServer -//import kotlinx.rpc.grpc.test.AllPrimitives -//import kotlinx.rpc.grpc.test.Nested -//import kotlinx.rpc.grpc.test.OneOf -//import kotlinx.rpc.grpc.test.OptionalTypes -//import kotlinx.rpc.grpc.test.Repeated -//import kotlinx.rpc.grpc.test.TestMap -//import kotlinx.rpc.grpc.test.UsingEnum -//import kotlinx.rpc.withService -//import kotlin.test.Test -//import kotlin.test.assertContentEquals -//import kotlin.test.assertEquals -//import kotlin.test.assertNotNull - -//class ReferenceTestServiceImpl : ReferenceTestService { -// override suspend fun Get(message: References): kotlinx.rpc.grpc.test.References { -// return kotlinx.rpc.grpc.test.References { -// other = kotlinx.rpc.grpc.test.Other { -// field = message.other.arg.toInt() -// } -// -// primitive = message.other.arg -// } -// } -// -// override suspend fun Enum(message: UsingEnum): UsingEnum { -// return message -// } -// -// override suspend fun Optional(message: OptionalTypes): OptionalTypes { -// return message -// } -// -// override suspend fun Repeated(message: Repeated): Repeated { -// return message -// } -// -// override suspend fun Nested(message: Nested): Nested { -// return message -// } -// -// override suspend fun Map(message: TestMap): TestMap { -// return message -// } -// -// override suspend fun OneOf(message: OneOf): OneOf { -// return message -// } -//} -// -//class TestReferenceService : GrpcServerTest() { -// override fun RpcServer.registerServices() { -// registerService { ReferenceTestServiceImpl() } -// } -// -// @Test -// fun testReferenceService() = runGrpcTest { grpcClient -> -// val service = grpcClient.withService() -// val arg = References { -// other = Other { -// arg = "42" -// } -// } -// -// val result = service.Get(arg) -// -// assertEquals("42", result.primitive) -// assertEquals(42, result.other.field) -// } -// -// @Test -// fun testEnum() = runGrpcTest { grpcClient -> -// val service = grpcClient.withService() -// val result = service.Enum(UsingEnum { -// enum = kotlinx.rpc.grpc.test.Enum.ONE -// }) -// -// assertEquals(kotlinx.rpc.grpc.test.Enum.ONE, result.enum) -// } -// -// @Test -// fun testOptional() = runGrpcTest { grpcClient -> -// val service = grpcClient.withService() -// val resultNotNull = service.Optional(OptionalTypes { -// name = "test" -// age = 42 -// reference = kotlinx.rpc.grpc.test.Other { -// field = 42 -// } -// }) -// -// assertEquals("test", resultNotNull.name) -// assertEquals(42, resultNotNull.age) -// assertEquals(42, resultNotNull.reference?.field) -// -// val resultNullable = service.Optional(OptionalTypes { -// name = null -// age = null -// reference = null -// }) -// -// assertEquals(null, resultNullable.name) -// assertEquals(null, resultNullable.age) +package kotlinx.rpc.grpc.test.proto + +import Other +import ReferenceTestService +import References +import invoke +import kotlinx.rpc.RpcServer +import kotlinx.rpc.grpc.test.AllPrimitives +import kotlinx.rpc.grpc.test.Nested +import kotlinx.rpc.grpc.test.OneOf +import kotlinx.rpc.grpc.test.OptionalTypes +import kotlinx.rpc.grpc.test.Repeated +import kotlinx.rpc.grpc.test.TestMap +import kotlinx.rpc.grpc.test.UsingEnum +import kotlinx.rpc.grpc.test.invoke +import kotlinx.rpc.registerService +import kotlinx.rpc.withService +import kotlin.test.Test +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals +import kotlin.test.assertNotNull + +class ReferenceTestServiceImpl : ReferenceTestService { + override suspend fun Get(message: References): kotlinx.rpc.grpc.test.References { + return kotlinx.rpc.grpc.test.References { + other = kotlinx.rpc.grpc.test.Other { + field = message.other.arg.toInt() + } + + primitive = message.other.arg + } + } + + override suspend fun Enum(message: UsingEnum): UsingEnum { + return message + } + + override suspend fun Optional(message: OptionalTypes): OptionalTypes { + return message + } + + override suspend fun Repeated(message: Repeated): Repeated { + return message + } + + override suspend fun Nested(message: Nested): Nested { + return message + } + + override suspend fun Map(message: TestMap): TestMap { + return message + } + + override suspend fun OneOf(message: OneOf): OneOf { + return message + } +} + +class TestReferenceService : GrpcProtoTest() { + override fun RpcServer.registerServices() { + registerService { ReferenceTestServiceImpl() } + } + + @Test + fun testReferenceService() = runGrpcTest { grpcClient -> + val service = grpcClient.withService() + val arg = References { + other = Other { + arg = "42" + } + } + + val result = service.Get(arg) + + assertEquals("42", result.primitive) + assertEquals(42, result.other.field) + } + + @Test + fun testEnum() = runGrpcTest { grpcClient -> + val service = grpcClient.withService() + val result = service.Enum(UsingEnum { + enum = kotlinx.rpc.grpc.test.Enum.ONE + }) + + assertEquals(kotlinx.rpc.grpc.test.Enum.ONE, result.enum) + } + + @Test + fun testOptional() = runGrpcTest { grpcClient -> + val service = grpcClient.withService() + val resultNotNull = service.Optional(OptionalTypes { + name = "test" + age = 42 + reference = kotlinx.rpc.grpc.test.Other { + field = 42 + } + }) + + assertEquals("test", resultNotNull.name) + assertEquals(42, resultNotNull.age) + assertEquals(42, resultNotNull.reference.field) + + val resultNullable = service.Optional(OptionalTypes { + name = null + age = null + }) + + assertEquals(null, resultNullable.name) + assertEquals(null, resultNullable.age) + // todo presence check // assertEquals(null, resultNullable.reference) -// } -// -// @Test -// fun testRepeated() = runGrpcTest { grpcClient -> -// val service = grpcClient.withService() -// val result = service.Repeated(Repeated { -// listFixed32 = listOf(0u, 1u, 2u) -// listInt32 = listOf(0, 1, 2) -// listString = listOf("test", "hello") -// listReference = listOf(kotlinx.rpc.grpc.test.References { -// other = kotlinx.rpc.grpc.test.Other { -// field = 42 -// } -// }) -// }) -// -// assertEquals(listOf("test", "hello"), result.listString) -// assertEquals(listOf(0u, 1u, 2u), result.listFixed32) -// assertEquals(listOf(0, 1, 2), result.listInt32) -// assertEquals(1, result.listReference.size) -// assertEquals(42, result.listReference[0].other.field) -// -// val resultEmpty = service.Repeated(Repeated {}) -// -// assertEquals(emptyList(), resultEmpty.listString) -// assertEquals(emptyList(), resultEmpty.listFixed32) -// assertEquals(emptyList(), resultEmpty.listInt32) -// assertEquals(emptyList(), resultEmpty.listReference) -// } -// -// @Test -// fun testNested() = runGrpcTest { grpcClient -> -// val service = grpcClient.withService() -// val result = service.Nested(Nested { -// inner1 = Nested.Inner1 { -// inner11 = Nested.Inner1.Inner11 { -// reference21 = null -// reference12 = Nested.Inner1.Inner12 { -// recursion = null -// } -// enum = Nested.Inner2.NestedEnum.ZERO -// } -// -// inner22 = Nested.Inner1.Inner12 { -// recursion = Nested.Inner1.Inner12 { -// recursion = null -// } -// } -// -// string = "42_1" -// -// inner1 = null -// } -// -// inner2 = Nested.Inner2 { -// inner21 = Nested.Inner2.Inner21 { -// reference11 = Nested.Inner1.Inner11 { -// reference21 = null -// reference12 = Nested.Inner1.Inner12 { -// recursion = null -// } -// enum = Nested.Inner2.NestedEnum.ZERO -// } -// -// reference22 = Nested.Inner2.Inner22 { -// enum = Nested.Inner2.NestedEnum.ZERO -// } -// } -// -// inner22 = Nested.Inner2.Inner22 { -// enum = Nested.Inner2.NestedEnum.ZERO -// } -// string = "42_2" -// } -// -// string = "42" -// enum = Nested.Inner2.NestedEnum.ZERO -// }) -// -// // Assert Inner1.Inner11 + } + + @Test + fun testRepeated() = runGrpcTest { grpcClient -> + val service = grpcClient.withService() + val result = service.Repeated(Repeated { + listFixed32 = listOf(0u, 1u, 2u) + listInt32 = listOf(0, 1, 2) + listString = listOf("test", "hello") + listReference = listOf(kotlinx.rpc.grpc.test.References { + other = kotlinx.rpc.grpc.test.Other { + field = 42 + } + }) + }) + + assertEquals(listOf("test", "hello"), result.listString) + assertEquals(listOf(0u, 1u, 2u), result.listFixed32) + assertEquals(listOf(0, 1, 2), result.listInt32) + assertEquals(1, result.listReference.size) + assertEquals(42, result.listReference[0].other.field) + + val resultEmpty = service.Repeated(Repeated {}) + + assertEquals(emptyList(), resultEmpty.listString) + assertEquals(emptyList(), resultEmpty.listFixed32) + assertEquals(emptyList(), resultEmpty.listInt32) + assertEquals(emptyList(), resultEmpty.listReference) + } + + @Test + fun testNested() = runGrpcTest { grpcClient -> + val service = grpcClient.withService() + val result = service.Nested(Nested { + inner1 = Nested.Inner1 { + inner11 = Nested.Inner1.Inner11 { + reference12 = Nested.Inner1.Inner12 { } + enum = Nested.Inner2.NestedEnum.ZERO + } + + inner22 = Nested.Inner1.Inner12 { + recursion = Nested.Inner1.Inner12 { } + } + + string = "42_1" + } + + inner2 = Nested.Inner2 { + inner21 = Nested.Inner2.Inner21 { + reference11 = Nested.Inner1.Inner11 { + reference12 = Nested.Inner1.Inner12 { } + enum = Nested.Inner2.NestedEnum.ZERO + } + + reference22 = Nested.Inner2.Inner22 { + enum = Nested.Inner2.NestedEnum.ZERO + } + } + + inner22 = Nested.Inner2.Inner22 { + enum = Nested.Inner2.NestedEnum.ZERO + } + string = "42_2" + } + + string = "42" + enum = Nested.Inner2.NestedEnum.ZERO + }) + + // Assert Inner1.Inner11 + // todo presence check // assertEquals(null, result.inner1.inner11.reference21) // assertEquals(null, result.inner1.inner11.reference12.recursion) -// assertEquals(Nested.Inner2.NestedEnum.ZERO, result.inner1.inner11.enum) -// -// // Assert Inner1.Inner12 -// assertNotNull(result.inner1.inner22.recursion) -// assertEquals(null, result.inner1.inner22.recursion?.recursion) -// -// // Assert Inner1 -// assertEquals("42_1", result.inner1.string) + assertEquals(Nested.Inner2.NestedEnum.ZERO, result.inner1.inner11.enum) + + // Assert Inner1.Inner12 + assertNotNull(result.inner1.inner22.recursion) + // todo presence check +// assertEquals(null, result.inner1.inner22.recursion.recursion) + + // Assert Inner1 + assertEquals("42_1", result.inner1.string) + // todo presence check // assertEquals(null, result.inner1.inner1) -// -// // Assert Inner2.Inner21 + + // Assert Inner2.Inner21 + // todo presence check // assertEquals(null, result.inner2.inner21.reference11.reference21) // assertEquals(null, result.inner2.inner21.reference11.reference12.recursion) -// assertEquals(Nested.Inner2.NestedEnum.ZERO, result.inner2.inner21.reference11.enum) -// assertEquals(Nested.Inner2.NestedEnum.ZERO, result.inner2.inner21.reference22.enum) -// -// // Assert Inner2.Inner22 -// assertEquals(Nested.Inner2.NestedEnum.ZERO, result.inner2.inner22.enum) -// -// // Assert Inner2 -// assertEquals("42_2", result.inner2.string) -// -// // Assert root Nested -// assertEquals("42", result.string) -// assertEquals(Nested.Inner2.NestedEnum.ZERO, result.enum) -// } -// -// @Test -// fun testMap() = runGrpcTest { grpcClient -> -// val service = grpcClient.withService() -// val result = service.Map(TestMap { -// primitives = mapOf("1" to 2, "2" to 1) -// references = mapOf("ref" to kotlinx.rpc.grpc.test.References { -// other = kotlinx.rpc.grpc.test.Other { -// field = 42 -// } -// }) -// }) -// -// assertEquals(mapOf("1" to 2L, "2" to 1L), result.primitives) -// assertEquals(mapOf("ref" to 42), result.references.mapValues { it.value.other.field }) -// } -// -// @Test -// fun testOneOf() = runGrpcTest { grpcClient -> -// val service = grpcClient.withService() -// val result1 = service.OneOf(OneOf { -// primitives = OneOf.Primitives.StringValue("42") -// references = OneOf.References.Other(kotlinx.rpc.grpc.test.Other { -// field = 42 -// }) -// mixed = OneOf.Mixed.Int64(42L) -// single = OneOf.Single.Bytes(byteArrayOf(42)) -// }) -// -// assertEquals("42", (result1.primitives as OneOf.Primitives.StringValue).value) -// assertEquals(42, (result1.references as OneOf.References.Other).value.field) -// assertEquals(42L, (result1.mixed as OneOf.Mixed.Int64).value) -// assertContentEquals(byteArrayOf(42), (result1.single as OneOf.Single.Bytes).value) -// -// val result2 = service.OneOf(OneOf { -// primitives = OneOf.Primitives.Bool(true) -// references = OneOf.References.InnerReferences(kotlinx.rpc.grpc.test.References { -// other = kotlinx.rpc.grpc.test.Other { -// field = 42 -// } -// }) -// mixed = OneOf.Mixed.AllPrimitives(AllPrimitives { -// string = "42" -// }) -// }) -// -// assertEquals(true, (result2.primitives as OneOf.Primitives.Bool).value) -// assertEquals(42, (result2.references as OneOf.References.InnerReferences).value.other.field) -// assertEquals("42", (result2.mixed as OneOf.Mixed.AllPrimitives).value.string) -// assertEquals(null, result2.single) -// -// val result3 = service.OneOf(OneOf { -// primitives = OneOf.Primitives.Int32(42) -// }) -// -// assertEquals(42, (result3.primitives as OneOf.Primitives.Int32).value) -// assertEquals(null, result3.references) -// assertEquals(null, result3.mixed) -// assertEquals(null, result3.single) -// } -//} + assertEquals(Nested.Inner2.NestedEnum.ZERO, result.inner2.inner21.reference11.enum) + assertEquals(Nested.Inner2.NestedEnum.ZERO, result.inner2.inner21.reference22.enum) + + // Assert Inner2.Inner22 + assertEquals(Nested.Inner2.NestedEnum.ZERO, result.inner2.inner22.enum) + + // Assert Inner2 + assertEquals("42_2", result.inner2.string) + + // Assert root Nested + assertEquals("42", result.string) + assertEquals(Nested.Inner2.NestedEnum.ZERO, result.enum) + } + + @Test + fun testMap() = runGrpcTest { grpcClient -> + val service = grpcClient.withService() + val result = service.Map(TestMap { + primitives = mapOf("1" to 2, "2" to 1) + references = mapOf("ref" to kotlinx.rpc.grpc.test.References { + other = kotlinx.rpc.grpc.test.Other { + field = 42 + } + }) + }) + + assertEquals(mapOf("1" to 2L, "2" to 1L), result.primitives) + assertEquals(mapOf("ref" to 42), result.references.mapValues { it.value.other.field }) + } + + @Test + fun testOneOf() = runGrpcTest { grpcClient -> + val service = grpcClient.withService() + val result1 = service.OneOf(OneOf { + primitives = OneOf.Primitives.StringValue("42") + references = OneOf.References.Other(kotlinx.rpc.grpc.test.Other { + field = 42 + }) + mixed = OneOf.Mixed.Int64(42L) + single = OneOf.Single.Bytes(byteArrayOf(42)) + }) + + assertEquals("42", (result1.primitives as OneOf.Primitives.StringValue).value) + assertEquals(42, (result1.references as OneOf.References.Other).value.field) + assertEquals(42L, (result1.mixed as OneOf.Mixed.Int64).value) + assertContentEquals(byteArrayOf(42), (result1.single as OneOf.Single.Bytes).value) + + val result2 = service.OneOf(OneOf { + primitives = OneOf.Primitives.Bool(true) + references = OneOf.References.InnerReferences(kotlinx.rpc.grpc.test.References { + other = kotlinx.rpc.grpc.test.Other { + field = 42 + } + }) + mixed = OneOf.Mixed.AllPrimitives(AllPrimitives { + string = "42" + }) + }) + + assertEquals(true, (result2.primitives as OneOf.Primitives.Bool).value) + assertEquals(42, (result2.references as OneOf.References.InnerReferences).value.other.field) + assertEquals("42", (result2.mixed as OneOf.Mixed.AllPrimitives).value.string) + assertEquals(null, result2.single) + + val result3 = service.OneOf(OneOf { + primitives = OneOf.Primitives.Int32(42) + }) + + assertEquals(42, (result3.primitives as OneOf.Primitives.Int32).value) + assertEquals(null, result3.references) + assertEquals(null, result3.mixed) + assertEquals(null, result3.single) + } +} diff --git a/grpc/grpc-core/src/commonTest/proto/all_primitives_grpc.proto b/grpc/grpc-core/src/commonTest/proto/all_primitives_grpc.proto new file mode 100644 index 000000000..be698f9e6 --- /dev/null +++ b/grpc/grpc-core/src/commonTest/proto/all_primitives_grpc.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; + +package kotlinx.rpc.grpc.test; + +message AllPrimitives { + double double = 1; + float float = 2; + int32 int32 = 3; + int64 int64 = 4; + uint32 uint32 = 5; + uint64 uint64 = 6; + sint32 sint32 = 7; + sint64 sint64 = 8; + fixed32 fixed32 = 9; + fixed64 fixed64 = 10; + sfixed32 sfixed32 = 11; + sfixed64 sfixed64 = 12; + bool bool = 13; + string string = 14; + bytes bytes = 15; +} diff --git a/grpc/grpc-core/src/commonTest/proto/enum_grpc.proto b/grpc/grpc-core/src/commonTest/proto/enum_grpc.proto new file mode 100644 index 000000000..83db7b7fe --- /dev/null +++ b/grpc/grpc-core/src/commonTest/proto/enum_grpc.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; + +package kotlinx.rpc.grpc.test; + +enum Enum { + option allow_alias = true; + ZERO = 0; + ONE = 1; + ONE_SECOND = 1; + TWO = 2 [deprecated = true]; + THREE = 3; +} + +message UsingEnum { + Enum enum = 1; +} diff --git a/grpc/grpc-core/src/commonTest/proto/exclude/empty_deprecated.proto b/grpc/grpc-core/src/commonTest/proto/exclude/empty_deprecated.proto deleted file mode 100644 index dcb1e64c9..000000000 --- a/grpc/grpc-core/src/commonTest/proto/exclude/empty_deprecated.proto +++ /dev/null @@ -1,7 +0,0 @@ -syntax = "proto3"; - -package kotlinx.rpc.grpc.test; - -message EmptyDeprecated { - option deprecated = true; -} diff --git a/grpc/grpc-core/src/commonTest/proto/exclude/enum_options.proto b/grpc/grpc-core/src/commonTest/proto/exclude/enum_options.proto deleted file mode 100644 index 12ecd3723..000000000 --- a/grpc/grpc-core/src/commonTest/proto/exclude/enum_options.proto +++ /dev/null @@ -1,22 +0,0 @@ -syntax = "proto3"; - -package kotlinx.rpc.grpc.test; - -import "google/protobuf/descriptor.proto"; -//import "options.proto"; - -//extend google.protobuf.EnumValueOptions { -// optional Options options = 50000; -//} - -enum EnumOptions { - option allow_alias = true; - ZERO = 0; - ONE = 1; - ONE_SECOND = 1; - TWO = 2 [deprecated = true]; - THREE = 3; // [ -// (options).string = "three", -// (options).inner.string = "inner three" - //]; -} diff --git a/grpc/grpc-core/src/commonTest/proto/exclude/example.proto b/grpc/grpc-core/src/commonTest/proto/exclude/example.proto deleted file mode 100644 index 284f0cc23..000000000 --- a/grpc/grpc-core/src/commonTest/proto/exclude/example.proto +++ /dev/null @@ -1,25 +0,0 @@ -syntax = "proto3"; - -message Address { - string street = 1; - City city = 2; - - enum City { - ROME = 0; - BERLIN = 1; - LONDON = 2; - } -} - -message User { - int64 id = 1; - string name = 2; - bool married = 3; - repeated User friends = 4; - optional User spouse = 5; - Address address = 6; - oneof contact { - string email = 7; - string phone = 8; - } -} diff --git a/grpc/grpc-core/src/commonTest/proto/exclude/multiple_files.proto b/grpc/grpc-core/src/commonTest/proto/exclude/multiple_files.proto deleted file mode 100644 index 49195a10b..000000000 --- a/grpc/grpc-core/src/commonTest/proto/exclude/multiple_files.proto +++ /dev/null @@ -1,26 +0,0 @@ -syntax = "proto3"; - -package kotlinx.rpc.protobuf; - -option java_multiple_files = true; -option java_outer_classname = "MultipleFilesNewClassName"; -option java_package = "kotlinx.rpc.protobuf"; - -message Hello { - string hello = 1; -} - -message World { - string world = 1; - - message Nested { - string nested = 2; - } - - Nested nested = 3; -} - -enum Enum { - ZERO = 0; -} - diff --git a/grpc/grpc-core/src/commonTest/proto/exclude/options.proto b/grpc/grpc-core/src/commonTest/proto/exclude/options.proto deleted file mode 100644 index df77c8d6d..000000000 --- a/grpc/grpc-core/src/commonTest/proto/exclude/options.proto +++ /dev/null @@ -1,12 +0,0 @@ -syntax = "proto3"; - -package kotlinx.rpc.grpc.test; - -message Options { - message Inner { - string string = 1; - } - - string string = 1; - Inner inner = 2; -} diff --git a/grpc/grpc-core/src/commonTest/proto/exclude/with_comments.proto b/grpc/grpc-core/src/commonTest/proto/exclude/with_comments.proto deleted file mode 100644 index fe43f59ee..000000000 --- a/grpc/grpc-core/src/commonTest/proto/exclude/with_comments.proto +++ /dev/null @@ -1,9 +0,0 @@ -syntax = "proto3"; - -package kotlinx.rpc.grpc.test; - -// This message has comment -message WithComments { - // and this field too. - string string = 1; -} diff --git a/grpc/grpc-core/src/commonTest/proto/exclude/image-recognizer.proto b/grpc/grpc-core/src/commonTest/proto/image-recognizer.proto similarity index 100% rename from grpc/grpc-core/src/commonTest/proto/exclude/image-recognizer.proto rename to grpc/grpc-core/src/commonTest/proto/image-recognizer.proto diff --git a/grpc/grpc-core/src/commonTest/proto/exclude/nested.proto b/grpc/grpc-core/src/commonTest/proto/nested_grpc.proto similarity index 100% rename from grpc/grpc-core/src/commonTest/proto/exclude/nested.proto rename to grpc/grpc-core/src/commonTest/proto/nested_grpc.proto diff --git a/grpc/grpc-core/src/commonTest/proto/exclude/one_of.proto b/grpc/grpc-core/src/commonTest/proto/one_of_grpc.proto similarity index 71% rename from grpc/grpc-core/src/commonTest/proto/exclude/one_of.proto rename to grpc/grpc-core/src/commonTest/proto/one_of_grpc.proto index b096aa9d2..d603a696d 100644 --- a/grpc/grpc-core/src/commonTest/proto/exclude/one_of.proto +++ b/grpc/grpc-core/src/commonTest/proto/one_of_grpc.proto @@ -2,8 +2,8 @@ syntax = "proto3"; package kotlinx.rpc.grpc.test; -import "all_primitives.proto"; -import "reference_package.proto"; +import "all_primitives_grpc.proto"; +import "reference_package_grpc.proto"; message OneOf { oneof primitives { @@ -19,7 +19,7 @@ message OneOf { oneof mixed { int64 int64 = 6; - AllPrimitives allPrimitives = 7; + kotlinx.rpc.grpc.test.AllPrimitives allPrimitives = 7; } oneof single { diff --git a/grpc/grpc-core/src/commonTest/proto/exclude/optional.proto b/grpc/grpc-core/src/commonTest/proto/optional_grpc.proto similarity index 80% rename from grpc/grpc-core/src/commonTest/proto/exclude/optional.proto rename to grpc/grpc-core/src/commonTest/proto/optional_grpc.proto index 7bed51cc5..3444fb845 100644 --- a/grpc/grpc-core/src/commonTest/proto/exclude/optional.proto +++ b/grpc/grpc-core/src/commonTest/proto/optional_grpc.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package kotlinx.rpc.grpc.test; -import 'reference_package.proto'; +import 'reference_package_grpc.proto'; message OptionalTypes { optional string name = 1; diff --git a/grpc/grpc-core/src/commonTest/proto/exclude/primitive_service.proto b/grpc/grpc-core/src/commonTest/proto/primitive_service.proto similarity index 78% rename from grpc/grpc-core/src/commonTest/proto/exclude/primitive_service.proto rename to grpc/grpc-core/src/commonTest/proto/primitive_service.proto index aac406f19..a030a1d52 100644 --- a/grpc/grpc-core/src/commonTest/proto/exclude/primitive_service.proto +++ b/grpc/grpc-core/src/commonTest/proto/primitive_service.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package kotlinx.rpc.grpc.test; -import "all_primitives.proto"; +import "all_primitives_grpc.proto"; service PrimitiveService { rpc Echo(AllPrimitives) returns (AllPrimitives); diff --git a/grpc/grpc-core/src/commonTest/proto/reference_grpc.proto b/grpc/grpc-core/src/commonTest/proto/reference_grpc.proto new file mode 100644 index 000000000..4a68c5189 --- /dev/null +++ b/grpc/grpc-core/src/commonTest/proto/reference_grpc.proto @@ -0,0 +1,9 @@ +syntax = "proto3"; + +message Other { + string arg = 1; +} + +message References { + Other other = 2; +} diff --git a/grpc/grpc-core/src/commonTest/proto/exclude/reference_package.proto b/grpc/grpc-core/src/commonTest/proto/reference_package_grpc.proto similarity index 100% rename from grpc/grpc-core/src/commonTest/proto/exclude/reference_package.proto rename to grpc/grpc-core/src/commonTest/proto/reference_package_grpc.proto diff --git a/grpc/grpc-core/src/commonTest/proto/exclude/reference_service.proto b/grpc/grpc-core/src/commonTest/proto/reference_service.proto similarity index 72% rename from grpc/grpc-core/src/commonTest/proto/exclude/reference_service.proto rename to grpc/grpc-core/src/commonTest/proto/reference_service.proto index c3fd1a012..644af9023 100644 --- a/grpc/grpc-core/src/commonTest/proto/exclude/reference_service.proto +++ b/grpc/grpc-core/src/commonTest/proto/reference_service.proto @@ -1,13 +1,13 @@ syntax = "proto3"; -import "reference.proto"; -import "reference_package.proto"; -import "enum.proto"; -import "optional.proto"; -import "repeated.proto"; -import "nested.proto"; -import "test_map.proto"; -import "one_of.proto"; +import "reference_grpc.proto"; +import "reference_package_grpc.proto"; +import "enum_grpc.proto"; +import "optional_grpc.proto"; +import "repeated_grpc.proto"; +import "nested_grpc.proto"; +import "test_map_grpc.proto"; +import "one_of_grpc.proto"; service ReferenceTestService { rpc Get(References) returns (kotlinx.rpc.grpc.test.References); diff --git a/grpc/grpc-core/src/commonTest/proto/repeated_grpc.proto b/grpc/grpc-core/src/commonTest/proto/repeated_grpc.proto new file mode 100644 index 000000000..2a2047c77 --- /dev/null +++ b/grpc/grpc-core/src/commonTest/proto/repeated_grpc.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; + +package kotlinx.rpc.grpc.test; + +import 'reference_package_grpc.proto'; + +message Repeated { + repeated string listString = 1; + repeated References listReference = 2; + repeated fixed32 listFixed32 = 3; + repeated int32 listInt32 = 4; +} diff --git a/grpc/grpc-core/src/commonTest/proto/exclude/streaming.proto b/grpc/grpc-core/src/commonTest/proto/streaming.proto similarity index 90% rename from grpc/grpc-core/src/commonTest/proto/exclude/streaming.proto rename to grpc/grpc-core/src/commonTest/proto/streaming.proto index 042383a65..d87128c5e 100644 --- a/grpc/grpc-core/src/commonTest/proto/exclude/streaming.proto +++ b/grpc/grpc-core/src/commonTest/proto/streaming.proto @@ -1,6 +1,6 @@ syntax = "proto3"; -import "reference_package.proto"; +import "reference_package_grpc.proto"; service StreamingTestService { rpc Server(kotlinx.rpc.grpc.test.References) returns (stream kotlinx.rpc.grpc.test.References); diff --git a/grpc/grpc-core/src/commonTest/proto/test_map_grpc.proto b/grpc/grpc-core/src/commonTest/proto/test_map_grpc.proto new file mode 100644 index 000000000..4114b1242 --- /dev/null +++ b/grpc/grpc-core/src/commonTest/proto/test_map_grpc.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; + +package kotlinx.rpc.grpc.test; + +import "reference_package_grpc.proto"; + +message TestMap { + map primitives = 1; + map references = 2; +} + diff --git a/grpc/grpc-core/src/jvmMain/kotlin/kotlinx/rpc/grpc/internal/MethodDescriptor.jvm.kt b/grpc/grpc-core/src/jvmMain/kotlin/kotlinx/rpc/grpc/internal/MethodDescriptor.jvm.kt index 5f90a894a..5aec16360 100644 --- a/grpc/grpc-core/src/jvmMain/kotlin/kotlinx/rpc/grpc/internal/MethodDescriptor.jvm.kt +++ b/grpc/grpc-core/src/jvmMain/kotlin/kotlinx/rpc/grpc/internal/MethodDescriptor.jvm.kt @@ -4,13 +4,9 @@ package kotlinx.rpc.grpc.internal -import kotlinx.io.asInputStream -import kotlinx.io.asSource -import kotlinx.io.buffered import kotlinx.rpc.grpc.codec.MessageCodec import kotlinx.rpc.internal.utils.InternalRpcApi - -internal actual typealias InputStream = java.io.InputStream +import java.io.InputStream internal actual typealias MethodDescriptor = io.grpc.MethodDescriptor @@ -35,11 +31,11 @@ internal val MethodType.asJvm: io.grpc.MethodDescriptor.MethodType private fun MessageCodec.toJvm(): io.grpc.MethodDescriptor.Marshaller { return object : io.grpc.MethodDescriptor.Marshaller { override fun stream(value: T): InputStream { - return encode(value).asInputStream() + return encode(value) } override fun parse(stream: InputStream): T { - return decode(stream.asSource().buffered()) + return decode(stream) } } } diff --git a/grpc/grpc-core/src/nativeMain/kotlin/kotlinx/rpc/grpc/internal/MethodDescriptor.native.kt b/grpc/grpc-core/src/nativeMain/kotlin/kotlinx/rpc/grpc/internal/MethodDescriptor.native.kt index 4b543294f..a4774b52c 100644 --- a/grpc/grpc-core/src/nativeMain/kotlin/kotlinx/rpc/grpc/internal/MethodDescriptor.native.kt +++ b/grpc/grpc-core/src/nativeMain/kotlin/kotlinx/rpc/grpc/internal/MethodDescriptor.native.kt @@ -6,9 +6,7 @@ package kotlinx.rpc.grpc.internal import kotlinx.rpc.grpc.codec.MessageCodec import kotlinx.rpc.internal.utils.InternalRpcApi - -@InternalRpcApi -public actual abstract class InputStream +import kotlinx.rpc.protobuf.input.stream.InputStream @InternalRpcApi internal actual val MethodDescriptor<*, *>.type: MethodType diff --git a/krpc/krpc-serialization/krpc-serialization-core/api/krpc-serialization-core.api b/krpc/krpc-serialization/krpc-serialization-core/api/krpc-serialization-core.api index 78a34cca3..0382934af 100644 --- a/krpc/krpc-serialization/krpc-serialization-core/api/krpc-serialization-core.api +++ b/krpc/krpc-serialization/krpc-serialization-core/api/krpc-serialization-core.api @@ -1,7 +1,6 @@ public abstract interface class kotlinx/rpc/krpc/serialization/KrpcSerialFormat { public abstract fun applySerializersModule (Ljava/lang/Object;Lkotlinx/serialization/modules/SerializersModule;)V public abstract fun withBuilder (Lkotlinx/serialization/SerialFormat;Lkotlin/jvm/functions/Function1;)Lkotlinx/serialization/SerialFormat; - public static synthetic fun withBuilder$default (Lkotlinx/rpc/krpc/serialization/KrpcSerialFormat;Lkotlinx/serialization/SerialFormat;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlinx/serialization/SerialFormat; } public final class kotlinx/rpc/krpc/serialization/KrpcSerialFormat$DefaultImpls { diff --git a/protobuf/protobuf-core/api/protobuf-core.api b/protobuf/protobuf-core/api/protobuf-core.api new file mode 100644 index 000000000..c0f086f4c --- /dev/null +++ b/protobuf/protobuf-core/api/protobuf-core.api @@ -0,0 +1,29 @@ +public final class kotlinx/rpc/protobuf/internal/ProtobufDecodingException : kotlinx/rpc/protobuf/internal/ProtobufException { + public static final field Companion Lkotlinx/rpc/protobuf/internal/ProtobufDecodingException$Companion; + public fun (Ljava/lang/String;Ljava/lang/Throwable;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/Throwable;ILkotlin/jvm/internal/DefaultConstructorMarker;)V +} + +public final class kotlinx/rpc/protobuf/internal/ProtobufDecodingException$Companion { +} + +public final class kotlinx/rpc/protobuf/internal/ProtobufEncodingException : kotlinx/rpc/protobuf/internal/ProtobufException { + public fun (Ljava/lang/String;Ljava/lang/Throwable;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/Throwable;ILkotlin/jvm/internal/DefaultConstructorMarker;)V +} + +public abstract class kotlinx/rpc/protobuf/internal/ProtobufException : java/lang/RuntimeException { + public synthetic fun (Ljava/lang/String;Ljava/lang/Throwable;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/Throwable;Lkotlin/jvm/internal/DefaultConstructorMarker;)V +} + +public final class kotlinx/rpc/protobuf/internal/WireDecoder_jvmKt { + public static final fun WireDecoder (Ljava/io/InputStream;)Lkotlinx/rpc/protobuf/internal/WireDecoder; + public static final fun checkForPlatformDecodeException (Lkotlin/jvm/functions/Function0;)V +} + +public final class kotlinx/rpc/protobuf/internal/WireEncoder_jvmKt { + public static final fun WireEncoder (Lkotlinx/io/Sink;)Lkotlinx/rpc/protobuf/internal/WireEncoder; + public static final fun checkForPlatformEncodeException (Lkotlin/jvm/functions/Function0;)V +} + diff --git a/protobuf/protobuf-core/api/protobuf-core.klib.api b/protobuf/protobuf-core/api/protobuf-core.klib.api new file mode 100644 index 000000000..d1b363c75 --- /dev/null +++ b/protobuf/protobuf-core/api/protobuf-core.klib.api @@ -0,0 +1,24 @@ +// Klib ABI Dump +// Targets: [macosArm64] +// Rendering settings: +// - Signature version: 2 +// - Show manifest properties: true +// - Show declarations: true + +// Library unique name: +final class kotlinx.rpc.protobuf.internal/ProtobufDecodingException : kotlinx.rpc.protobuf.internal/ProtobufException { // kotlinx.rpc.protobuf.internal/ProtobufDecodingException|null[0] + constructor (kotlin/String, kotlin/Throwable? = ...) // kotlinx.rpc.protobuf.internal/ProtobufDecodingException.|(kotlin.String;kotlin.Throwable?){}[0] + + final object Companion // kotlinx.rpc.protobuf.internal/ProtobufDecodingException.Companion|null[0] +} + +final class kotlinx.rpc.protobuf.internal/ProtobufEncodingException : kotlinx.rpc.protobuf.internal/ProtobufException { // kotlinx.rpc.protobuf.internal/ProtobufEncodingException|null[0] + constructor (kotlin/String, kotlin/Throwable? = ...) // kotlinx.rpc.protobuf.internal/ProtobufEncodingException.|(kotlin.String;kotlin.Throwable?){}[0] +} + +sealed class kotlinx.rpc.protobuf.internal/ProtobufException : kotlin/RuntimeException // kotlinx.rpc.protobuf.internal/ProtobufException|null[0] + +final fun kotlinx.rpc.protobuf.internal/WireDecoder(kotlinx.rpc.protobuf.input.stream/BufferInputStream): kotlinx.rpc.protobuf.internal/WireDecoder // kotlinx.rpc.protobuf.internal/WireDecoder|WireDecoder(kotlinx.rpc.protobuf.input.stream.BufferInputStream){}[0] +final fun kotlinx.rpc.protobuf.internal/WireEncoder(kotlinx.io/Sink): kotlinx.rpc.protobuf.internal/WireEncoder // kotlinx.rpc.protobuf.internal/WireEncoder|WireEncoder(kotlinx.io.Sink){}[0] +final inline fun kotlinx.rpc.protobuf.internal/checkForPlatformDecodeException(kotlin/Function0) // kotlinx.rpc.protobuf.internal/checkForPlatformDecodeException|checkForPlatformDecodeException(kotlin.Function0){}[0] +final inline fun kotlinx.rpc.protobuf.internal/checkForPlatformEncodeException(kotlin/Function0) // kotlinx.rpc.protobuf.internal/checkForPlatformEncodeException|checkForPlatformEncodeException(kotlin.Function0){}[0] diff --git a/protobuf/protobuf-core/build.gradle.kts b/protobuf/protobuf-core/build.gradle.kts index fdc7b1592..d75a73515 100644 --- a/protobuf/protobuf-core/build.gradle.kts +++ b/protobuf/protobuf-core/build.gradle.kts @@ -18,6 +18,7 @@ kotlin { commonMain { dependencies { api(projects.utils) + api(projects.protobuf.protobufInputStream) api(libs.kotlinx.io.core) } } diff --git a/protobuf/protobuf-core/src/commonMain/kotlin/kotlinx/rpc/protobuf/internal/WireDecoder.kt b/protobuf/protobuf-core/src/commonMain/kotlin/kotlinx/rpc/protobuf/internal/WireDecoder.kt index 6b5d6fd4c..f010f44b9 100644 --- a/protobuf/protobuf-core/src/commonMain/kotlin/kotlinx/rpc/protobuf/internal/WireDecoder.kt +++ b/protobuf/protobuf-core/src/commonMain/kotlin/kotlinx/rpc/protobuf/internal/WireDecoder.kt @@ -6,6 +6,7 @@ package kotlinx.rpc.protobuf.internal import kotlinx.io.Buffer import kotlinx.rpc.internal.utils.InternalRpcApi +import kotlinx.rpc.protobuf.input.stream.InputStream // TODO: Evaluate if this buffer size is suitable for all targets (KRPC-186) // maximum buffer size to allocate as contiguous memory in bytes @@ -116,4 +117,4 @@ public expect inline fun checkForPlatformDecodeException(block: () -> Unit) * @param source The buffer containing the encoded wire-format data. */ @InternalRpcApi -public expect fun WireDecoder(source: Buffer): WireDecoder +public expect fun WireDecoder(source: InputStream): WireDecoder diff --git a/protobuf/protobuf-core/src/commonTest/kotlin/kotlinx/rpc/protobuf/test/ProtosTest.kt b/protobuf/protobuf-core/src/commonTest/kotlin/kotlinx/rpc/protobuf/test/ProtosTest.kt index 1c26009ae..65338c867 100644 --- a/protobuf/protobuf-core/src/commonTest/kotlin/kotlinx/rpc/protobuf/test/ProtosTest.kt +++ b/protobuf/protobuf-core/src/commonTest/kotlin/kotlinx/rpc/protobuf/test/ProtosTest.kt @@ -14,10 +14,8 @@ import encodeWith import invoke import kotlinx.io.Buffer import kotlinx.rpc.grpc.codec.MessageCodec -import kotlinx.rpc.grpc.test.* -import kotlinx.rpc.grpc.test.common.* -import kotlinx.rpc.grpc.test.common.invoke -import kotlinx.rpc.grpc.test.invoke +import kotlinx.rpc.protobuf.input.stream.asInputStream +import kotlinx.rpc.protobuf.input.stream.asSource import kotlinx.rpc.protobuf.internal.ProtobufDecodingException import kotlinx.rpc.protobuf.internal.WireEncoder import test.nested.* @@ -53,7 +51,7 @@ class ProtosTest { encoder.writeFixed32(9, 1234u) encoder.flush() - val decoded = AllPrimitivesInternal.CODEC.decode(buffer) + val decoded = AllPrimitivesInternal.CODEC.decode(buffer.asInputStream()) assertEquals(12, decoded.sint32) assertNull(decoded.sint64) assertEquals(1234u, decoded.fixed32) @@ -134,7 +132,7 @@ class ProtosTest { encoder.flush() assertFailsWith { - PresenceCheckInternal.CODEC.decode(buffer) + PresenceCheckInternal.CODEC.decode(buffer.asInputStream()) } } @@ -146,7 +144,7 @@ class ProtosTest { encoder.writeEnum(1, 50) encoder.flush() - val decodedMsg = UsingEnumInternal.CODEC.decode(buffer) + val decodedMsg = UsingEnumInternal.CODEC.decode(buffer.asInputStream()) assertEquals(MyEnum.UNRECOGNIZED(50), decodedMsg.enum) } @@ -166,11 +164,11 @@ class ProtosTest { // create message without enum field set val msg = UsingEnum {} - val buffer = UsingEnumInternal.CODEC.encode(msg) as Buffer + val buffer = UsingEnumInternal.CODEC.encode(msg).asSource() // buffer should be empty (default is not in wire) - assertEquals(0, buffer.size) + assertTrue(buffer.exhausted()) - val decoded = UsingEnumInternal.CODEC.decode(buffer) + val decoded = UsingEnumInternal.CODEC.decode(buffer.asInputStream()) assertEquals(MyEnum.ZERO, decoded.enum) } @@ -228,7 +226,7 @@ class ProtosTest { encoder.flush() - val decoded = OneOfMsgInternal.CODEC.decode(buffer) + val decoded = OneOfMsgInternal.CODEC.decode(buffer.asInputStream()) assertIs(decoded.field) val decodedOther = (decoded.field as OneOfMsg.Field.Other).value assertEquals("arg2", decodedOther.arg2) @@ -246,7 +244,7 @@ class ProtosTest { encoder.writeFixed64(3, 123u) encoder.flush() - val decoded = OneOfMsgInternal.CODEC.decode(buffer) + val decoded = OneOfMsgInternal.CODEC.decode(buffer.asInputStream()) assertEquals(OneOfMsg.Field.Fixed(123u), decoded.field) } @@ -266,7 +264,7 @@ class ProtosTest { // write two values on the oneOf field. // the second value must be the one stored during decoding. val buffer = Buffer() - val decoded = OneOfMsgInternal.CODEC.decode(buffer) + val decoded = OneOfMsgInternal.CODEC.decode(buffer.asInputStream()) assertNull(decoded.field) } @@ -284,7 +282,7 @@ class ProtosTest { @Test fun testRecursiveReqNotSet() { assertFailsWith { - val msg = RecursiveReq { + RecursiveReq { rec = RecursiveReq { rec = RecursiveReq { @@ -373,7 +371,7 @@ class ProtosTest { encoder.writeMessage(1, secondPart as OtherInternal) { encodeWith(encoder) } encoder.flush() - val decoded = ReferenceInternal.CODEC.decode(buffer) + val decoded = ReferenceInternal.CODEC.decode(buffer.asInputStream()) assertEquals("first", decoded.other.arg1) assertEquals("third", decoded.other.arg2) assertEquals("fourth", decoded.other.arg3) @@ -405,7 +403,7 @@ class ProtosTest { val missingRequiredMessage = PresenceCheckInternal() assertFailsWith { - val msg = TestMap { + TestMap { messages = mapOf( 2 to missingRequiredMessage ) diff --git a/protobuf/protobuf-core/src/commonTest/kotlin/kotlinx/rpc/protobuf/test/WireCodecTest.kt b/protobuf/protobuf-core/src/commonTest/kotlin/kotlinx/rpc/protobuf/test/WireCodecTest.kt index aaeacbe0d..b0967e45a 100644 --- a/protobuf/protobuf-core/src/commonTest/kotlin/kotlinx/rpc/protobuf/test/WireCodecTest.kt +++ b/protobuf/protobuf-core/src/commonTest/kotlin/kotlinx/rpc/protobuf/test/WireCodecTest.kt @@ -5,6 +5,7 @@ package kotlinx.rpc.protobuf.test import kotlinx.io.Buffer +import kotlinx.rpc.protobuf.input.stream.asInputStream import kotlinx.rpc.protobuf.internal.ProtobufDecodingException import kotlinx.rpc.protobuf.internal.WireDecoder import kotlinx.rpc.protobuf.internal.WireEncoder @@ -20,12 +21,16 @@ import kotlinx.rpc.protobuf.internal.packedUInt32 import kotlinx.rpc.protobuf.internal.packedUInt64 import kotlin.test.* +@Suppress("unused") enum class TestPlatform { Jvm, Native, Js, WasmJs, Wasi; } expect val testPlatform: TestPlatform +@Suppress("TestFunctionName") +private fun WireDecoder(buffer: Buffer) = WireDecoder(buffer.asInputStream()) + class WireCodecTest { @Test diff --git a/protobuf/protobuf-core/src/commonTest/proto/all_primitives.proto b/protobuf/protobuf-core/src/commonTest/proto/all_primitives.proto index 99b12cd57..e9afd1266 100644 --- a/protobuf/protobuf-core/src/commonTest/proto/all_primitives.proto +++ b/protobuf/protobuf-core/src/commonTest/proto/all_primitives.proto @@ -1,6 +1,6 @@ syntax = "proto3"; -package kotlinx.rpc.grpc.test.common; +package kotlinx.rpc.protobuf.test; message AllPrimitives { double double = 1; @@ -18,4 +18,4 @@ message AllPrimitives { optional bool bool = 13; optional string string = 14; optional bytes bytes = 15; -} \ No newline at end of file +} diff --git a/protobuf/protobuf-core/src/commonTest/proto/enum.proto b/protobuf/protobuf-core/src/commonTest/proto/enum.proto index 2a3a8e716..0cc090e3b 100644 --- a/protobuf/protobuf-core/src/commonTest/proto/enum.proto +++ b/protobuf/protobuf-core/src/commonTest/proto/enum.proto @@ -1,6 +1,6 @@ syntax = "proto3"; -package kotlinx.rpc.grpc.test; +package kotlinx.rpc.protobuf.test; enum MyEnum { option allow_alias = true; diff --git a/protobuf/protobuf-core/src/commonTest/proto/oneof.proto b/protobuf/protobuf-core/src/commonTest/proto/oneof.proto index b55ddae16..d0fbdc8fd 100644 --- a/protobuf/protobuf-core/src/commonTest/proto/oneof.proto +++ b/protobuf/protobuf-core/src/commonTest/proto/oneof.proto @@ -7,13 +7,13 @@ message OneOfMsg { int32 sint = 2; fixed64 fixed = 3; test.submsg.Other other = 4; - kotlinx.rpc.grpc.test.MyEnum enum = 5; + kotlinx.rpc.protobuf.test.MyEnum enum = 5; } } message OneOfWithRequired { oneof field { int32 sint = 1; - kotlinx.rpc.grpc.test.common.PresenceCheck msg = 2; + kotlinx.rpc.protobuf.test.PresenceCheck msg = 2; } -} \ No newline at end of file +} diff --git a/protobuf/protobuf-core/src/commonTest/proto/presence_check.proto b/protobuf/protobuf-core/src/commonTest/proto/presence_check.proto index f428ce2c9..39a91f4c3 100644 --- a/protobuf/protobuf-core/src/commonTest/proto/presence_check.proto +++ b/protobuf/protobuf-core/src/commonTest/proto/presence_check.proto @@ -1,6 +1,6 @@ syntax = "proto2"; -package kotlinx.rpc.grpc.test.common; +package kotlinx.rpc.protobuf.test; message PresenceCheck { required int32 RequiredPresence = 1; diff --git a/protobuf/protobuf-core/src/commonTest/proto/repeated.proto b/protobuf/protobuf-core/src/commonTest/proto/repeated.proto index 7451b33ac..e84c61dc0 100644 --- a/protobuf/protobuf-core/src/commonTest/proto/repeated.proto +++ b/protobuf/protobuf-core/src/commonTest/proto/repeated.proto @@ -2,7 +2,7 @@ syntax = "proto3"; import "presence_check.proto"; -package kotlinx.rpc.grpc.test.common; +package kotlinx.rpc.protobuf.test; message Repeated { repeated fixed32 listFixed32 = 1 [packed = false]; @@ -19,4 +19,4 @@ message Repeated { message RepeatedWithRequired { repeated PresenceCheck msgList = 1; -} \ No newline at end of file +} diff --git a/protobuf/protobuf-core/src/commonTest/proto/test_map.proto b/protobuf/protobuf-core/src/commonTest/proto/test_map.proto index 816c292e8..f012b5212 100644 --- a/protobuf/protobuf-core/src/commonTest/proto/test_map.proto +++ b/protobuf/protobuf-core/src/commonTest/proto/test_map.proto @@ -1,10 +1,10 @@ syntax = "proto3"; -package kotlinx.rpc.grpc.test; +package kotlinx.rpc.protobuf.test; import "presence_check.proto"; message TestMap { map primitives = 1; - map messages = 2; -} \ No newline at end of file + map messages = 2; +} diff --git a/protobuf/protobuf-core/src/jvmMain/kotlin/kotlinx/rpc/protobuf/internal/WireDecoder.jvm.kt b/protobuf/protobuf-core/src/jvmMain/kotlin/kotlinx/rpc/protobuf/internal/WireDecoder.jvm.kt index a899713ab..b452c5c58 100644 --- a/protobuf/protobuf-core/src/jvmMain/kotlin/kotlinx/rpc/protobuf/internal/WireDecoder.jvm.kt +++ b/protobuf/protobuf-core/src/jvmMain/kotlin/kotlinx/rpc/protobuf/internal/WireDecoder.jvm.kt @@ -6,12 +6,11 @@ package kotlinx.rpc.protobuf.internal import com.google.protobuf.CodedInputStream import com.google.protobuf.InvalidProtocolBufferException -import kotlinx.io.Buffer -import kotlinx.io.asInputStream +import java.io.InputStream -internal class WireDecoderJvm(source: Buffer) : WireDecoder { +internal class WireDecoderJvm(source: InputStream) : WireDecoder { // there is no way to omit coping here - internal val codedInputStream: CodedInputStream = CodedInputStream.newInstance(source.asInputStream()) + internal val codedInputStream: CodedInputStream = CodedInputStream.newInstance(source) override fun readTag(): KTag? { val tag = codedInputStream.readTag().toUInt() @@ -121,6 +120,6 @@ public actual inline fun checkForPlatformDecodeException(block: () -> Unit) { } } -public actual fun WireDecoder(source: Buffer): WireDecoder { +public actual fun WireDecoder(source: InputStream): WireDecoder { return WireDecoderJvm(source) } diff --git a/protobuf/protobuf-core/src/nativeMain/kotlin/kotlinx/rpc/protobuf/internal/WireDecoder.native.kt b/protobuf/protobuf-core/src/nativeMain/kotlin/kotlinx/rpc/protobuf/internal/WireDecoder.native.kt index 55d161dc6..c3fd1cfbb 100644 --- a/protobuf/protobuf-core/src/nativeMain/kotlin/kotlinx/rpc/protobuf/internal/WireDecoder.native.kt +++ b/protobuf/protobuf-core/src/nativeMain/kotlin/kotlinx/rpc/protobuf/internal/WireDecoder.native.kt @@ -7,6 +7,7 @@ package kotlinx.rpc.protobuf.internal import kotlinx.cinterop.* import kotlinx.collections.immutable.persistentListOf import kotlinx.io.Buffer +import kotlinx.rpc.protobuf.input.stream.InputStream import libprotowire.* import kotlin.experimental.ExperimentalNativeApi import kotlin.math.min @@ -298,7 +299,7 @@ internal class WireDecoderNative(private val source: Buffer) : WireDecoder { } } -public actual fun WireDecoder(source: Buffer): WireDecoder = WireDecoderNative(source) +public actual fun WireDecoder(source: InputStream): WireDecoder = WireDecoderNative(source.buffer) public actual inline fun checkForPlatformDecodeException(block: () -> Unit) { block() diff --git a/protobuf/protobuf-input-stream/api/protobuf-input-stream.api b/protobuf/protobuf-input-stream/api/protobuf-input-stream.api new file mode 100644 index 000000000..bf019ccd7 --- /dev/null +++ b/protobuf/protobuf-input-stream/api/protobuf-input-stream.api @@ -0,0 +1,5 @@ +public final class kotlinx/rpc/protobuf/input/stream/InputStream_jvmKt { + public static final fun asInputStream (Lkotlinx/io/Source;)Ljava/io/InputStream; + public static final fun asSource (Ljava/io/InputStream;)Lkotlinx/io/Source; +} + diff --git a/protobuf/protobuf-input-stream/api/protobuf-input-stream.klib.api b/protobuf/protobuf-input-stream/api/protobuf-input-stream.klib.api new file mode 100644 index 000000000..9473a2224 --- /dev/null +++ b/protobuf/protobuf-input-stream/api/protobuf-input-stream.klib.api @@ -0,0 +1,25 @@ +// 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 +// - Show declarations: true + +// Library unique name: +// Targets: [native] +final fun (kotlinx.io/Source).kotlinx.rpc.protobuf.input.stream/asInputStream(): kotlinx.rpc.protobuf.input.stream/BufferInputStream // kotlinx.rpc.protobuf.input.stream/asInputStream|asInputStream@kotlinx.io.Source(){}[0] + +// Targets: [native] +final fun (kotlinx.rpc.protobuf.input.stream/BufferInputStream).kotlinx.rpc.protobuf.input.stream/asSource(): kotlinx.io/Source // kotlinx.rpc.protobuf.input.stream/asSource|asSource@kotlinx.rpc.protobuf.input.stream.BufferInputStream(){}[0] + +// Targets: [js, wasmJs, wasmWasi] +abstract class kotlinx.rpc.protobuf.input.stream/InputStream { // kotlinx.rpc.protobuf.input.stream/InputStream|null[0] + constructor () // kotlinx.rpc.protobuf.input.stream/InputStream.|(){}[0] +} + +// Targets: [js, wasmJs, wasmWasi] +final fun (kotlinx.io/Source).kotlinx.rpc.protobuf.input.stream/asInputStream(): kotlinx.rpc.protobuf.input.stream/InputStream // kotlinx.rpc.protobuf.input.stream/asInputStream|asInputStream@kotlinx.io.Source(){}[0] + +// Targets: [js, wasmJs, wasmWasi] +final fun (kotlinx.rpc.protobuf.input.stream/InputStream).kotlinx.rpc.protobuf.input.stream/asSource(): kotlinx.io/Source // kotlinx.rpc.protobuf.input.stream/asSource|asSource@kotlinx.rpc.protobuf.input.stream.InputStream(){}[0] diff --git a/protobuf/protobuf-input-stream/build.gradle.kts b/protobuf/protobuf-input-stream/build.gradle.kts new file mode 100644 index 000000000..ffd9b3790 --- /dev/null +++ b/protobuf/protobuf-input-stream/build.gradle.kts @@ -0,0 +1,23 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +plugins { + alias(libs.plugins.conventions.kmp) + alias(libs.plugins.kotlinx.rpc) +} + +kotlin { + compilerOptions { + freeCompilerArgs.add("-Xexpect-actual-classes") + } + + sourceSets { + commonMain { + dependencies { + api(projects.utils) + api(libs.kotlinx.io.core) + } + } + } +} diff --git a/protobuf/protobuf-input-stream/src/commonMain/kotlin/kotlinx/rpc/protobuf/input/stream/InputStream.kt b/protobuf/protobuf-input-stream/src/commonMain/kotlin/kotlinx/rpc/protobuf/input/stream/InputStream.kt new file mode 100644 index 000000000..bb75eab9b --- /dev/null +++ b/protobuf/protobuf-input-stream/src/commonMain/kotlin/kotlinx/rpc/protobuf/input/stream/InputStream.kt @@ -0,0 +1,17 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.protobuf.input.stream + +import kotlinx.io.Source +import kotlinx.rpc.internal.utils.ExperimentalRpcApi + +@ExperimentalRpcApi +public expect abstract class InputStream + +@ExperimentalRpcApi +public expect fun Source.asInputStream(): InputStream + +@ExperimentalRpcApi +public expect fun InputStream.asSource(): Source diff --git a/protobuf/protobuf-input-stream/src/jsMain/kotlin/kotlinx/rpc/protobuf/input/stream/InputStream.js.kt b/protobuf/protobuf-input-stream/src/jsMain/kotlin/kotlinx/rpc/protobuf/input/stream/InputStream.js.kt new file mode 100644 index 000000000..10d80739d --- /dev/null +++ b/protobuf/protobuf-input-stream/src/jsMain/kotlin/kotlinx/rpc/protobuf/input/stream/InputStream.js.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.protobuf.input.stream + +import kotlinx.io.Source +import kotlinx.rpc.internal.utils.ExperimentalRpcApi + +@ExperimentalRpcApi +public actual abstract class InputStream + +@ExperimentalRpcApi +public actual fun Source.asInputStream(): InputStream { + TODO("Not yet implemented") +} + +@ExperimentalRpcApi +public actual fun InputStream.asSource(): Source { + TODO("Not yet implemented") +} diff --git a/protobuf/protobuf-input-stream/src/jvmMain/kotlin/kotlinx/rpc/protobuf/input/stream/InputStream.jvm.kt b/protobuf/protobuf-input-stream/src/jvmMain/kotlin/kotlinx/rpc/protobuf/input/stream/InputStream.jvm.kt new file mode 100644 index 000000000..3187e9dac --- /dev/null +++ b/protobuf/protobuf-input-stream/src/jvmMain/kotlin/kotlinx/rpc/protobuf/input/stream/InputStream.jvm.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.protobuf.input.stream + +import kotlinx.io.Source +import kotlinx.io.asInputStream +import kotlinx.io.asSource +import kotlinx.io.buffered +import kotlinx.rpc.internal.utils.ExperimentalRpcApi + +@ExperimentalRpcApi +public actual typealias InputStream = java.io.InputStream + +@ExperimentalRpcApi +@Suppress("NOTHING_TO_INLINE") +public actual inline fun Source.asInputStream(): InputStream = asInputStream() + +@ExperimentalRpcApi +@Suppress("NOTHING_TO_INLINE") +public actual inline fun InputStream.asSource(): Source { + return asSource().buffered() +} diff --git a/protobuf/protobuf-input-stream/src/nativeMain/kotlin/kotlinx/rpc/protobuf/input/stream/InputStream.native.kt b/protobuf/protobuf-input-stream/src/nativeMain/kotlin/kotlinx/rpc/protobuf/input/stream/InputStream.native.kt new file mode 100644 index 000000000..2e5a9046a --- /dev/null +++ b/protobuf/protobuf-input-stream/src/nativeMain/kotlin/kotlinx/rpc/protobuf/input/stream/InputStream.native.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.protobuf.input.stream + +import kotlinx.io.Buffer +import kotlinx.io.Source +import kotlinx.rpc.internal.utils.ExperimentalRpcApi +import kotlinx.rpc.internal.utils.InternalRpcApi + +@InternalRpcApi +public abstract class BufferInputStream(public val buffer: Buffer) + +@InternalRpcApi +public fun bufferInputStream(buffer: Buffer): BufferInputStream = object : BufferInputStream(buffer) {} + +@ExperimentalRpcApi +public actual typealias InputStream = BufferInputStream + +@ExperimentalRpcApi +public actual fun Source.asInputStream(): InputStream { + return bufferInputStream(this as Buffer) +} + +@ExperimentalRpcApi +public actual fun InputStream.asSource(): Source { + return buffer +} diff --git a/protobuf/protobuf-input-stream/src/wasmJsMain/kotlin/kotlinx/rpc/protobuf/input/stream/InputStream.wasmJs.kt b/protobuf/protobuf-input-stream/src/wasmJsMain/kotlin/kotlinx/rpc/protobuf/input/stream/InputStream.wasmJs.kt new file mode 100644 index 000000000..10d80739d --- /dev/null +++ b/protobuf/protobuf-input-stream/src/wasmJsMain/kotlin/kotlinx/rpc/protobuf/input/stream/InputStream.wasmJs.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.protobuf.input.stream + +import kotlinx.io.Source +import kotlinx.rpc.internal.utils.ExperimentalRpcApi + +@ExperimentalRpcApi +public actual abstract class InputStream + +@ExperimentalRpcApi +public actual fun Source.asInputStream(): InputStream { + TODO("Not yet implemented") +} + +@ExperimentalRpcApi +public actual fun InputStream.asSource(): Source { + TODO("Not yet implemented") +} diff --git a/protobuf/protobuf-input-stream/src/wasmWasiMain/kotlin/kotlinx/rpc/protobuf/input/stream/InputStream.wasmWasi.kt b/protobuf/protobuf-input-stream/src/wasmWasiMain/kotlin/kotlinx/rpc/protobuf/input/stream/InputStream.wasmWasi.kt new file mode 100644 index 000000000..10d80739d --- /dev/null +++ b/protobuf/protobuf-input-stream/src/wasmWasiMain/kotlin/kotlinx/rpc/protobuf/input/stream/InputStream.wasmWasi.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.protobuf.input.stream + +import kotlinx.io.Source +import kotlinx.rpc.internal.utils.ExperimentalRpcApi + +@ExperimentalRpcApi +public actual abstract class InputStream + +@ExperimentalRpcApi +public actual fun Source.asInputStream(): InputStream { + TODO("Not yet implemented") +} + +@ExperimentalRpcApi +public actual fun InputStream.asSource(): Source { + TODO("Not yet implemented") +} diff --git a/protoc-gen/common/src/main/kotlin/kotlinx/rpc/protoc/gen/core/AModelToKotlinCommonGenerator.kt b/protoc-gen/common/src/main/kotlin/kotlinx/rpc/protoc/gen/core/AModelToKotlinCommonGenerator.kt index 47d63bcd7..c1f7df818 100644 --- a/protoc-gen/common/src/main/kotlin/kotlinx/rpc/protoc/gen/core/AModelToKotlinCommonGenerator.kt +++ b/protoc-gen/common/src/main/kotlin/kotlinx/rpc/protoc/gen/core/AModelToKotlinCommonGenerator.kt @@ -26,8 +26,8 @@ abstract class AModelToKotlinCommonGenerator( protected abstract fun CodeGenerator.generatePublicDeclaredEntities(fileDeclaration: FileDeclaration) protected abstract fun CodeGenerator.generateInternalDeclaredEntities(fileDeclaration: FileDeclaration) - protected abstract val hasPublicGeneratedFiles: Boolean - protected abstract val hasInternalGeneratedFiles: Boolean + protected abstract val FileDeclaration.hasPublicGeneratedContent: Boolean + protected abstract val FileDeclaration.hasInternalGeneratedContent: Boolean protected var currentPackage: FqName = FqName.Package.Root protected val additionalPublicImports = mutableSetOf() @@ -42,8 +42,8 @@ abstract class AModelToKotlinCommonGenerator( additionalInternalImports.clear() return listOfNotNull( - if (hasPublicGeneratedFiles) generatePublicKotlinFile() else null, - if (hasInternalGeneratedFiles) generateInternalKotlinFile() else null, + if (hasPublicGeneratedContent) generatePublicKotlinFile() else null, + if (hasInternalGeneratedContent) generateInternalKotlinFile() else null, ) } diff --git a/protoc-gen/grpc/src/main/kotlin/kotlinx/rpc/protoc/gen/grpc/ModelToGrpcKotlinCommonGenerator.kt b/protoc-gen/grpc/src/main/kotlin/kotlinx/rpc/protoc/gen/grpc/ModelToGrpcKotlinCommonGenerator.kt index e8d966404..4d50cd3c9 100644 --- a/protoc-gen/grpc/src/main/kotlin/kotlinx/rpc/protoc/gen/grpc/ModelToGrpcKotlinCommonGenerator.kt +++ b/protoc-gen/grpc/src/main/kotlin/kotlinx/rpc/protoc/gen/grpc/ModelToGrpcKotlinCommonGenerator.kt @@ -15,8 +15,8 @@ class ModelToGrpcKotlinCommonGenerator( model: Model, logger: Logger, ) : AModelToKotlinCommonGenerator(model, logger) { - override val hasPublicGeneratedFiles: Boolean = model.files.any { it.serviceDeclarations.isNotEmpty() } - override val hasInternalGeneratedFiles: Boolean = false + override val FileDeclaration.hasPublicGeneratedContent: Boolean get() = serviceDeclarations.isNotEmpty() + override val FileDeclaration.hasInternalGeneratedContent: Boolean get() = false override fun CodeGenerator.generatePublicDeclaredEntities(fileDeclaration: FileDeclaration) { fileDeclaration.serviceDeclarations.forEach { generatePublicService(it) } diff --git a/protoc-gen/protobuf/src/main/kotlin/kotlinx/rpc/protoc/gen/ModelToProtobufKotlinCommonGenerator.kt b/protoc-gen/protobuf/src/main/kotlin/kotlinx/rpc/protoc/gen/ModelToProtobufKotlinCommonGenerator.kt index e48b73d86..e8343cf0b 100644 --- a/protoc-gen/protobuf/src/main/kotlin/kotlinx/rpc/protoc/gen/ModelToProtobufKotlinCommonGenerator.kt +++ b/protoc-gen/protobuf/src/main/kotlin/kotlinx/rpc/protoc/gen/ModelToProtobufKotlinCommonGenerator.kt @@ -25,11 +25,11 @@ class ModelToProtobufKotlinCommonGenerator( model: Model, logger: Logger, ) : AModelToKotlinCommonGenerator(model, logger) { - override val hasPublicGeneratedFiles: Boolean = model.files.any { - it.enumDeclarations.isNotEmpty() || it.messageDeclarations.isNotEmpty() - } + override val FileDeclaration.hasPublicGeneratedContent: Boolean + get() = enumDeclarations.isNotEmpty() || messageDeclarations.isNotEmpty() - override val hasInternalGeneratedFiles: Boolean = hasPublicGeneratedFiles + override val FileDeclaration.hasInternalGeneratedContent: Boolean + get() = hasPublicGeneratedContent override fun CodeGenerator.generatePublicDeclaredEntities(fileDeclaration: FileDeclaration) { fileDeclaration.messageDeclarations.forEach { generatePublicMessage(it) } @@ -176,21 +176,21 @@ class ModelToProtobufKotlinCommonGenerator( if (!declaration.isUserFacing) return val msgFqName = declaration.name.safeFullName() - val sourceFqName = "kotlinx.io.Source" + val inputStreamFqName = "kotlinx.rpc.protobuf.input.stream.InputStream" val bufferFqName = "kotlinx.io.Buffer" scope("object CODEC : kotlinx.rpc.grpc.codec.MessageCodec<$msgFqName>") { - function("encode", modifiers = "override", args = "value: $msgFqName", returnType = sourceFqName) { + function("encode", modifiers = "override", args = "value: $msgFqName", returnType = inputStreamFqName) { code("val buffer = $bufferFqName()") code("val encoder = $PB_PKG.WireEncoder(buffer)") scope("${PB_PKG}.checkForPlatformEncodeException", nlAfterClosed = false) { code("value.asInternal().encodeWith(encoder)") } code("encoder.flush()") - code("return buffer") + code("return buffer.asInputStream()") } - function("decode", modifiers = "override", args = "stream: $sourceFqName", returnType = msgFqName) { - scope("$PB_PKG.WireDecoder(stream as $bufferFqName).use") { + function("decode", modifiers = "override", args = "stream: $inputStreamFqName", returnType = msgFqName) { + scope("$PB_PKG.WireDecoder(stream).use") { code("val msg = ${declaration.internalClassFullName()}()") scope("${PB_PKG}.checkForPlatformDecodeException", nlAfterClosed = false) { code("${declaration.internalClassFullName()}.decodeWith(msg, it)") @@ -200,6 +200,8 @@ class ModelToProtobufKotlinCommonGenerator( } } } + + additionalInternalImports.add("kotlinx.rpc.protobuf.input.stream.asInputStream") } private fun CodeGenerator.generateMessageConstructor(declaration: MessageDeclaration) { diff --git a/settings.gradle.kts b/settings.gradle.kts index 7b86eba05..be56183a8 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -30,6 +30,7 @@ dependencyResolutionManagement { include(":protobuf") includePublic(":protobuf:protobuf-core") +includePublic(":protobuf:protobuf-input-stream") include(":grpc") includePublic(":grpc:grpc-core") diff --git a/tests/compiler-plugin-tests/src/main/kotlin/kotlinx/rpc/codegen/test/Grpc.kt b/tests/compiler-plugin-tests/src/main/kotlin/kotlinx/rpc/codegen/test/Grpc.kt index 7d1adbf27..80f1079b7 100644 --- a/tests/compiler-plugin-tests/src/main/kotlin/kotlinx/rpc/codegen/test/Grpc.kt +++ b/tests/compiler-plugin-tests/src/main/kotlin/kotlinx/rpc/codegen/test/Grpc.kt @@ -5,13 +5,13 @@ package kotlinx.rpc.codegen.test import io.grpc.MethodDescriptor -import kotlinx.io.Source import kotlinx.rpc.descriptor.serviceDescriptorOf import kotlinx.rpc.grpc.annotations.Grpc import kotlinx.rpc.grpc.codec.MessageCodec import kotlinx.rpc.grpc.codec.MessageCodecResolver import kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate import kotlinx.rpc.grpc.descriptor.GrpcServiceDescriptor +import kotlinx.rpc.protobuf.input.stream.InputStream import kotlin.reflect.KType /** @@ -72,21 +72,21 @@ object SimpleResolver : MessageCodecResolver { } object StringCodec : MessageCodec { - override fun encode(value: String): Source { + override fun encode(value: String): InputStream { TODO("Not yet implemented") } - override fun decode(stream: Source): String { + override fun decode(stream: InputStream): String { TODO("Not yet implemented") } } object UnitCodec : MessageCodec { - override fun encode(value: String): Source { + override fun encode(value: String): InputStream { TODO("Not yet implemented") } - override fun decode(stream: Source): String { + override fun decode(stream: InputStream): String { TODO("Not yet implemented") } } @@ -95,11 +95,11 @@ object UnitCodec : MessageCodec { class Message(val a: Int, val b: String) object MessageClassCodec : MessageCodec { - override fun encode(value: Message): Source { + override fun encode(value: Message): InputStream { TODO("Not yet implemented") } - override fun decode(stream: Source): Message { + override fun decode(stream: InputStream): Message { TODO("Not yet implemented") } } diff --git a/tests/compiler-plugin-tests/src/testData/box/grpc.fir.ir.txt b/tests/compiler-plugin-tests/src/testData/box/grpc.fir.ir.txt index 3054ad8c1..9c9f8c13e 100644 --- a/tests/compiler-plugin-tests/src/testData/box/grpc.fir.ir.txt +++ b/tests/compiler-plugin-tests/src/testData/box/grpc.fir.ir.txt @@ -37,17 +37,17 @@ FILE fqName: fileName:/grpc.kt public open fun toString (): kotlin.String declared in kotlinx.rpc.grpc.codec.MessageCodec FUN name:decode visibility:public modality:OPEN returnType:.Custom VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.Custom.Companion - VALUE_PARAMETER kind:Regular name:stream index:1 type:kotlinx.io.Source + VALUE_PARAMETER kind:Regular name:stream index:1 type:java.io.InputStream overridden: - public abstract fun decode (stream: kotlinx.io.Source): T of kotlinx.rpc.grpc.codec.MessageCodec declared in kotlinx.rpc.grpc.codec.MessageCodec + public abstract fun decode (stream: java.io.InputStream): T of kotlinx.rpc.grpc.codec.MessageCodec declared in kotlinx.rpc.grpc.codec.MessageCodec BLOCK_BODY CALL 'public final fun TODO (reason: kotlin.String): kotlin.Nothing declared in kotlin' type=kotlin.Nothing origin=null ARG reason: CONST String type=kotlin.String value="Not yet implemented" - FUN name:encode visibility:public modality:OPEN returnType:kotlinx.io.Source + FUN name:encode visibility:public modality:OPEN returnType:java.io.InputStream VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.Custom.Companion VALUE_PARAMETER kind:Regular name:value index:1 type:.Custom overridden: - public abstract fun encode (value: T of kotlinx.rpc.grpc.codec.MessageCodec): kotlinx.io.Source declared in kotlinx.rpc.grpc.codec.MessageCodec + public abstract fun encode (value: T of kotlinx.rpc.grpc.codec.MessageCodec): java.io.InputStream declared in kotlinx.rpc.grpc.codec.MessageCodec BLOCK_BODY CALL 'public final fun TODO (reason: kotlin.String): kotlin.Nothing declared in kotlin' type=kotlin.Nothing origin=null ARG reason: CONST String type=kotlin.String value="Not yet implemented" diff --git a/tests/compiler-plugin-tests/src/testData/box/grpc.fir.txt b/tests/compiler-plugin-tests/src/testData/box/grpc.fir.txt index 36a642e84..e60f78ea9 100644 --- a/tests/compiler-plugin-tests/src/testData/box/grpc.fir.txt +++ b/tests/compiler-plugin-tests/src/testData/box/grpc.fir.txt @@ -13,11 +13,11 @@ FILE: grpc.kt super() } - public open override fun encode(value: R|Custom|): R|kotlinx/io/Source| { + public open override fun encode(value: R|Custom|): R|{kotlinx/rpc/protobuf/input/stream/InputStream=} java/io/InputStream| { R|kotlin/TODO|(String(Not yet implemented)) } - public open override fun decode(stream: R|kotlinx/io/Source|): R|Custom| { + public open override fun decode(stream: R|{kotlinx/rpc/protobuf/input/stream/InputStream=} java/io/InputStream|): R|Custom| { R|kotlin/TODO|(String(Not yet implemented)) } diff --git a/tests/compiler-plugin-tests/src/testData/box/grpc.kt b/tests/compiler-plugin-tests/src/testData/box/grpc.kt index 7ce58d401..605ec7de2 100644 --- a/tests/compiler-plugin-tests/src/testData/box/grpc.kt +++ b/tests/compiler-plugin-tests/src/testData/box/grpc.kt @@ -7,7 +7,6 @@ @file:OptIn(kotlinx.rpc.internal.utils.ExperimentalRpcApi::class, kotlinx.rpc.internal.utils.InternalRpcApi::class) import io.grpc.MethodDescriptor -import kotlinx.io.Source import kotlinx.coroutines.flow.Flow import kotlinx.rpc.codegen.test.grpcDelegate import kotlinx.rpc.codegen.test.checkMethod @@ -15,15 +14,16 @@ import kotlinx.rpc.codegen.test.Message import kotlinx.rpc.grpc.annotations.Grpc import kotlinx.rpc.grpc.codec.WithCodec import kotlinx.rpc.grpc.codec.MessageCodec +import kotlinx.rpc.protobuf.input.stream.InputStream @WithCodec(Custom.Companion::class) class Custom(val content: String) { companion object : MessageCodec { - override fun encode(value: Custom): Source { + override fun encode(value: Custom): InputStream { TODO("Not yet implemented") } - override fun decode(stream: Source): Custom { + override fun decode(stream: InputStream): Custom { TODO("Not yet implemented") } } diff --git a/tests/compiler-plugin-tests/src/testData/diagnostics/withCodec.fir.txt b/tests/compiler-plugin-tests/src/testData/diagnostics/withCodec.fir.txt index be8efe558..9a7e8a4d7 100644 --- a/tests/compiler-plugin-tests/src/testData/diagnostics/withCodec.fir.txt +++ b/tests/compiler-plugin-tests/src/testData/diagnostics/withCodec.fir.txt @@ -23,11 +23,11 @@ FILE: module_main_withCodec.kt super() } - public open override fun encode(value: R|Test|): R|kotlinx/io/Source| { + public open override fun encode(value: R|Test|): R|{kotlinx/rpc/protobuf/input/stream/InputStream=} java/io/InputStream| { R|kotlin/error|(String(Not implemented)) } - public open override fun decode(stream: R|kotlinx/io/Source|): R|Test| { + public open override fun decode(stream: R|{kotlinx/rpc/protobuf/input/stream/InputStream=} java/io/InputStream|): R|Test| { R|kotlin/error|(String(Not implemented)) } @@ -43,11 +43,11 @@ FILE: module_main_withCodec.kt super() } - public open override fun encode(value: R|Test3|): R|kotlinx/io/Source| { + public open override fun encode(value: R|Test3|): R|{kotlinx/rpc/protobuf/input/stream/InputStream=} java/io/InputStream| { R|kotlin/error|(String(Not implemented)) } - public open override fun decode(stream: R|kotlinx/io/Source|): R|Test3| { + public open override fun decode(stream: R|{kotlinx/rpc/protobuf/input/stream/InputStream=} java/io/InputStream|): R|Test3| { R|kotlin/error|(String(Not implemented)) } @@ -71,11 +71,11 @@ FILE: module_main_withCodec.kt super() } - public open override fun encode(value: R|Test4|): R|kotlinx/io/Source| { + public open override fun encode(value: R|Test4|): R|{kotlinx/rpc/protobuf/input/stream/InputStream=} java/io/InputStream| { R|kotlin/error|(String(Not implemented)) } - public open override fun decode(stream: R|kotlinx/io/Source|): R|Test4| { + public open override fun decode(stream: R|{kotlinx/rpc/protobuf/input/stream/InputStream=} java/io/InputStream|): R|Test4| { R|kotlin/error|(String(Not implemented)) } @@ -86,3 +86,77 @@ FILE: module_main_withCodec.kt } } + @R|kotlinx/rpc/grpc/codec/WithCodec|(codec = (Q|TestCodec6|)) public final class Test6 : R|kotlin/Any| { + public constructor(): R|Test6| { + super() + } + + } + public final object TestCodec6 : R|kotlinx/rpc/grpc/codec/SourcedMessageCodec| { + private constructor(): R|TestCodec6| { + super() + } + + public open override fun encodeToSource(value: R|Test6|): R|kotlinx/io/Source| { + R|kotlin/error|(String(Not implemented)) + } + + public open override fun decodeFromSource(stream: R|kotlinx/io/Source|): R|Test6| { + R|kotlin/error|(String(Not implemented)) + } + + } + @R|kotlinx/rpc/grpc/codec/WithCodec|(codec = (Q|TestCodec6|)) public final class Test7 : R|kotlin/Any| { + public constructor(): R|Test7| { + super() + } + + } + public abstract interface CustomCodec1 : R|kotlinx/rpc/grpc/codec/MessageCodec| { + } + public abstract interface CustomCodec2 : R|kotlinx/rpc/grpc/codec/MessageCodec| { + } + public abstract interface CustomCodec3 : R|CustomCodec2| { + } + public abstract interface CustomCodec4 : R|CustomCodec3|, R|CustomCodec1| { + } + @R|kotlinx/rpc/grpc/codec/WithCodec|(codec = (Q|TestCodec8|)) public final class Test8 : R|kotlin/Any| { + public constructor(): R|Test8| { + super() + } + + } + public final object TestCodec8 : R|CustomCodec4| { + private constructor(): R|TestCodec8| { + super() + } + + public open override fun encode(value: R|Test8|): R|{kotlinx/rpc/protobuf/input/stream/InputStream=} java/io/InputStream| { + R|kotlin/error|(String(Not implemented)) + } + + public open override fun decode(stream: R|{kotlinx/rpc/protobuf/input/stream/InputStream=} java/io/InputStream|): R|Test8| { + R|kotlin/error|(String(Not implemented)) + } + + } + @R|kotlinx/rpc/grpc/codec/WithCodec|(codec = (Q|TestCodec9|)) public final class Test9 : R|kotlin/Any| { + public constructor(): R|Test9| { + super() + } + + } + public final object TestCodec9 : R|CustomCodec4| { + private constructor(): R|TestCodec9| { + super() + } + + public open override fun encode(value: R|Test8|): R|{kotlinx/rpc/protobuf/input/stream/InputStream=} java/io/InputStream| { + R|kotlin/error|(String(Not implemented)) + } + + public open override fun decode(stream: R|{kotlinx/rpc/protobuf/input/stream/InputStream=} java/io/InputStream|): R|Test8| { + R|kotlin/error|(String(Not implemented)) + } + + } diff --git a/tests/compiler-plugin-tests/src/testData/diagnostics/withCodec.kt b/tests/compiler-plugin-tests/src/testData/diagnostics/withCodec.kt index 2307e49f7..189e8b23a 100644 --- a/tests/compiler-plugin-tests/src/testData/diagnostics/withCodec.kt +++ b/tests/compiler-plugin-tests/src/testData/diagnostics/withCodec.kt @@ -8,8 +8,10 @@ @file:OptIn(kotlinx.rpc.internal.utils.ExperimentalRpcApi::class) +import kotlinx.rpc.protobuf.input.stream.InputStream import kotlinx.rpc.grpc.codec.WithCodec import kotlinx.rpc.grpc.codec.MessageCodec +import kotlinx.rpc.grpc.codec.SourcedMessageCodec import kotlinx.io.Source @WithCodec(TestCodec::class) @@ -22,11 +24,11 @@ class Test1 class Test2 : Test() object TestCodec : MessageCodec { - override fun encode(value: Test): Source { + override fun encode(value: Test): InputStream { error("Not implemented") } - override fun decode(stream: Source): Test { + override fun decode(stream: InputStream): Test { error("Not implemented") } } @@ -35,11 +37,11 @@ object TestCodec : MessageCodec { class Test3 class TestCodec3 : MessageCodec { - override fun encode(value: Test3): Source { + override fun encode(value: Test3): InputStream { error("Not implemented") } - override fun decode(stream: Source): Test3 { + override fun decode(stream: InputStream): Test3 { error("Not implemented") } } @@ -52,14 +54,61 @@ object TestCodec4 : ATestCodec4(), Whatever interface Whatever abstract class ATestCodec4 : MessageCodec { - override fun encode(value: Test4): Source { + override fun encode(value: Test4): InputStream { error("Not implemented") } - override fun decode(stream: Source): Test4 { + override fun decode(stream: InputStream): Test4 { error("Not implemented") } } @WithCodec(TestCodec4::class) class Test5 + +@WithCodec(TestCodec6::class) +class Test6 + +object TestCodec6 : SourcedMessageCodec { + override fun encodeToSource(value: Test6): Source { + error("Not implemented") + } + + override fun decodeFromSource(stream: Source): Test6 { + error("Not implemented") + } +} + +@WithCodec(TestCodec6::class) +class Test7 + +interface CustomCodec1 : MessageCodec +interface CustomCodec2 : MessageCodec +interface CustomCodec3 : CustomCodec2 +interface CustomCodec4 : CustomCodec3, CustomCodec1 + +@WithCodec(TestCodec8::class) +class Test8 + +object TestCodec8 : CustomCodec4 { + override fun encode(value: Test8): InputStream { + error("Not implemented") + } + + override fun decode(stream: InputStream): Test8 { + error("Not implemented") + } +} + +@WithCodec(TestCodec9::class) +class Test9 + +object TestCodec9 : CustomCodec4 { + override fun encode(value: Test8): InputStream { + error("Not implemented") + } + + override fun decode(stream: InputStream): Test8 { + error("Not implemented") + } +} diff --git a/utils/src/commonMain/kotlin/kotlinx/rpc/internal/utils/ExperimentalRpcApi.kt b/utils/src/commonMain/kotlin/kotlinx/rpc/internal/utils/ExperimentalRpcApi.kt index 86c7419e9..02df42204 100644 --- a/utils/src/commonMain/kotlin/kotlinx/rpc/internal/utils/ExperimentalRpcApi.kt +++ b/utils/src/commonMain/kotlin/kotlinx/rpc/internal/utils/ExperimentalRpcApi.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ package kotlinx.rpc.internal.utils @@ -8,4 +8,11 @@ package kotlinx.rpc.internal.utils message = "This API is experimental and can be changed or removed at any time.", level = RequiresOptIn.Level.ERROR, ) +@Target( + AnnotationTarget.CLASS, + AnnotationTarget.FUNCTION, + AnnotationTarget.TYPEALIAS, + AnnotationTarget.PROPERTY, + AnnotationTarget.ANNOTATION_CLASS, +) public annotation class ExperimentalRpcApi