Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement the non-blittable type marshalling proposal #302

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
edcfded
First pass adding custom type marshaller.
jkoritzinsky Sep 25, 2020
40c8b87
Add support for a byref Value property and remove implementation rest…
jkoritzinsky Nov 3, 2020
fcdaa86
Add some negative tests for the custom native type marshalling.
jkoritzinsky Nov 4, 2020
086ef1c
Don't use stackalloc constructor if refkind is 'ref'.
jkoritzinsky Nov 4, 2020
f66d1d8
Add integration tests for non-blittable structs.
jkoritzinsky Nov 4, 2020
481bca3
Add more tests
jkoritzinsky Nov 4, 2020
60362ac
Merge branch 'feature/DllImportGenerator' of github.com:dotnet/runtim…
jkoritzinsky Nov 9, 2020
e26027d
Allow a GetPinnableReference call on the native type instead of allow…
jkoritzinsky Nov 12, 2020
7d729e1
Add missing cast.
jkoritzinsky Nov 13, 2020
e2e2f0e
Call GetPinnableReference.
jkoritzinsky Nov 13, 2020
b661b48
Assign stackalloc to pointer before creating span to work around life…
jkoritzinsky Nov 13, 2020
433275e
Merge branch 'feature/DllImportGenerator' of github.com:dotnet/runtim…
jkoritzinsky Nov 14, 2020
32c6336
Add custom message for errors.
jkoritzinsky Nov 14, 2020
7116872
Merge branch 'feature/DllImportGenerator' of github.com:dotnet/runtim…
jkoritzinsky Nov 16, 2020
f0b8241
Fix simple flags logic error.
jkoritzinsky Nov 16, 2020
4fae329
Move tests to CompileFails.cs
jkoritzinsky Nov 17, 2020
b359225
Add analyzer error for ref Value property.
jkoritzinsky Nov 17, 2020
563d39f
Update comments.
jkoritzinsky Nov 17, 2020
dfd4e26
Add simple MarshalUsing test
jkoritzinsky Nov 17, 2020
8bc0d70
Add more tests. Fix a bug with using a marshaller that supports pinni…
jkoritzinsky Nov 17, 2020
af8b53f
Fix typo in DNNE type hint attribute.
jkoritzinsky Nov 17, 2020
cba7503
Unify on boolean operators at the start of a line instead of at the e…
jkoritzinsky Nov 18, 2020
5be8022
Minor cleanup
jkoritzinsky Nov 19, 2020
28c1c58
Rename tests.
jkoritzinsky Nov 19, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
using SharedTypes;

using Xunit;

namespace DllImportGenerator.IntegrationTests
{
partial class NativeExportsNE
{
[GeneratedDllImport(nameof(NativeExportsNE), EntryPoint = "stringcontainer_deepduplicate")]
public static partial void DeepDuplicateStrings(StringContainer strings, out StringContainer pStringsOut);

[GeneratedDllImport(nameof(NativeExportsNE), EntryPoint = "stringcontainer_reverse_strings")]
public static partial void ReverseStrings(ref StringContainer strings);

[GeneratedDllImport(nameof(NativeExportsNE), EntryPoint = "get_long_bytes_as_double")]
public static partial double GetLongBytesAsDouble([MarshalUsing(typeof(DoubleToLongMarshaler))] double d);

[GeneratedDllImport(nameof(NativeExportsNE), EntryPoint = "negate_bools")]
public static partial void NegateBools(
BoolStruct boolStruct,
out BoolStruct pBoolStructOut);

[GeneratedDllImport(nameof(NativeExportsNE), EntryPoint = "and_bools_ref")]
[return: MarshalAs(UnmanagedType.U1)]
public static partial bool AndBoolsRef(in BoolStruct boolStruct);

[GeneratedDllImport(nameof(NativeExportsNE), EntryPoint = "double_int_ref")]
public static partial IntWrapper DoubleIntRef(IntWrapper pInt);

[GeneratedDllImport(nameof(NativeExportsNE), EntryPoint = "reverse_replace_ref_ushort")]
public static partial void ReverseReplaceString([MarshalUsing(typeof(Utf16StringMarshaler))] ref string s);

[GeneratedDllImport(nameof(NativeExportsNE), EntryPoint = "return_length_ushort")]
public static partial int ReturnStringLength([MarshalUsing(typeof(Utf16StringMarshaler))] string s);
}

public class CustomMarshallingTests
{
[Fact]
public void NonBlittableStructWithFree()
{
var stringContainer = new StringContainer
{
str1 = "Foo",
str2 = "Bar"
};

NativeExportsNE.DeepDuplicateStrings(stringContainer, out var stringContainer2);

Assert.Equal(stringContainer, stringContainer2);
}

[Fact]
public void MarshalUsing()
{
double d = 1234.56789;

Assert.Equal(d, NativeExportsNE.GetLongBytesAsDouble(d));
}

[Fact]
public void NonBlittableStructWithoutAllocation()
{
var boolStruct = new BoolStruct
{
b1 = true,
b2 = false,
b3 = true
};

NativeExportsNE.NegateBools(boolStruct, out BoolStruct boolStructNegated);

Assert.Equal(!boolStruct.b1, boolStructNegated.b1);
Assert.Equal(!boolStruct.b2, boolStructNegated.b2);
Assert.Equal(!boolStruct.b3, boolStructNegated.b3);
}

[Fact]
public void GetPinnableReferenceMarshalling()
{
int originalValue = 42;
var wrapper = new IntWrapper { i = originalValue };

var retVal = NativeExportsNE.DoubleIntRef(wrapper);

Assert.Equal(originalValue * 2, wrapper.i);
Assert.Equal(originalValue * 2, retVal.i);
}

[Fact]
public void NonBlittableStructRef()
{
var stringContainer = new StringContainer
{
str1 = "Foo",
str2 = "Bar"
};

var expected = new StringContainer
{
str1 = ReverseUTF8Bytes(stringContainer.str1),
str2 = ReverseUTF8Bytes(stringContainer.str2)
};

var stringContainerCopy = stringContainer;

NativeExportsNE.ReverseStrings(ref stringContainerCopy);

Assert.Equal(expected, stringContainerCopy);
}

[Theory]
[InlineData(true, true, true)]
[InlineData(true, true, false)]
[InlineData(true, false, true)]
[InlineData(true, false, false)]
[InlineData(false, true, true)]
[InlineData(false, true, false)]
[InlineData(false, false, true)]
[InlineData(false, false, false)]
public void NonBlittableStructIn(bool b1, bool b2, bool b3)
{
var container = new BoolStruct
{
b1 = b1,
b2 = b2,
b3 = b3
};

Assert.Equal(b1 && b2 && b3, NativeExportsNE.AndBoolsRef(container));
}

[Fact]
public void NonBlittableStructStackallocPinnableNativeMarshalling()
{
string str = "Hello world!";
Assert.Equal(str.Length, NativeExportsNE.ReturnStringLength(str));
}

[Fact]
public void NonBlittableStructPinnableMarshalerPassByRef()
{
string str = "Hello world!";
string expected = ReverseChars(str);
NativeExportsNE.ReverseReplaceString(ref str);
Assert.Equal(expected, str);
}

private static string ReverseChars(string value)
{
if (value == null)
return null;

var chars = value.ToCharArray();
Array.Reverse(chars);
return new string(chars);
}

private static string ReverseUTF8Bytes(string value)
{
if (value == null)
return null;

byte[] bytes = Encoding.UTF8.GetBytes(value);
Array.Reverse(bytes);
return Encoding.UTF8.GetString(bytes);
}
}
}
Loading