| /* |
| * Copyright 2010-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license |
| * that can be found in the LICENSE file. |
| */ |
| // IGNORE_KLIB_BACKEND_ERRORS_WITH_CUSTOM_SECOND_STAGE: Native:* |
| // ^^^ KT-86026 TODO: Rework testdata to move functions/globals definitions from .def/.h into separate source files |
| |
| // TARGET_BACKEND: NATIVE |
| // WITH_PLATFORM_LIBS |
| // MODULE: cinterop |
| // FILE: ccallbacksAndVarargs.def |
| --- |
| #include <stdarg.h> |
| |
| struct S { |
| int x; |
| }; |
| |
| static int getX(struct S (*callback)(void)) { |
| return callback().x; |
| } |
| |
| static void applyCallback(struct S s, void (*callback)(struct S)) { |
| callback(s); |
| } |
| |
| static struct S makeS(int x, ...) { |
| return (struct S){ x }; |
| } |
| |
| enum E { |
| ZERO, ONE, TWO |
| }; |
| |
| static enum E makeE(int ordinal, ...) { |
| return ordinal; |
| } |
| |
| struct Args { |
| char a1; |
| char a2; |
| short a3; |
| int a4; |
| long long a5; |
| float a6; |
| double a7; |
| void* a8; |
| unsigned char a9; |
| unsigned short a10; |
| unsigned int a11; |
| unsigned long long a12; |
| enum E a13; |
| struct S a14; |
| void* a15; |
| }; |
| |
| static struct Args getVarargs(int ignore, ...) { |
| va_list args; |
| va_start(args, ignore); |
| |
| struct Args result = { |
| va_arg(args, char), |
| va_arg(args, char), |
| va_arg(args, short), |
| va_arg(args, int), |
| va_arg(args, long long), |
| va_arg(args, double), |
| va_arg(args, double), |
| va_arg(args, void*), |
| va_arg(args, unsigned char), |
| va_arg(args, unsigned short), |
| va_arg(args, unsigned int), |
| va_arg(args, unsigned long long), |
| va_arg(args, enum E), |
| va_arg(args, struct S), |
| va_arg(args, void*) |
| }; |
| |
| va_end(args); |
| |
| return result; |
| } |
| |
| static int sum(int first, int second) { |
| return first + second; |
| } |
| |
| // MODULE: main(cinterop) |
| // FILE: main.kt |
| |
| @file:OptIn(kotlinx.cinterop.ExperimentalForeignApi::class) |
| |
| import kotlin.test.* |
| import kotlinx.cinterop.* |
| import ccallbacksAndVarargs.* |
| |
| fun box(): String { |
| testStructCallbacks() |
| testVarargs() |
| testCallableReferences() |
| |
| return "OK" |
| } |
| |
| fun testStructCallbacks() { |
| assertEquals(42, getX(staticCFunction { -> cValue<S> { x = 42 } })) |
| applyCallback(cValue { x = 17 }, staticCFunction { it: CValue<S> -> |
| assertEquals(17, it.useContents { x }) |
| it.useContents { |
| val xRef = ::x |
| assertEquals(17, xRef.get()) |
| } |
| }) |
| |
| assertEquals(66, makeS(66, 111).useContents { x }) |
| } |
| |
| fun testVarargs() { |
| assertEquals(E.ONE, makeE(1)) |
| |
| getVarargs( |
| 0, |
| true, |
| 2.toByte(), |
| Short.MIN_VALUE, |
| 42, |
| Long.MAX_VALUE, |
| 3.14f, |
| 2.71, |
| 0x1234ABCDL.toCPointer<COpaque>(), |
| UByte.MAX_VALUE, |
| 22.toUShort(), |
| 111u, |
| ULong.MAX_VALUE, |
| E.TWO, |
| cValue<S> { x = 15 }, |
| null |
| ).useContents { |
| assertEquals(1, a1) |
| assertEquals(2.toByte(), a2) |
| assertEquals(Short.MIN_VALUE, a3) |
| assertEquals(42, a4) |
| assertEquals(Long.MAX_VALUE, a5) |
| assertEquals(3.14f, a6) |
| assertEquals(2.71, a7) |
| assertEquals(0x1234ABCDL, a8.toLong()) |
| assertEquals(UByte.MAX_VALUE, a9) |
| assertEquals(22.toUShort(), a10) |
| assertEquals(111u, a11) |
| assertEquals(ULong.MAX_VALUE, a12) |
| assertEquals(E.TWO, a13) |
| assertEquals(15, a14.x) |
| assertEquals(null, a15) |
| } |
| } |
| |
| fun testCallableReferences() { |
| val sumRef = ::sum |
| assertEquals(3, sumRef(1, 2)) |
| |
| val sumPtr = staticCFunction(::sum) |
| assertEquals(7, sumPtr(3, 4)) |
| |
| val anonymousFunPtr = staticCFunction(fun (x: Int, y: Int): Int { return x + y }) |
| assertEquals(11, anonymousFunPtr(5, 6)) |
| } |