Skip to content

Commit

Permalink
Generic delegate support (#41)
Browse files Browse the repository at this point in the history
* 2.0 release - update release notes.

* Split out delegate definition logic into an extension method.

* Stub out generic delegate wrapper class.

* Implement basic wrapper generation.

* Implement basic managed-to-native generic delegate marshalling.

* Correct mixed-up functions.

* Remove loading of null object instead of the correct parameter.

* Implement native-to-managed generic delegate return types.

* Add documentation.

* Implement nested generics. Kinda works on Mono, but not Core.

* Update package version and release notes.
  • Loading branch information
Nihlus authored Jul 26, 2018
1 parent f466f36 commit 8e6b862
Show file tree
Hide file tree
Showing 16 changed files with 1,157 additions and 74 deletions.
3 changes: 2 additions & 1 deletion AdvanceDLSupport.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Passthrough/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
52 changes: 52 additions & 0 deletions AdvancedDLSupport.Tests/Data/Interfaces/IGenericDelegateLibrary.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//
// IGenericDelegateLibrary.cs
//
// Copyright (c) 2018 Firwood Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//

using System;

#pragma warning disable SA1600, CS1591

namespace AdvancedDLSupport.Tests.Data
{
public interface IGenericDelegateLibrary
{
void ExecuteAction(Action action);

void ExecuteActionT1(Action<int> action);

void ExecuteActionT1Nested(Action<Action<int>> action);

int ExecuteFuncT1(Func<int> func);

int ExecuteFuncT1T2(Func<int, int> func);

int ExecuteFuncT1T2Nested(Func<Func<int, int>, int> func);

Action GetNativeAction();

Action<int> GetNativeActionT1();

Action<Action<int>> GetNativeActionT1Nested();

Func<int> GetNativeFuncT1();

Func<int, int> GetNativeFuncT1T2();

Func<Func<int, int>, int> GetNativeFuncT1T2Nested();
}
}
170 changes: 170 additions & 0 deletions AdvancedDLSupport.Tests/Tests/Integration/GenericDelegateTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
//
// GenericDelegateTests.cs
//
// Copyright (c) 2018 Firwood Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//

using System;
using AdvancedDLSupport.Tests.Data;
using AdvancedDLSupport.Tests.TestBases;
using Xunit;

#pragma warning disable SA1600, CS1591

namespace AdvancedDLSupport.Tests.Integration
{
public class GenericDelegateTests
{
private const string LibraryName = "GenericDelegateTests";

public class FromManagedToNative : LibraryTestBase<IGenericDelegateLibrary>
{
public FromManagedToNative()
: base(LibraryName)
{
}

[Fact]
public void NativeCanCallAction()
{
bool ranAction = false;
Library.ExecuteAction(() => ranAction = true);

Assert.True(ranAction);
}

[Fact]
public void NativeCanCallActionWithParameter()
{
bool ranAction = false;
int result = 0;
Library.ExecuteActionT1(x =>
{
ranAction = true;
result = x;
});

Assert.True(ranAction);
Assert.Equal(5, result);
}

[Fact]
public void NativeCanCallFunc()
{
var result = Library.ExecuteFuncT1(() => 5);

Assert.Equal(5, result);
}

[Fact]
public void NativeCanCallFuncWithParameter()
{
var result = Library.ExecuteFuncT1T2(x => 5 * x);

Assert.Equal(25, result);
}

[Fact(Skip = "Not working due to CLR limitations.")]
public void NativeCanCallNestedAction()
{
bool ranAction = false;
Library.ExecuteActionT1Nested
(
action =>
{
ranAction = true;
action(5);
}
);

Assert.True(ranAction);
}

[Fact(Skip = "Not working due to CLR limitations.")]
public void NativeCanCallNestedFunc()
{
var result = Library.ExecuteFuncT1T2Nested
(
func => func(5)
);

Assert.Equal(25, result);
}
}

public class FromNativeToManaged : LibraryTestBase<IGenericDelegateLibrary>
{
public FromNativeToManaged()
: base(LibraryName)
{
}

[Fact]
public void ManagedCanCallAction()
{
var action = Library.GetNativeAction();
action();
}

[Fact]
public void ManagedCanCallActionWithParameter()
{
var action = Library.GetNativeActionT1();
action(5);
}

[Fact]
public void ManagedCanCallFunc()
{
var func = Library.GetNativeFuncT1();
var result = func();

Assert.Equal(5, result);
}

[Fact]
public void ManagedCanCallFuncWithParameter()
{
var func = Library.GetNativeFuncT1T2();
var result = func(5);

Assert.Equal(25, result);
}

[Fact(Skip = "Not working due to CLR limitations.")]
public void ManagedCanCallNestedAction()
{
var action = Library.GetNativeActionT1Nested();

int result = 0;
action(i => result = i);

Assert.Equal(5, result);
}

[Fact(Skip = "Not working due to CLR limitations.")]
public void ManagedCanCallNestedFunc()
{
var func = Library.GetNativeFuncT1T2Nested();

int result = 0;
func(i => result = i * 5);

Assert.Equal(25, result);
}
}
}
}
1 change: 1 addition & 0 deletions AdvancedDLSupport.Tests/c/CMake/install-functions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ function(install_for_frameworks FRAMEWORKS)
IndirectCallTests
NameManglingTests
SymbolTransformationTests
GenericDelegateTests
COMPONENT
standard
DESTINATION
Expand Down
3 changes: 3 additions & 0 deletions AdvancedDLSupport.Tests/c/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ add_library(NullableTests SHARED src/NullableTests.c ${SHARED_HEADERS})
add_library(IndirectCallTests SHARED src/IndirectCallTests.c ${SHARED_HEADERS})
add_library(NameManglingTests SHARED src/NameManglingTests.c ${SHARED_HEADERS})
add_library(SymbolTransformationTests SHARED src/SymbolTransformationTests.c ${SHARED_HEADERS} src/SymbolTransformationTests.c)
add_library(GenericDelegateTests SHARED src/GenericDelegateTests.c ${SHARED_HEADERS} src/GenericDelegateTests.c)

if (IS_UNIX_COMPILER)
# Any CPU is assumed to be 64-bit
Expand All @@ -64,6 +65,7 @@ if (IS_UNIX_COMPILER)
set_target_properties(IndirectCallTests PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64")
set_target_properties(NameManglingTests PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64")
set_target_properties(SymbolTransformationTests PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64")
set_target_properties(GenericDelegateTests PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64")
elseif (BUILD_PLATFORM STREQUAL "x86")
set_target_properties(BaseTests PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
set_target_properties(DisposeTests PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
Expand All @@ -79,6 +81,7 @@ if (IS_UNIX_COMPILER)
set_target_properties(IndirectCallTests PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
set_target_properties(NameManglingTests PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
set_target_properties(SymbolTransformationTests PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
set_target_properties(GenericDelegateTests PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
endif()

set_target_properties(BaseTests-x64 PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64")
Expand Down
118 changes: 118 additions & 0 deletions AdvancedDLSupport.Tests/c/src/GenericDelegateTests.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
//
// GenericDelegateTests.c
//
// Author:
// Jarl Gullberg <[email protected]>
//
// Copyright (c) 2018 Jarl Gullberg
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//

#include <stdlib.h>
#include <stdio.h>
#include "comp.h"

typedef void (*Action)();
typedef void (*ActionT1)(int t1);
typedef void (*ActionT1Nested)(ActionT1 action);

typedef int (*FuncT1)();
typedef int (*FuncT1T2)(int t2);
typedef int (*FuncT1T2Nested)(FuncT1T2 func);

void NativeActionT1(int t1);

int NativeFuncT1T2(int t2);

__declspec(dllexport) void ExecuteAction(Action action)
{
action();
}

__declspec(dllexport) void ExecuteActionT1(ActionT1 action)
{
action(5);
}

__declspec(dllexport) void ExecuteActionT1Nested(ActionT1Nested action)
{
fprintf(stdout, "In nested, seeing function pointer as %x", (unsigned int)&NativeActionT1);
action(&NativeActionT1);
}

__declspec(dllexport) int ExecuteFuncT1(FuncT1 func)
{
return func();
}

__declspec(dllexport) int ExecuteFuncT1T2(FuncT1T2 func)
{
return func(5);
}

__declspec(dllexport) int ExecuteFuncT1T2Nested(FuncT1T2Nested func)
{
return func(&NativeFuncT1T2);
}

__declspec(dllexport) void NativeAction()
{
fprintf(stdout, "Living in native land!");
}

__declspec(dllexport) void NativeActionT1(int t1)
{
fprintf(stdout, "Living in native land, seeing parameter as %d!", t1);
}

__declspec(dllexport) Action GetNativeAction()
{
return &NativeAction;
}

__declspec(dllexport) ActionT1 GetNativeActionT1()
{
return &NativeActionT1;
}

__declspec(dllexport) ActionT1Nested GetNativeActionT1Nested()
{
return &ExecuteActionT1;
}

__declspec(dllexport) int NativeFuncT1()
{
return 5;
}

__declspec(dllexport) FuncT1 GetNativeFuncT1()
{
return &NativeFuncT1;
}

__declspec(dllexport) int NativeFuncT1T2(int t2)
{
return t2 * 5;
}

__declspec(dllexport) FuncT1T2 GetNativeFuncT1T2()
{
return &NativeFuncT1T2;
}

__declspec(dllexport) FuncT1T2Nested GetNativeFuncT1T2Nested()
{
return &ExecuteFuncT1T2;
}
Loading

0 comments on commit 8e6b862

Please sign in to comment.