// 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
// 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)));
}
