// Copyright (c) 2024, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// Dart test program for testing dart:ffi callbacks that take advantage of
// subtyping rules.
//
// VMOptions=
// VMOptions=--stacktrace-every=100
// VMOptions=--use-slow-path
// VMOptions=--use-slow-path --stacktrace-every=100
// VMOptions=--dwarf_stack_traces --no-retain_function_objects --no-retain_code_objects
// VMOptions=--test_il_serialization
// VMOptions=--profiler --profile_vm=true
// VMOptions=--profiler --profile_vm=false
// SharedObjects=ffi_test_functions

import 'dart:async';
import 'dart:ffi';

import "package:expect/expect.dart";

import 'dylib_utils.dart';

final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");

typedef TwoIntVoidFnNativeType = Void Function(Pointer, Int32, Int32);
typedef TwoIntVoidFnType = void Function(Pointer, int, int);
final callTwoIntVoidFunction =
    ffiTestFunctions.lookupFunction<TwoIntVoidFnNativeType, TwoIntVoidFnType>(
        "CallTwoIntVoidFunction");

typedef TwoIntPointerFnNativeType = Pointer<NativeType> Function(
    Pointer, Int32, Int32);
typedef TwoIntPointerFnType = Pointer<NativeType> Function(Pointer, int, int);
final callTwoIntPointerFunction = ffiTestFunctions.lookupFunction<
    TwoIntPointerFnNativeType,
    TwoIntPointerFnType>("CallTwoIntPointerFunction");

typedef TwoPointerIntFnNativeType = Int32 Function(
    Pointer, Pointer<NativeType>, Pointer<NativeType>);
typedef TwoPointerIntFnType = int Function(
    Pointer, Pointer<NativeType>, Pointer<NativeType>);
final callTwoPointerIntFunction = ffiTestFunctions.lookupFunction<
    TwoPointerIntFnNativeType,
    TwoPointerIntFnType>("CallTwoPointerIntFunction");

typedef VoidReturnFunction = Void Function(Int32, Int32);
int addVoidResult = 0;
int addVoid(int x, int y) {
  print("addVoid($x, $y)");
  addVoidResult = x + y;
  return addVoidResult;
}

final addVoidAsyncResult = Completer<int>();
int addVoidAsync(int x, int y) {
  print("addVoidAsync($x, $y)");
  final result = x + y;
  addVoidAsyncResult.complete(result);
  return result;
}

typedef NaTyPtrReturnFunction = Pointer<NativeType> Function(Int32, Int32);
Pointer<Int64> addInt64PtrReturn(int x, int y) {
  print("addInt64PtrReturn($x, $y)");
  return Pointer<Int64>.fromAddress(x + y);
}

typedef Int64PtrParamFunction = Int32 Function(Pointer<Int64>, Pointer<Int64>);
int addNaTyPtrParam(Pointer<NativeType> x, Pointer<NativeType> y) {
  print("addNaTyPtrParam($x, $y)");
  return x.address + y.address;
}

Future<void> main() async {
  await testReturnVoid();
  testReturnSubtype();
  testParamSubtype();
  print("Done! :)");
}

Future<void> testReturnVoid() async {
  // If the native function type returns void, the Dart function can return
  // anything.
  final legacyCallback = Pointer.fromFunction<VoidReturnFunction>(addVoid);
  callTwoIntVoidFunction(legacyCallback, 100, 23);
  Expect.equals(123, addVoidResult);

  final isolateLocal = NativeCallable<VoidReturnFunction>.isolateLocal(addVoid)
    ..keepIsolateAlive = false;
  callTwoIntVoidFunction(isolateLocal.nativeFunction, 400, 56);
  Expect.equals(456, addVoidResult);

  final listener = NativeCallable<VoidReturnFunction>.listener(addVoidAsync)
    ..keepIsolateAlive = false;
  callTwoIntVoidFunction(listener.nativeFunction, 700, 89);
  Expect.equals(789, await addVoidAsyncResult.future);
}

void testReturnSubtype() {
  // The Dart function is allowed to return a subtype of the native return type.
  final legacyCallback =
      Pointer.fromFunction<NaTyPtrReturnFunction>(addInt64PtrReturn);
  Expect.equals(
      123, callTwoIntPointerFunction(legacyCallback, 100, 23).address);

  final isolateLocal =
      NativeCallable<NaTyPtrReturnFunction>.isolateLocal(addInt64PtrReturn)
        ..keepIsolateAlive = false;
  Expect.equals(456,
      callTwoIntPointerFunction(isolateLocal.nativeFunction, 400, 56).address);
}

void testParamSubtype() {
  // The Dart function is allowed to accept params that are a supertype of the
  // native type's params.
  final legacyCallback =
      Pointer.fromFunction<Int64PtrParamFunction>(addNaTyPtrParam, 0);
  Expect.equals(
      123,
      callTwoPointerIntFunction(legacyCallback, Pointer<Int64>.fromAddress(100),
          Pointer<Int64>.fromAddress(23)));

  final isolateLocal = NativeCallable<Int64PtrParamFunction>.isolateLocal(
      addNaTyPtrParam,
      exceptionalReturn: 0)
    ..keepIsolateAlive = false;
  Expect.equals(
      456,
      callTwoPointerIntFunction(isolateLocal.nativeFunction,
          Pointer<Int64>.fromAddress(400), Pointer<Int64>.fromAddress(56)));
}
