Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElinor Fung <elfung@microsoft.com>2022-07-01 22:34:46 +0300
committerGitHub <noreply@github.com>2022-07-01 22:34:46 +0300
commit19811c279a5f97bbda203530a26d9e7244faeaa4 (patch)
treebd26b291a2edf2d9a7fadc0c2c69bd78f588c9e7 /src/libraries/System.Runtime.InteropServices/tests
parent6d8a6c25768eab0fda32365e10812ef4ca68ff39 (diff)
Basic support for stateless linear collection marshalling (#71473)
Basic stateless linear collection marshalling for blittable elements Not handled: - caller-allocated buffer - guaranteed unmarshal - pinnable reference - non-blittable element marshalling - element scenarios on custom marshallers
Diffstat (limited to 'src/libraries/System.Runtime.InteropServices/tests')
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ElementUnmanagedTypeAttribute.cs17
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/ArrayTests.Custom.cs142
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CollectionTests.V1.cs246
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CollectionTests.cs140
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs386
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs7
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs133
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.V1.cs32
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.cs89
9 files changed, 883 insertions, 309 deletions
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ElementUnmanagedTypeAttribute.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ElementUnmanagedTypeAttribute.cs
new file mode 100644
index 00000000000..d0f508904a1
--- /dev/null
+++ b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ElementUnmanagedTypeAttribute.cs
@@ -0,0 +1,17 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System.Runtime.InteropServices.Marshalling
+{
+ /// <summary>
+ /// Specifies that a particular generic parameter is the collection element's unmanaged type.
+ /// </summary>
+ /// <remarks>
+ /// If this attribute is provided on a generic parameter of a marshaller, then the generator will assume
+ /// that it is a linear collection marshaller.
+ /// </remarks>
+ [AttributeUsage(AttributeTargets.GenericParameter)]
+ public sealed class ElementUnmanagedTypeAttribute : Attribute
+ {
+ }
+}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/ArrayTests.Custom.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/ArrayTests.Custom.cs
new file mode 100644
index 00000000000..a1b8789fa16
--- /dev/null
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/ArrayTests.Custom.cs
@@ -0,0 +1,142 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using SharedTypes;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
+using System.Text;
+
+using Xunit;
+
+namespace LibraryImportGenerator.IntegrationTests
+{
+ partial class NativeExportsNE
+ {
+ public partial class Arrays
+ {
+ // TODO: All these tests can be removed once we switch the array marshaller in runtime libraries
+ // to V2 of custom type marshalling shapes
+ public partial class Custom
+ {
+ [LibraryImport(NativeExportsNE_Binary, EntryPoint = "sum_int_array")]
+ public static partial int Sum([MarshalUsing(typeof(CustomArrayMarshaller<,>))] int[] values, int numValues);
+
+ [LibraryImport(NativeExportsNE_Binary, EntryPoint = "sum_int_array_ref")]
+ public static partial int SumInArray([MarshalUsing(typeof(CustomArrayMarshaller<,>))] in int[] values, int numValues);
+
+ [LibraryImport(NativeExportsNE_Binary, EntryPoint = "duplicate_int_array")]
+ public static partial void Duplicate([MarshalUsing(typeof(CustomArrayMarshaller<,>), CountElementName = "numValues")] ref int[] values, int numValues);
+
+ [LibraryImport(NativeExportsNE_Binary, EntryPoint = "create_range_array")]
+ [return: MarshalUsing(typeof(CustomArrayMarshaller<,>), CountElementName = "numValues")]
+ public static partial int[] CreateRange(int start, int end, out int numValues);
+
+ [LibraryImport(NativeExportsNE_Binary, EntryPoint = "create_range_array_out")]
+ public static partial void CreateRange_Out(int start, int end, out int numValues, [MarshalUsing(typeof(CustomArrayMarshaller<,>), CountElementName = "numValues")] out int[] res);
+
+ [LibraryImport(NativeExportsNE_Binary, EntryPoint = "sum_char_array", StringMarshalling = StringMarshalling.Utf16)]
+ public static partial int SumChars([MarshalUsing(typeof(CustomArrayMarshaller<,>))] char[] chars, int numElements);
+
+ [LibraryImport(NativeExportsNE_Binary, EntryPoint = "reverse_char_array", StringMarshalling = StringMarshalling.Utf16)]
+ public static partial void ReverseChars([MarshalUsing(typeof(CustomArrayMarshaller<,>), CountElementName = "numElements")] ref char[] chars, int numElements);
+
+ [LibraryImport(NativeExportsNE_Binary, EntryPoint = "get_long_bytes")]
+ [return: MarshalUsing(typeof(CustomArrayMarshaller<,>), ConstantElementCount = sizeof(long))]
+ public static partial byte[] GetLongBytes(long l);
+ }
+ }
+ }
+
+ public class ArrayTests_Custom
+ {
+ private int[] GetIntArray() => new[] { 1, 5, 79, 165, 32, 3 };
+
+ [Fact]
+ public void IntArray_ByValue()
+ {
+ int[] array = GetIntArray();
+ Assert.Equal(array.Sum(), NativeExportsNE.Arrays.Custom.Sum(array, array.Length));
+ }
+
+ [Fact]
+ public void NullIntArray_ByValue()
+ {
+ int[] array = null;
+ Assert.Equal(-1, NativeExportsNE.Arrays.Custom.Sum(array, 0));
+ }
+
+ [Fact]
+ public void ZeroLengthArray_MarshalledAsNonNull()
+ {
+ var array = new int[0];
+ Assert.Equal(0, NativeExportsNE.Arrays.Custom.Sum(array, array.Length));
+ }
+
+ [Fact]
+ public void IntArray_In()
+ {
+ int[] array = GetIntArray();
+ Assert.Equal(array.Sum(), NativeExportsNE.Arrays.Custom.SumInArray(array, array.Length));
+ }
+
+ [Fact]
+ public void IntArray_Ref()
+ {
+ int[] array = GetIntArray();
+ var newArray = array;
+ NativeExportsNE.Arrays.Custom.Duplicate(ref newArray, array.Length);
+ Assert.Equal((IEnumerable<int>)array, newArray);
+ }
+
+ [Fact]
+ public void CharArray_ByValue()
+ {
+ char[] array = CharacterTests.CharacterMappings().Select(o => (char)o[0]).ToArray();
+ Assert.Equal(array.Sum(c => c), NativeExportsNE.Arrays.Custom.SumChars(array, array.Length));
+ }
+
+ [Fact]
+ public void CharArray_Ref()
+ {
+ char[] array = CharacterTests.CharacterMappings().Select(o => (char)o[0]).ToArray();
+ var newArray = array;
+ NativeExportsNE.Arrays.Custom.ReverseChars(ref newArray, array.Length);
+ Assert.Equal(array.Reverse(), newArray);
+ }
+
+ [Fact]
+ public void IntArray_Return()
+ {
+ int start = 5;
+ int end = 20;
+
+ IEnumerable<int> expected = Enumerable.Range(start, end - start);
+ Assert.Equal(expected, NativeExportsNE.Arrays.Custom.CreateRange(start, end, out _));
+
+ int[] res;
+ NativeExportsNE.Arrays.Custom.CreateRange_Out(start, end, out _, out res);
+ Assert.Equal(expected, res);
+ }
+
+ [Fact]
+ public void NullArray_Return()
+ {
+ Assert.Null(NativeExportsNE.Arrays.Custom.CreateRange(1, 0, out _));
+
+ int[] res;
+ NativeExportsNE.Arrays.Custom.CreateRange_Out(1, 0, out _, out res);
+ Assert.Null(res);
+ }
+
+ [Fact]
+ public void ConstantSizeArray()
+ {
+ var longVal = 0x12345678ABCDEF10L;
+
+ Assert.Equal(longVal, MemoryMarshal.Read<long>(NativeExportsNE.Arrays.Custom.GetLongBytes(longVal)));
+ }
+ }
+}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CollectionTests.V1.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CollectionTests.V1.cs
new file mode 100644
index 00000000000..ea039de946e
--- /dev/null
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CollectionTests.V1.cs
@@ -0,0 +1,246 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using SharedTypes;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
+using System.Text;
+
+using Xunit;
+
+namespace LibraryImportGenerator.IntegrationTests
+{
+ partial class NativeExportsNE
+ {
+ public partial class Collections
+ {
+ public partial class V1
+ {
+ [LibraryImport(NativeExportsNE_Binary, EntryPoint = "sum_int_array")]
+ public static partial int Sum([MarshalUsing(typeof(ListMarshaller_V1<int>))] List<int> values, int numValues);
+
+ [LibraryImport(NativeExportsNE_Binary, EntryPoint = "sum_int_array_ref")]
+ public static partial int SumInArray([MarshalUsing(typeof(ListMarshaller_V1<int>))] in List<int> values, int numValues);
+
+ [LibraryImport(NativeExportsNE_Binary, EntryPoint = "duplicate_int_array")]
+ public static partial void Duplicate([MarshalUsing(typeof(ListMarshaller_V1<int>), CountElementName = "numValues")] ref List<int> values, int numValues);
+
+ [LibraryImport(NativeExportsNE_Binary, EntryPoint = "create_range_array")]
+ [return: MarshalUsing(typeof(ListMarshaller_V1<int>), CountElementName = "numValues")]
+ public static partial List<int> CreateRange(int start, int end, out int numValues);
+
+ [LibraryImport(NativeExportsNE_Binary, EntryPoint = "create_range_array_out")]
+ public static partial void CreateRange_Out(int start, int end, out int numValues, [MarshalUsing(typeof(ListMarshaller_V1<int>), CountElementName = "numValues")] out List<int> res);
+
+ [LibraryImport(NativeExportsNE_Binary, EntryPoint = "sum_string_lengths")]
+ public static partial int SumStringLengths([MarshalUsing(typeof(ListMarshaller_V1<string>)), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)] List<string> strArray);
+
+ [LibraryImport(NativeExportsNE_Binary, EntryPoint = "sum_string_lengths")]
+ public static partial int SumStringLengths([MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)] WrappedList_V1<string> strArray);
+
+ [LibraryImport(NativeExportsNE_Binary, EntryPoint = "reverse_strings_replace")]
+ public static partial void ReverseStrings_Ref([MarshalUsing(typeof(ListMarshaller_V1<string>), CountElementName = "numElements"), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)] ref List<string> strArray, out int numElements);
+
+ [LibraryImport(NativeExportsNE_Binary, EntryPoint = "reverse_strings_return")]
+ [return: MarshalUsing(typeof(ListMarshaller_V1<string>), CountElementName = "numElements"), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)]
+ public static partial List<string> ReverseStrings_Return([MarshalUsing(typeof(ListMarshaller_V1<string>), CountElementName = "numElements"), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)] List<string> strArray, out int numElements);
+
+ [LibraryImport(NativeExportsNE_Binary, EntryPoint = "reverse_strings_out")]
+ public static partial void ReverseStrings_Out(
+ [MarshalUsing(typeof(ListMarshaller_V1<string>)), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)] List<string> strArray,
+ out int numElements,
+ [MarshalUsing(typeof(ListMarshaller_V1<string>), CountElementName = "numElements"), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)] out List<string> res);
+
+ [LibraryImport(NativeExportsNE_Binary, EntryPoint = "get_long_bytes")]
+ [return: MarshalUsing(typeof(ListMarshaller_V1<byte>), ConstantElementCount = sizeof(long))]
+ public static partial List<byte> GetLongBytes(long l);
+
+ [LibraryImport(NativeExportsNE_Binary, EntryPoint = "and_all_members")]
+ [return: MarshalAs(UnmanagedType.U1)]
+ public static partial bool AndAllMembers([MarshalUsing(typeof(ListMarshaller_V1<BoolStruct_V1>))] List<BoolStruct_V1> pArray, int length);
+ }
+ }
+ }
+
+ public class CollectionTests_V1
+ {
+ [Fact]
+ public void BlittableElementColllectionMarshalledToNativeAsExpected()
+ {
+ var list = new List<int> { 1, 5, 79, 165, 32, 3 };
+ Assert.Equal(list.Sum(), NativeExportsNE.Collections.V1.Sum(list, list.Count));
+ }
+
+ [Fact]
+ public void NullBlittableElementColllectionMarshalledToNativeAsExpected()
+ {
+ Assert.Equal(-1, NativeExportsNE.Collections.V1.Sum(null, 0));
+ }
+
+ [Fact]
+ public void BlittableElementColllectionInParameter()
+ {
+ var list = new List<int> { 1, 5, 79, 165, 32, 3 };
+ Assert.Equal(list.Sum(), NativeExportsNE.Collections.V1.SumInArray(list, list.Count));
+ }
+
+ [Fact]
+ public void BlittableElementCollectionRefParameter()
+ {
+ var list = new List<int> { 1, 5, 79, 165, 32, 3 };
+ var newList = list;
+ NativeExportsNE.Collections.V1.Duplicate(ref newList, list.Count);
+ Assert.Equal((IEnumerable<int>)list, newList);
+ }
+
+ [Fact]
+ public void BlittableElementCollectionReturnedFromNative()
+ {
+ int start = 5;
+ int end = 20;
+
+ IEnumerable<int> expected = Enumerable.Range(start, end - start);
+ Assert.Equal(expected, NativeExportsNE.Collections.V1.CreateRange(start, end, out _));
+
+ List<int> res;
+ NativeExportsNE.Collections.V1.CreateRange_Out(start, end, out _, out res);
+ Assert.Equal(expected, res);
+ }
+
+ [Fact]
+ public void NullBlittableElementCollectionReturnedFromNative()
+ {
+ Assert.Null(NativeExportsNE.Collections.V1.CreateRange(1, 0, out _));
+
+ List<int> res;
+ NativeExportsNE.Collections.V1.CreateRange_Out(1, 0, out _, out res);
+ Assert.Null(res);
+ }
+
+ private static List<string> GetStringList()
+ {
+ return new()
+ {
+ "ABCdef 123$%^",
+ "🍜 !! 🍜 !!",
+ "🌲 木 🔥 火 🌾 土 🛡 金 🌊 水" ,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed vitae posuere mauris, sed ultrices leo. Suspendisse potenti. Mauris enim enim, blandit tincidunt consequat in, varius sit amet neque. Morbi eget porttitor ex. Duis mattis aliquet ante quis imperdiet. Duis sit.",
+ string.Empty,
+ null
+ };
+ }
+
+ [Fact]
+ public void ByValueCollectionWithNonBlittableElements()
+ {
+ var strings = GetStringList();
+ Assert.Equal(strings.Sum(str => str?.Length ?? 0), NativeExportsNE.Collections.V1.SumStringLengths(strings));
+ }
+
+ [Fact]
+ public void ByValueNullCollectionWithNonBlittableElements()
+ {
+ Assert.Equal(0, NativeExportsNE.Collections.V1.SumStringLengths(null));
+ }
+
+ [Fact]
+ public void ByValueCollectionWithNonBlittableElements_WithDefaultMarshalling()
+ {
+ var strings = new WrappedList_V1<string>(GetStringList());
+ Assert.Equal(strings.Wrapped.Sum(str => str?.Length ?? 0), NativeExportsNE.Collections.V1.SumStringLengths(strings));
+ }
+
+ [Fact]
+ public void ByRefCollectionWithNonBlittableElements()
+ {
+ var strings = GetStringList();
+ var expectedStrings = strings.Select(s => ReverseChars(s)).ToList();
+ NativeExportsNE.Collections.V1.ReverseStrings_Ref(ref strings, out _);
+
+ Assert.Equal((IEnumerable<string>)expectedStrings, strings);
+ }
+
+ [Fact]
+ public void ReturnCollectionWithNonBlittableElements()
+ {
+ var strings = GetStringList();
+ var expectedStrings = strings.Select(s => ReverseChars(s)).ToList();
+ Assert.Equal(expectedStrings, NativeExportsNE.Collections.V1.ReverseStrings_Return(strings, out _));
+
+ List<string> res;
+ NativeExportsNE.Collections.V1.ReverseStrings_Out(strings, out _, out res);
+ Assert.Equal(expectedStrings, res);
+ }
+
+ [Fact]
+ public void ByRefNullCollectionWithNonBlittableElements()
+ {
+ List<string> strings = null;
+ NativeExportsNE.Collections.V1.ReverseStrings_Ref(ref strings, out _);
+
+ Assert.Null(strings);
+ }
+
+ [Fact]
+ public void ReturnNullCollectionWithNonBlittableElements()
+ {
+ List<string> strings = null;
+ Assert.Null(NativeExportsNE.Collections.V1.ReverseStrings_Return(strings, out _));
+
+ List<string> res;
+ NativeExportsNE.Collections.V1.ReverseStrings_Out(strings, out _, out res);
+ Assert.Null(res);
+ }
+
+ [Fact]
+ public void ConstantSizeCollection()
+ {
+ var longVal = 0x12345678ABCDEF10L;
+
+ Assert.Equal(longVal, MemoryMarshal.Read<long>(CollectionsMarshal.AsSpan(NativeExportsNE.Collections.V1.GetLongBytes(longVal))));
+ }
+
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void CollectionWithSimpleNonBlittableTypeMarshalling(bool result)
+ {
+ var boolValues = new List<BoolStruct_V1>
+ {
+ new BoolStruct_V1
+ {
+ b1 = true,
+ b2 = true,
+ b3 = true,
+ },
+ new BoolStruct_V1
+ {
+ b1 = true,
+ b2 = true,
+ b3 = true,
+ },
+ new BoolStruct_V1
+ {
+ b1 = true,
+ b2 = true,
+ b3 = result,
+ },
+ };
+
+ Assert.Equal(result, NativeExportsNE.Collections.V1.AndAllMembers(boolValues, boolValues.Count));
+ }
+
+ private static string ReverseChars(string value)
+ {
+ if (value == null)
+ return null;
+
+ var chars = value.ToCharArray();
+ Array.Reverse(chars);
+ return new string(chars);
+ }
+ }
+}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CollectionTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CollectionTests.cs
index cf058810d43..b4851346917 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CollectionTests.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CollectionTests.cs
@@ -18,50 +18,24 @@ namespace LibraryImportGenerator.IntegrationTests
public partial class Collections
{
[LibraryImport(NativeExportsNE_Binary, EntryPoint = "sum_int_array")]
- public static partial int Sum([MarshalUsing(typeof(ListMarshaller<int>))] List<int> values, int numValues);
-
- [LibraryImport(NativeExportsNE_Binary, EntryPoint = "sum_int_array")]
- public static partial int Sum(ref int values, int numValues);
+ public static partial int Sum([MarshalUsing(typeof(ListMarshaller<,>))] List<int> values, int numValues);
[LibraryImport(NativeExportsNE_Binary, EntryPoint = "sum_int_array_ref")]
- public static partial int SumInArray([MarshalUsing(typeof(ListMarshaller<int>))] in List<int> values, int numValues);
+ public static partial int SumInArray([MarshalUsing(typeof(ListMarshaller<,>))] in List<int> values, int numValues);
[LibraryImport(NativeExportsNE_Binary, EntryPoint = "duplicate_int_array")]
- public static partial void Duplicate([MarshalUsing(typeof(ListMarshaller<int>), CountElementName = "numValues")] ref List<int> values, int numValues);
+ public static partial void Duplicate([MarshalUsing(typeof(ListMarshaller<,>), CountElementName = "numValues")] ref List<int> values, int numValues);
[LibraryImport(NativeExportsNE_Binary, EntryPoint = "create_range_array")]
- [return:MarshalUsing(typeof(ListMarshaller<int>), CountElementName = "numValues")]
+ [return: MarshalUsing(typeof(ListMarshaller<,>), CountElementName = "numValues")]
public static partial List<int> CreateRange(int start, int end, out int numValues);
[LibraryImport(NativeExportsNE_Binary, EntryPoint = "create_range_array_out")]
- public static partial void CreateRange_Out(int start, int end, out int numValues, [MarshalUsing(typeof(ListMarshaller<int>), CountElementName = "numValues")] out List<int> res);
-
- [LibraryImport(NativeExportsNE_Binary, EntryPoint = "sum_string_lengths")]
- public static partial int SumStringLengths([MarshalUsing(typeof(ListMarshaller<string>)), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)] List<string> strArray);
-
- [LibraryImport(NativeExportsNE_Binary, EntryPoint = "sum_string_lengths")]
- public static partial int SumStringLengths([MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)] WrappedList<string> strArray);
-
- [LibraryImport(NativeExportsNE_Binary, EntryPoint = "reverse_strings_replace")]
- public static partial void ReverseStrings_Ref([MarshalUsing(typeof(ListMarshaller<string>), CountElementName = "numElements"), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)] ref List<string> strArray, out int numElements);
-
- [LibraryImport(NativeExportsNE_Binary, EntryPoint = "reverse_strings_return")]
- [return: MarshalUsing(typeof(ListMarshaller<string>), CountElementName = "numElements"), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)]
- public static partial List<string> ReverseStrings_Return([MarshalUsing(typeof(ListMarshaller<string>), CountElementName = "numElements"), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)] List<string> strArray, out int numElements);
-
- [LibraryImport(NativeExportsNE_Binary, EntryPoint = "reverse_strings_out")]
- public static partial void ReverseStrings_Out(
- [MarshalUsing(typeof(ListMarshaller<string>)), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)] List<string> strArray,
- out int numElements,
- [MarshalUsing(typeof(ListMarshaller<string>), CountElementName = "numElements"), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)] out List<string> res);
+ public static partial void CreateRange_Out(int start, int end, out int numValues, [MarshalUsing(typeof(ListMarshaller<,>), CountElementName = "numValues")] out List<int> res);
[LibraryImport(NativeExportsNE_Binary, EntryPoint = "get_long_bytes")]
- [return:MarshalUsing(typeof(ListMarshaller<byte>), ConstantElementCount = sizeof(long))]
+ [return: MarshalUsing(typeof(ListMarshaller<,>), ConstantElementCount = sizeof(long))]
public static partial List<byte> GetLongBytes(long l);
-
- [LibraryImport(NativeExportsNE_Binary, EntryPoint = "and_all_members")]
- [return: MarshalAs(UnmanagedType.U1)]
- public static partial bool AndAllMembers([MarshalUsing(typeof(ListMarshaller<BoolStruct_V1>))] List<BoolStruct_V1> pArray, int length);
}
}
@@ -134,113 +108,11 @@ namespace LibraryImportGenerator.IntegrationTests
}
[Fact]
- public void ByValueCollectionWithNonBlittableElements()
- {
- var strings = GetStringList();
- Assert.Equal(strings.Sum(str => str?.Length ?? 0), NativeExportsNE.Collections.SumStringLengths(strings));
- }
-
- [Fact]
- public void ByValueNullCollectionWithNonBlittableElements()
- {
- Assert.Equal(0, NativeExportsNE.Collections.SumStringLengths(null));
- }
-
- [Fact]
- public void ByValueCollectionWithNonBlittableElements_WithDefaultMarshalling()
- {
- var strings = new WrappedList<string>(GetStringList());
- Assert.Equal(strings.Wrapped.Sum(str => str?.Length ?? 0), NativeExportsNE.Collections.SumStringLengths(strings));
- }
-
- [Fact]
- public void ByRefCollectionWithNonBlittableElements()
- {
- var strings = GetStringList();
- var expectedStrings = strings.Select(s => ReverseChars(s)).ToList();
- NativeExportsNE.Collections.ReverseStrings_Ref(ref strings, out _);
-
- Assert.Equal((IEnumerable<string>)expectedStrings, strings);
- }
-
- [Fact]
- public void ReturnCollectionWithNonBlittableElements()
- {
- var strings = GetStringList();
- var expectedStrings = strings.Select(s => ReverseChars(s)).ToList();
- Assert.Equal(expectedStrings, NativeExportsNE.Collections.ReverseStrings_Return(strings, out _));
-
- List<string> res;
- NativeExportsNE.Collections.ReverseStrings_Out(strings, out _, out res);
- Assert.Equal(expectedStrings, res);
- }
-
- [Fact]
- public void ByRefNullCollectionWithNonBlittableElements()
- {
- List<string> strings = null;
- NativeExportsNE.Collections.ReverseStrings_Ref(ref strings, out _);
-
- Assert.Null(strings);
- }
-
- [Fact]
- public void ReturnNullCollectionWithNonBlittableElements()
- {
- List<string> strings = null;
- Assert.Null(NativeExportsNE.Collections.ReverseStrings_Return(strings, out _));
-
- List<string> res;
- NativeExportsNE.Collections.ReverseStrings_Out(strings, out _, out res);
- Assert.Null(res);
- }
-
- [Fact]
public void ConstantSizeCollection()
{
var longVal = 0x12345678ABCDEF10L;
Assert.Equal(longVal, MemoryMarshal.Read<long>(CollectionsMarshal.AsSpan(NativeExportsNE.Collections.GetLongBytes(longVal))));
}
-
- [Theory]
- [InlineData(true)]
- [InlineData(false)]
- public void CollectionWithSimpleNonBlittableTypeMarshalling(bool result)
- {
- var boolValues = new List<BoolStruct_V1>
- {
- new BoolStruct_V1
- {
- b1 = true,
- b2 = true,
- b3 = true,
- },
- new BoolStruct_V1
- {
- b1 = true,
- b2 = true,
- b3 = true,
- },
- new BoolStruct_V1
- {
- b1 = true,
- b2 = true,
- b3 = result,
- },
- };
-
- Assert.Equal(result, NativeExportsNE.Collections.AndAllMembers(boolValues, boolValues.Count));
- }
-
- private static string ReverseChars(string value)
- {
- if (value == null)
- return null;
-
- var chars = value.ToCharArray();
- Array.Reverse(chars);
- return new string(chars);
- }
}
}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs
index d3e5b0c2e1f..eb3c4a66c00 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs
@@ -1379,49 +1379,162 @@ struct RecursiveStruct2
int i;
}";
- public static string CollectionByValue(string elementType) => BasicParameterByValue($"TestCollection<{elementType}>", DisableRuntimeMarshalling) + @"
-[NativeMarshalling(typeof(Marshaller<>))]
-class TestCollection<T> {}
-
-[CustomTypeMarshaller(typeof(TestCollection<>), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)]
-ref struct Marshaller<T>
-{
- public Marshaller(int nativeElementSize) : this() {}
- public Marshaller(TestCollection<T> managed, int nativeElementSize) : this() {}
- public System.ReadOnlySpan<T> GetManagedValuesSource() => throw null;
- public System.Span<T> GetManagedValuesDestination(int length) => throw null;
- public System.ReadOnlySpan<byte> GetNativeValuesSource(int length) => throw null;
- public System.Span<byte> GetNativeValuesDestination() => throw null;
- public System.IntPtr ToNativeValue() => throw null;
- public void FromNativeValue(System.IntPtr value) => throw null;
- public TestCollection<T> ToManaged() => throw null;
-}
+ public static class CustomCollectionMarshalling
+ {
+ public static string TestCollection(bool defineNativeMarshalling = true) => $@"
+{(defineNativeMarshalling ? "[NativeMarshalling(typeof(Marshaller<,>))]" : string.Empty)}
+class TestCollection<T> {{}}
";
- public static string CollectionByValue<T>() => CollectionByValue(typeof(T).ToString());
-
- public static string MarshalUsingCollectionCountInfoParametersAndModifiers(string collectionType) => $@"
+ public static string CollectionOutParameter(string collectionType, string predeclaration = "") => $@"
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
-{DisableRuntimeMarshalling}
+{predeclaration}
partial class Test
{{
[LibraryImport(""DoesNotExist"")]
- [return:MarshalUsing(ConstantElementCount=10)]
- public static partial {collectionType} Method(
- {collectionType} p,
- in {collectionType} pIn,
- int pRefSize,
- [MarshalUsing(CountElementName = ""pRefSize"")] ref {collectionType} pRef,
- [MarshalUsing(CountElementName = ""pOutSize"")] out {collectionType} pOut,
- out int pOutSize
- );
-}}";
+ public static partial int Method(
+ [MarshalUsing(ConstantElementCount = 10)] out {collectionType} pOut);
+}}
+";
+ public static string CollectionReturnType(string collectionType, string predeclaration = "") => $@"
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
+{predeclaration}
+partial class Test
+{{
+ [LibraryImport(""DoesNotExist"")]
+ [return: MarshalUsing(ConstantElementCount = 10)]
+ public static partial {collectionType} Method();
+}}
+";
+ public static class Stateless
+ {
+ public const string In = @"
+[CustomMarshaller(typeof(TestCollection<>), Scenario.ManagedToUnmanagedIn, typeof(Marshaller<,>))]
+static unsafe class Marshaller<T, [ElementUnmanagedType] TUnmanagedElement>
+{
+ public static byte* AllocateContainerForUnmanagedElements(TestCollection<T> managed, out int numElements) => throw null;
+ public static System.ReadOnlySpan<T> GetManagedValuesSource(TestCollection<T> managed) => throw null;
+ public static System.Span<TUnmanagedElement> GetUnmanagedValuesDestination(byte* unmanaged, int numElements) => throw null;
+}
+";
+ public const string InBuffer = @"
+[CustomMarshaller(typeof(TestCollection<>), Scenario.ManagedToUnmanagedIn, typeof(Marshaller<,>))]
+static unsafe class Marshaller<T, [ElementUnmanagedType] TUnmanagedElement>
+{
+ public const int BufferSize = 0x100;
+ public static byte* AllocateContainerForUnmanagedElements(TestCollection<T> managed, System.Span<byte> buffer, out int numElements) => throw null;
+ public static System.ReadOnlySpan<T> GetManagedValuesSource(TestCollection<T> managed) => throw null;
+ public static System.Span<TUnmanagedElement> GetUnmanagedValuesDestination(byte* unmanaged, int numElements) => throw null;
+}
+";
+ public const string Ref = @"
+[CustomMarshaller(typeof(TestCollection<>), Scenario.Default, typeof(Marshaller<,>))]
+static unsafe class Marshaller<T, [ElementUnmanagedType] TUnmanagedElement>
+{
+ public static byte* AllocateContainerForUnmanagedElements(TestCollection<T> managed, out int numElements) => throw null;
+ public static System.ReadOnlySpan<T> GetManagedValuesSource(TestCollection<T> managed) => throw null;
+ public static System.Span<TUnmanagedElement> GetUnmanagedValuesDestination(byte* unmanaged, int numElements) => throw null;
- public static string CustomCollectionWithMarshaller(bool enableDefaultMarshalling)
+ public static TestCollection<T> AllocateContainerForManagedElements(byte* unmanaged, int length) => throw null;
+ public static System.Span<T> GetManagedValuesDestination(TestCollection<T> managed) => throw null;
+ public static System.ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(byte* unmanaged, int numElements) => throw null;
+}
+";
+ public const string RefNested = @"
+[CustomMarshaller(typeof(TestCollection<>), Scenario.Default, typeof(Marshaller<,>.Ref.Nested))]
+static unsafe class Marshaller<T, [ElementUnmanagedType] TUnmanagedElement>
+{
+ static class Nested
+ {
+ static class Ref
{
- string nativeMarshallingAttribute = enableDefaultMarshalling ? "[NativeMarshalling(typeof(Marshaller<>))]" : string.Empty;
- return nativeMarshallingAttribute + @"class TestCollection<T> {}
+ public static byte* AllocateContainerForUnmanagedElements(TestCollection<T> managed, out int numElements) => throw null;
+ public static System.ReadOnlySpan<T> GetManagedValuesSource(TestCollection<T> managed) => throw null;
+ public static System.Span<TUnmanagedElement> GetUnmanagedValuesDestination(byte* unmanaged, int numElements) => throw null;
+
+ public static TestCollection<T> AllocateContainerForManagedElements(byte* unmanaged, int length) => throw null;
+ public static System.Span<T> GetManagedValuesDestination(TestCollection<T> managed) => throw null;
+ public static System.ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(byte* unmanaged, int numElements) => throw null;
+ }
+ }
+}
+";
+ public const string Out = @"
+[CustomMarshaller(typeof(TestCollection<>), Scenario.ManagedToUnmanagedOut, typeof(Marshaller<,>))]
+static unsafe class Marshaller<T, [ElementUnmanagedType] TUnmanagedElement>
+{
+ public static TestCollection<T> AllocateContainerForManagedElements(byte* unmanaged, int length) => throw null;
+ public static System.Span<T> GetManagedValuesDestination(TestCollection<T> managed) => throw null;
+ public static System.ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(byte* unmanaged, int numElements) => throw null;
+}
+";
+ public static string ByValue<T>() => ByValue(typeof(T).ToString());
+ public static string ByValue(string elementType) => BasicParameterByValue($"TestCollection<{elementType}>", DisableRuntimeMarshalling)
+ + TestCollection()
+ + In;
+
+ public static string ByValueCallerAllocatedBuffer<T>() => ByValueCallerAllocatedBuffer(typeof(T).ToString());
+ public static string ByValueCallerAllocatedBuffer(string elementType) => BasicParameterByValue($"TestCollection<{elementType}>", DisableRuntimeMarshalling)
+ + TestCollection()
+ + In;
+
+ public static string DefaultMarshallerParametersAndModifiers<T>() => DefaultMarshallerParametersAndModifiers(typeof(T).ToString());
+ public static string DefaultMarshallerParametersAndModifiers(string elementType) => MarshalUsingCollectionCountInfoParametersAndModifiers($"TestCollection<{elementType}>")
+ + TestCollection()
+ + Ref;
+
+ public static string CustomMarshallerParametersAndModifiers<T>() => CustomMarshallerParametersAndModifiers(typeof(T).ToString());
+ public static string CustomMarshallerParametersAndModifiers(string elementType) => MarshalUsingCollectionParametersAndModifiers($"TestCollection<{elementType}>", $"Marshaller<,>")
+ + TestCollection(defineNativeMarshalling: false)
+ + Ref;
+
+ public static string CustomMarshallerReturnValueLength<T>() => CustomMarshallerReturnValueLength(typeof(T).ToString());
+ public static string CustomMarshallerReturnValueLength(string elementType) => MarshalUsingCollectionReturnValueLength($"TestCollection<{elementType}>", $"Marshaller<,>")
+ + TestCollection(defineNativeMarshalling: false)
+ + Ref;
+
+ public static string NativeToManagedOnlyOutParameter<T>() => NativeToManagedOnlyOutParameter(typeof(T).ToString());
+ public static string NativeToManagedOnlyOutParameter(string elementType) => CollectionOutParameter($"TestCollection<{elementType}>")
+ + TestCollection()
+ + Out;
+
+ public static string NativeToManagedOnlyReturnValue<T>() => NativeToManagedOnlyReturnValue(typeof(T).ToString());
+ public static string NativeToManagedOnlyReturnValue(string elementType) => CollectionReturnType($"TestCollection<{elementType}>")
+ + TestCollection()
+ + Out;
+
+ public static string NestedMarshallerParametersAndModifiers<T>() => DefaultMarshallerParametersAndModifiers(typeof(T).ToString());
+ public static string NestedMarshallerParametersAndModifiers(string elementType) => MarshalUsingCollectionCountInfoParametersAndModifiers($"TestCollection<{elementType}>")
+ + TestCollection()
+ + RefNested;
+
+ public static string GenericCollectionMarshallingArityMismatch => BasicParameterByValue("TestCollection<int>", DisableRuntimeMarshalling)
+ + @"
+[NativeMarshalling(typeof(Marshaller<,,>))]
+class TestCollection<T> {}
+
+[CustomMarshaller(typeof(TestCollection<>), Scenario.Default, typeof(Marshaller<,,>))]
+static unsafe class Marshaller<T, U, [ElementUnmanagedType] TUnmanagedElement>
+{
+ public static byte* AllocateContainerForUnmanagedElements(TestCollection<T> managed, out int numElements) => throw null;
+ public static System.ReadOnlySpan<T> GetManagedValuesSource(TestCollection<T> managed) => throw null;
+ public static System.Span<TUnmanagedElement> GetUnmanagedValuesDestination(byte* unmanaged, int numElements) => throw null;
+
+ public static TestCollection<T> AllocateContainerForManagedElements(byte* unmanaged, int length) => throw null;
+ public static System.Span<T> GetManagedValuesDestination(TestCollection<T> managed) => throw null;
+ public static System.ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(byte* unmanaged, int numElements) => throw null;
+}
+";
+ }
+ }
+
+ public static class CustomCollectionMarshalling_V1
+ {
+ public static string ByValue(string elementType) => BasicParameterByValue($"TestCollection<{elementType}>", DisableRuntimeMarshalling) + @"
+[NativeMarshalling(typeof(Marshaller<>))]
+class TestCollection<T> {}
[CustomTypeMarshaller(typeof(TestCollection<>), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)]
ref struct Marshaller<T>
@@ -1435,95 +1548,44 @@ ref struct Marshaller<T>
public System.IntPtr ToNativeValue() => throw null;
public void FromNativeValue(System.IntPtr value) => throw null;
public TestCollection<T> ToManaged() => throw null;
-}";
- }
-
- public static string MarshalUsingCollectionCountInfoParametersAndModifiers<T>() => MarshalUsingCollectionCountInfoParametersAndModifiers(typeof(T).ToString());
-
- public static string CustomCollectionDefaultMarshallerParametersAndModifiers(string elementType) => MarshalUsingCollectionCountInfoParametersAndModifiers($"TestCollection<{elementType}>") + CustomCollectionWithMarshaller(enableDefaultMarshalling: true);
-
- public static string CustomCollectionDefaultMarshallerParametersAndModifiers<T>() => CustomCollectionDefaultMarshallerParametersAndModifiers(typeof(T).ToString());
-
- public static string MarshalUsingCollectionParametersAndModifiers(string collectionType, string marshallerType) => $@"
-using System.Runtime.InteropServices;
-using System.Runtime.InteropServices.Marshalling;
-{DisableRuntimeMarshalling}
-partial class Test
-{{
- [LibraryImport(""DoesNotExist"")]
- [return:MarshalUsing(typeof({marshallerType}), ConstantElementCount=10)]
- public static partial {collectionType} Method(
- [MarshalUsing(typeof({marshallerType}))] {collectionType} p,
- [MarshalUsing(typeof({marshallerType}))] in {collectionType} pIn,
- int pRefSize,
- [MarshalUsing(typeof({marshallerType}), CountElementName = ""pRefSize"")] ref {collectionType} pRef,
- [MarshalUsing(typeof({marshallerType}), CountElementName = ""pOutSize"")] out {collectionType} pOut,
- out int pOutSize
- );
-}}";
+}
+";
- public static string CustomCollectionCustomMarshallerParametersAndModifiers(string elementType) => MarshalUsingCollectionParametersAndModifiers($"TestCollection<{elementType}>", $"Marshaller<{elementType}>") + CustomCollectionWithMarshaller(enableDefaultMarshalling: false);
+ public static string ByValue<T>() => ByValue(typeof(T).ToString());
- public static string CustomCollectionCustomMarshallerParametersAndModifiers<T>() => CustomCollectionCustomMarshallerParametersAndModifiers(typeof(T).ToString());
+ public static string CustomCollectionWithMarshaller(bool enableDefaultMarshalling)
+ {
+ string nativeMarshallingAttribute = enableDefaultMarshalling ? "[NativeMarshalling(typeof(Marshaller<>))]" : string.Empty;
+ return nativeMarshallingAttribute + @"class TestCollection<T> {}
- public static string MarshalUsingCollectionReturnValueLength(string collectionType, string marshallerType) => $@"
-using System.Runtime.InteropServices;
-using System.Runtime.InteropServices.Marshalling;
-{DisableRuntimeMarshalling}
-partial class Test
-{{
- [LibraryImport(""DoesNotExist"")]
- public static partial int Method(
- [MarshalUsing(typeof({marshallerType}), CountElementName = MarshalUsingAttribute.ReturnsCountValue)] out {collectionType} pOut
- );
-}}";
+ [CustomTypeMarshaller(typeof(TestCollection<>), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)]
+ ref struct Marshaller<T>
+ {
+ public Marshaller(int nativeElementSize) : this() {}
+ public Marshaller(TestCollection<T> managed, int nativeElementSize) : this() {}
+ public System.ReadOnlySpan<T> GetManagedValuesSource() => throw null;
+ public System.Span<T> GetManagedValuesDestination(int length) => throw null;
+ public System.ReadOnlySpan<byte> GetNativeValuesSource(int length) => throw null;
+ public System.Span<byte> GetNativeValuesDestination() => throw null;
+ public System.IntPtr ToNativeValue() => throw null;
+ public void FromNativeValue(System.IntPtr value) => throw null;
+ public TestCollection<T> ToManaged() => throw null;
+ }";
+ }
- public static string CustomCollectionCustomMarshallerReturnValueLength(string elementType) => MarshalUsingCollectionReturnValueLength($"TestCollection<{elementType}>", $"Marshaller<{elementType}>") + CustomCollectionWithMarshaller(enableDefaultMarshalling: false);
+ public static string DefaultMarshallerParametersAndModifiers(string elementType) => MarshalUsingCollectionCountInfoParametersAndModifiers($"TestCollection<{elementType}>") + CustomCollectionWithMarshaller(enableDefaultMarshalling: true);
- public static string CustomCollectionCustomMarshallerReturnValueLength<T>() => CustomCollectionCustomMarshallerReturnValueLength(typeof(T).ToString());
+ public static string DefaultMarshallerParametersAndModifiers<T>() => DefaultMarshallerParametersAndModifiers(typeof(T).ToString());
- public static string MarshalUsingArrayParameterWithSizeParam(string sizeParamType, bool isByRef) => $@"
-using System.Runtime.InteropServices;
-using System.Runtime.InteropServices.Marshalling;
-{DisableRuntimeMarshalling}
-partial class Test
-{{
- [LibraryImport(""DoesNotExist"")]
- public static partial void Method(
- {(isByRef ? "ref" : "")} {sizeParamType} pRefSize,
- [MarshalUsing(CountElementName = ""pRefSize"")] ref int[] pRef
- );
-}}";
+ public static string CustomMarshallerParametersAndModifiers(string elementType) => MarshalUsingCollectionParametersAndModifiers($"TestCollection<{elementType}>", $"Marshaller<{elementType}>") + CustomCollectionWithMarshaller(enableDefaultMarshalling: false);
- public static string MarshalUsingArrayParameterWithSizeParam<T>(bool isByRef) => MarshalUsingArrayParameterWithSizeParam(typeof(T).ToString(), isByRef);
+ public static string CustomMarshallerParametersAndModifiers<T>() => CustomMarshallerParametersAndModifiers(typeof(T).ToString());
- public static string MarshalUsingCollectionWithConstantAndElementCount => $@"
-using System.Runtime.InteropServices;
-using System.Runtime.InteropServices.Marshalling;
-{DisableRuntimeMarshalling}
-partial class Test
-{{
- [LibraryImport(""DoesNotExist"")]
- public static partial void Method(
- int pRefSize,
- [MarshalUsing(ConstantElementCount = 10, CountElementName = ""pRefSize"")] ref int[] pRef
- );
-}}";
+ public static string CustomMarshallerReturnValueLength(string elementType) => MarshalUsingCollectionReturnValueLength($"TestCollection<{elementType}>", $"Marshaller<{elementType}>") + CustomCollectionWithMarshaller(enableDefaultMarshalling: false);
- public static string MarshalUsingCollectionWithNullElementName => $@"
-using System.Runtime.InteropServices;
-using System.Runtime.InteropServices.Marshalling;
-{DisableRuntimeMarshalling}
-partial class Test
-{{
- [LibraryImport(""DoesNotExist"")]
- public static partial void Method(
- int pRefSize,
- [MarshalUsing(CountElementName = null)] ref int[] pRef
- );
-}}";
+ public static string CustomMarshallerReturnValueLength<T>() => CustomMarshallerReturnValueLength(typeof(T).ToString());
- public static string GenericCollectionMarshallingArityMismatch => BasicParameterByValue("TestCollection<int>", DisableRuntimeMarshalling) + @"
+ public static string GenericCollectionMarshallingArityMismatch => BasicParameterByValue("TestCollection<int>", DisableRuntimeMarshalling) + @"
[NativeMarshalling(typeof(Marshaller<,>))]
class TestCollection<T> {}
@@ -1542,7 +1604,7 @@ ref struct Marshaller<T, U>
public TestCollection<T> ToManaged() => throw null;
}";
- public static string GenericCollectionWithCustomElementMarshalling => $@"
+ public static string GenericCollectionWithCustomElementMarshalling => $@"
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
{DisableRuntimeMarshalling}
@@ -1569,7 +1631,7 @@ struct IntWrapper
" + CustomCollectionWithMarshaller(enableDefaultMarshalling: true);
- public static string GenericCollectionWithCustomElementMarshallingDuplicateElementIndirectionDepth => $@"
+ public static string GenericCollectionWithCustomElementMarshallingDuplicateElementIndirectionDepth => $@"
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
{DisableRuntimeMarshalling}
@@ -1588,7 +1650,7 @@ struct IntWrapper
" + CustomCollectionWithMarshaller(enableDefaultMarshalling: true);
- public static string GenericCollectionWithCustomElementMarshallingUnusedElementIndirectionDepth => $@"
+ public static string GenericCollectionWithCustomElementMarshallingUnusedElementIndirectionDepth => $@"
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
{DisableRuntimeMarshalling}
@@ -1606,6 +1668,98 @@ struct IntWrapper
}}
" + CustomCollectionWithMarshaller(enableDefaultMarshalling: true);
+ }
+
+ public static string MarshalUsingCollectionCountInfoParametersAndModifiers(string collectionType) => $@"
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
+{DisableRuntimeMarshalling}
+partial class Test
+{{
+ [LibraryImport(""DoesNotExist"")]
+ [return:MarshalUsing(ConstantElementCount=10)]
+ public static partial {collectionType} Method(
+ {collectionType} p,
+ in {collectionType} pIn,
+ int pRefSize,
+ [MarshalUsing(CountElementName = ""pRefSize"")] ref {collectionType} pRef,
+ [MarshalUsing(CountElementName = ""pOutSize"")] out {collectionType} pOut,
+ out int pOutSize
+ );
+}}";
+
+ public static string MarshalUsingCollectionCountInfoParametersAndModifiers<T>() => MarshalUsingCollectionCountInfoParametersAndModifiers(typeof(T).ToString());
+
+ public static string MarshalUsingCollectionParametersAndModifiers(string collectionType, string marshallerType) => $@"
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
+{DisableRuntimeMarshalling}
+partial class Test
+{{
+ [LibraryImport(""DoesNotExist"")]
+ [return:MarshalUsing(typeof({marshallerType}), ConstantElementCount=10)]
+ public static partial {collectionType} Method(
+ [MarshalUsing(typeof({marshallerType}))] {collectionType} p,
+ [MarshalUsing(typeof({marshallerType}))] in {collectionType} pIn,
+ int pRefSize,
+ [MarshalUsing(typeof({marshallerType}), CountElementName = ""pRefSize"")] ref {collectionType} pRef,
+ [MarshalUsing(typeof({marshallerType}), CountElementName = ""pOutSize"")] out {collectionType} pOut,
+ out int pOutSize
+ );
+}}";
+
+ public static string MarshalUsingCollectionReturnValueLength(string collectionType, string marshallerType) => $@"
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
+{DisableRuntimeMarshalling}
+partial class Test
+{{
+ [LibraryImport(""DoesNotExist"")]
+ public static partial int Method(
+ [MarshalUsing(typeof({marshallerType}), CountElementName = MarshalUsingAttribute.ReturnsCountValue)] out {collectionType} pOut
+ );
+}}";
+
+ public static string MarshalUsingArrayParameterWithSizeParam(string sizeParamType, bool isByRef) => $@"
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
+{DisableRuntimeMarshalling}
+partial class Test
+{{
+ [LibraryImport(""DoesNotExist"")]
+ public static partial void Method(
+ {(isByRef ? "ref" : "")} {sizeParamType} pRefSize,
+ [MarshalUsing(CountElementName = ""pRefSize"")] ref int[] pRef
+ );
+}}";
+
+ public static string MarshalUsingArrayParameterWithSizeParam<T>(bool isByRef) => MarshalUsingArrayParameterWithSizeParam(typeof(T).ToString(), isByRef);
+
+ public static string MarshalUsingCollectionWithConstantAndElementCount => $@"
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
+{DisableRuntimeMarshalling}
+partial class Test
+{{
+ [LibraryImport(""DoesNotExist"")]
+ public static partial void Method(
+ int pRefSize,
+ [MarshalUsing(ConstantElementCount = 10, CountElementName = ""pRefSize"")] ref int[] pRef
+ );
+}}";
+
+ public static string MarshalUsingCollectionWithNullElementName => $@"
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
+{DisableRuntimeMarshalling}
+partial class Test
+{{
+ [LibraryImport(""DoesNotExist"")]
+ public static partial void Method(
+ int pRefSize,
+ [MarshalUsing(CountElementName = null)] ref int[] pRef
+ );
+}}";
public static string MarshalAsAndMarshalUsingOnReturnValue => $@"
using System.Runtime.InteropServices;
diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs
index 935980dbc73..539a5116bcf 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs
@@ -117,11 +117,12 @@ namespace LibraryImportGenerator.UnitTests
yield return new object[] { CodeSnippets.MarshalUsingCollectionWithNullElementName, 2, 0 };
// Generic collection marshaller has different arity than collection.
- yield return new object[] { CodeSnippets.GenericCollectionMarshallingArityMismatch, 2, 0 };
+ yield return new object[] { CodeSnippets.CustomCollectionMarshalling.Stateless.GenericCollectionMarshallingArityMismatch, 2, 0 };
+ yield return new object[] { CodeSnippets.CustomCollectionMarshalling_V1.GenericCollectionMarshallingArityMismatch, 2, 0 };
yield return new object[] { CodeSnippets.MarshalAsAndMarshalUsingOnReturnValue, 2, 0 };
- yield return new object[] { CodeSnippets.GenericCollectionWithCustomElementMarshallingDuplicateElementIndirectionDepth, 2, 0 };
- yield return new object[] { CodeSnippets.GenericCollectionWithCustomElementMarshallingUnusedElementIndirectionDepth, 1, 0 };
+ yield return new object[] { CodeSnippets.CustomCollectionMarshalling_V1.GenericCollectionWithCustomElementMarshallingDuplicateElementIndirectionDepth, 2, 0 };
+ yield return new object[] { CodeSnippets.CustomCollectionMarshalling_V1.GenericCollectionWithCustomElementMarshallingUnusedElementIndirectionDepth, 1, 0 };
yield return new object[] { CodeSnippets.RecursiveCountElementNameOnReturnValue, 2, 0 };
yield return new object[] { CodeSnippets.RecursiveCountElementNameOnParameter, 2, 0 };
yield return new object[] { CodeSnippets.MutuallyRecursiveCountElementNameOnParameter, 4, 0 };
diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs
index 5536cfd4a24..4a971cd7f1d 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs
@@ -222,20 +222,47 @@ namespace LibraryImportGenerator.UnitTests
yield return new[] { CodeSnippets.MaybeBlittableGenericTypeParametersAndModifiers<double>() };
yield return new[] { CodeSnippets.MaybeBlittableGenericTypeParametersAndModifiers<IntPtr>() };
yield return new[] { CodeSnippets.MaybeBlittableGenericTypeParametersAndModifiers<UIntPtr>() };
+ }
+ public static IEnumerable<object[]> CustomCollections()
+ {
// Custom collection marshalling
- yield return new[] { CodeSnippets.CollectionByValue<byte>() };
- yield return new[] { CodeSnippets.CollectionByValue<sbyte>() };
- yield return new[] { CodeSnippets.CollectionByValue<short>() };
- yield return new[] { CodeSnippets.CollectionByValue<ushort>() };
- yield return new[] { CodeSnippets.CollectionByValue<int>() };
- yield return new[] { CodeSnippets.CollectionByValue<uint>() };
- yield return new[] { CodeSnippets.CollectionByValue<long>() };
- yield return new[] { CodeSnippets.CollectionByValue<ulong>() };
- yield return new[] { CodeSnippets.CollectionByValue<float>() };
- yield return new[] { CodeSnippets.CollectionByValue<double>() };
- yield return new[] { CodeSnippets.CollectionByValue<IntPtr>() };
- yield return new[] { CodeSnippets.CollectionByValue<UIntPtr>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.ByValue<byte>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.ByValue<sbyte>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.ByValue<short>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.ByValue<ushort>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.ByValue<int>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.ByValue<uint>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.ByValue<long>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.ByValue<ulong>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.ByValue<float>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.ByValue<double>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.ByValue<IntPtr>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.ByValue<UIntPtr>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.ByValueCallerAllocatedBuffer<byte>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.ByValueCallerAllocatedBuffer<sbyte>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.ByValueCallerAllocatedBuffer<short>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.ByValueCallerAllocatedBuffer<ushort>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.ByValueCallerAllocatedBuffer<int>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.ByValueCallerAllocatedBuffer<uint>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.ByValueCallerAllocatedBuffer<long>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.ByValueCallerAllocatedBuffer<ulong>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.ByValueCallerAllocatedBuffer<float>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.ByValueCallerAllocatedBuffer<double>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.ByValueCallerAllocatedBuffer<IntPtr>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.ByValueCallerAllocatedBuffer<UIntPtr>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.ByValue<byte>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.ByValue<sbyte>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.ByValue<short>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.ByValue<ushort>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.ByValue<int>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.ByValue<uint>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.ByValue<long>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.ByValue<ulong>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.ByValue<float>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.ByValue<double>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.ByValue<IntPtr>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.ByValue<UIntPtr>() };
yield return new[] { CodeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers<byte[]>() };
yield return new[] { CodeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers<sbyte[]>() };
yield return new[] { CodeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers<short[]>() };
@@ -248,37 +275,66 @@ namespace LibraryImportGenerator.UnitTests
yield return new[] { CodeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers<double[]>() };
yield return new[] { CodeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers<IntPtr[]>() };
yield return new[] { CodeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers<UIntPtr[]>() };
- yield return new[] { CodeSnippets.CustomCollectionDefaultMarshallerParametersAndModifiers<byte>() };
- yield return new[] { CodeSnippets.CustomCollectionDefaultMarshallerParametersAndModifiers<sbyte>() };
- yield return new[] { CodeSnippets.CustomCollectionDefaultMarshallerParametersAndModifiers<short>() };
- yield return new[] { CodeSnippets.CustomCollectionDefaultMarshallerParametersAndModifiers<ushort>() };
- yield return new[] { CodeSnippets.CustomCollectionDefaultMarshallerParametersAndModifiers<int>() };
- yield return new[] { CodeSnippets.CustomCollectionDefaultMarshallerParametersAndModifiers<uint>() };
- yield return new[] { CodeSnippets.CustomCollectionDefaultMarshallerParametersAndModifiers<long>() };
- yield return new[] { CodeSnippets.CustomCollectionDefaultMarshallerParametersAndModifiers<ulong>() };
- yield return new[] { CodeSnippets.CustomCollectionDefaultMarshallerParametersAndModifiers<float>() };
- yield return new[] { CodeSnippets.CustomCollectionDefaultMarshallerParametersAndModifiers<double>() };
- yield return new[] { CodeSnippets.CustomCollectionDefaultMarshallerParametersAndModifiers<IntPtr>() };
- yield return new[] { CodeSnippets.CustomCollectionDefaultMarshallerParametersAndModifiers<UIntPtr>() };
- yield return new[] { CodeSnippets.CustomCollectionCustomMarshallerParametersAndModifiers<byte>() };
- yield return new[] { CodeSnippets.CustomCollectionCustomMarshallerParametersAndModifiers<sbyte>() };
- yield return new[] { CodeSnippets.CustomCollectionCustomMarshallerParametersAndModifiers<short>() };
- yield return new[] { CodeSnippets.CustomCollectionCustomMarshallerParametersAndModifiers<ushort>() };
- yield return new[] { CodeSnippets.CustomCollectionCustomMarshallerParametersAndModifiers<int>() };
- yield return new[] { CodeSnippets.CustomCollectionCustomMarshallerParametersAndModifiers<uint>() };
- yield return new[] { CodeSnippets.CustomCollectionCustomMarshallerParametersAndModifiers<long>() };
- yield return new[] { CodeSnippets.CustomCollectionCustomMarshallerParametersAndModifiers<ulong>() };
- yield return new[] { CodeSnippets.CustomCollectionCustomMarshallerParametersAndModifiers<float>() };
- yield return new[] { CodeSnippets.CustomCollectionCustomMarshallerParametersAndModifiers<double>() };
- yield return new[] { CodeSnippets.CustomCollectionCustomMarshallerParametersAndModifiers<IntPtr>() };
- yield return new[] { CodeSnippets.CustomCollectionCustomMarshallerParametersAndModifiers<UIntPtr>() };
- yield return new[] { CodeSnippets.CustomCollectionCustomMarshallerReturnValueLength<int>() };
- yield return new[] { CodeSnippets.GenericCollectionWithCustomElementMarshalling };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.DefaultMarshallerParametersAndModifiers<byte>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.DefaultMarshallerParametersAndModifiers<sbyte>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.DefaultMarshallerParametersAndModifiers<short>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.DefaultMarshallerParametersAndModifiers<ushort>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.DefaultMarshallerParametersAndModifiers<int>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.DefaultMarshallerParametersAndModifiers<uint>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.DefaultMarshallerParametersAndModifiers<long>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.DefaultMarshallerParametersAndModifiers<ulong>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.DefaultMarshallerParametersAndModifiers<float>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.DefaultMarshallerParametersAndModifiers<double>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.DefaultMarshallerParametersAndModifiers<IntPtr>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.DefaultMarshallerParametersAndModifiers<UIntPtr>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.CustomMarshallerParametersAndModifiers<byte>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.CustomMarshallerParametersAndModifiers<sbyte>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.CustomMarshallerParametersAndModifiers<short>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.CustomMarshallerParametersAndModifiers<ushort>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.CustomMarshallerParametersAndModifiers<int>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.CustomMarshallerParametersAndModifiers<uint>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.CustomMarshallerParametersAndModifiers<long>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.CustomMarshallerParametersAndModifiers<ulong>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.CustomMarshallerParametersAndModifiers<float>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.CustomMarshallerParametersAndModifiers<double>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.CustomMarshallerParametersAndModifiers<IntPtr>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.CustomMarshallerParametersAndModifiers<UIntPtr>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.CustomMarshallerReturnValueLength<int>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.NativeToManagedOnlyOutParameter<int>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.NativeToManagedOnlyReturnValue<int>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling.Stateless.NestedMarshallerParametersAndModifiers<int>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.DefaultMarshallerParametersAndModifiers<byte>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.DefaultMarshallerParametersAndModifiers<sbyte>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.DefaultMarshallerParametersAndModifiers<short>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.DefaultMarshallerParametersAndModifiers<ushort>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.DefaultMarshallerParametersAndModifiers<int>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.DefaultMarshallerParametersAndModifiers<uint>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.DefaultMarshallerParametersAndModifiers<long>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.DefaultMarshallerParametersAndModifiers<ulong>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.DefaultMarshallerParametersAndModifiers<float>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.DefaultMarshallerParametersAndModifiers<double>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.DefaultMarshallerParametersAndModifiers<IntPtr>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.DefaultMarshallerParametersAndModifiers<UIntPtr>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.CustomMarshallerParametersAndModifiers<byte>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.CustomMarshallerParametersAndModifiers<sbyte>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.CustomMarshallerParametersAndModifiers<short>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.CustomMarshallerParametersAndModifiers<ushort>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.CustomMarshallerParametersAndModifiers<int>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.CustomMarshallerParametersAndModifiers<uint>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.CustomMarshallerParametersAndModifiers<long>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.CustomMarshallerParametersAndModifiers<ulong>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.CustomMarshallerParametersAndModifiers<float>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.CustomMarshallerParametersAndModifiers<double>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.CustomMarshallerParametersAndModifiers<IntPtr>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.CustomMarshallerParametersAndModifiers<UIntPtr>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.CustomMarshallerReturnValueLength<int>() };
+ yield return new[] { CodeSnippets.CustomCollectionMarshalling_V1.GenericCollectionWithCustomElementMarshalling };
yield return new[] { CodeSnippets.CollectionsOfCollectionsStress };
}
[Theory]
[MemberData(nameof(CodeSnippetsToCompile))]
+ [MemberData(nameof(CustomCollections))]
public async Task ValidateSnippets(string source)
{
Compilation comp = await TestUtils.CreateCompilation(source);
@@ -301,7 +357,6 @@ namespace LibraryImportGenerator.UnitTests
yield return new object[] { CodeSnippets.PreprocessorIfAfterAttributeAroundFunctionAdditionalFunctionAfter("Foo"), new string[] { "Foo" } };
yield return new object[] { CodeSnippets.PreprocessorIfAfterAttributeAroundFunctionAdditionalFunctionAfter("Foo"), Array.Empty<string>() };
}
-
[Theory]
[MemberData(nameof(CodeSnippetsToCompileWithPreprocessorSymbols))]
public async Task ValidateSnippetsWithPreprocessorDefintions(string source, IEnumerable<string> preprocessorSymbols)
diff --git a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.V1.cs b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.V1.cs
index 7f8d5cc0f72..78b8d1bda02 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.V1.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.V1.cs
@@ -144,24 +144,24 @@ namespace SharedTypes
}
[CustomTypeMarshaller(typeof(List<>), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.TwoStageMarshalling | CustomTypeMarshallerFeatures.CallerAllocatedBuffer, BufferSize = 0x200)]
- public unsafe ref struct ListMarshaller<T>
+ public unsafe ref struct ListMarshaller_V1<T>
{
private List<T> managedList;
private readonly int sizeOfNativeElement;
private IntPtr allocatedMemory;
- public ListMarshaller(int sizeOfNativeElement)
+ public ListMarshaller_V1(int sizeOfNativeElement)
: this()
{
this.sizeOfNativeElement = sizeOfNativeElement;
}
- public ListMarshaller(List<T> managed, int sizeOfNativeElement)
+ public ListMarshaller_V1(List<T> managed, int sizeOfNativeElement)
:this(managed, Span<byte>.Empty, sizeOfNativeElement)
{
}
- public ListMarshaller(List<T> managed, Span<byte> stackSpace, int sizeOfNativeElement)
+ public ListMarshaller_V1(List<T> managed, Span<byte> stackSpace, int sizeOfNativeElement)
{
allocatedMemory = default;
this.sizeOfNativeElement = sizeOfNativeElement;
@@ -228,10 +228,10 @@ namespace SharedTypes
}
}
- [NativeMarshalling(typeof(WrappedListMarshaller<>))]
- public struct WrappedList<T>
+ [NativeMarshalling(typeof(WrappedListMarshaller_V1<>))]
+ public struct WrappedList_V1<T>
{
- public WrappedList(List<T> list)
+ public WrappedList_V1(List<T> list)
{
Wrapped = list;
}
@@ -241,25 +241,25 @@ namespace SharedTypes
public ref T GetPinnableReference() => ref CollectionsMarshal.AsSpan(Wrapped).GetPinnableReference();
}
- [CustomTypeMarshaller(typeof(WrappedList<>), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.TwoStageMarshalling | CustomTypeMarshallerFeatures.CallerAllocatedBuffer, BufferSize = 0x200)]
- public unsafe ref struct WrappedListMarshaller<T>
+ [CustomTypeMarshaller(typeof(WrappedList_V1<>), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.TwoStageMarshalling | CustomTypeMarshallerFeatures.CallerAllocatedBuffer, BufferSize = 0x200)]
+ public unsafe ref struct WrappedListMarshaller_V1<T>
{
- private ListMarshaller<T> _marshaller;
+ private ListMarshaller_V1<T> _marshaller;
- public WrappedListMarshaller(int sizeOfNativeElement)
+ public WrappedListMarshaller_V1(int sizeOfNativeElement)
: this()
{
- this._marshaller = new ListMarshaller<T>(sizeOfNativeElement);
+ this._marshaller = new ListMarshaller_V1<T>(sizeOfNativeElement);
}
- public WrappedListMarshaller(WrappedList<T> managed, int sizeOfNativeElement)
+ public WrappedListMarshaller_V1(WrappedList_V1<T> managed, int sizeOfNativeElement)
: this(managed, Span<byte>.Empty, sizeOfNativeElement)
{
}
- public WrappedListMarshaller(WrappedList<T> managed, Span<byte> stackSpace, int sizeOfNativeElement)
+ public WrappedListMarshaller_V1(WrappedList_V1<T> managed, Span<byte> stackSpace, int sizeOfNativeElement)
{
- this._marshaller = new ListMarshaller<T>(managed.Wrapped, stackSpace, sizeOfNativeElement);
+ this._marshaller = new ListMarshaller_V1<T>(managed.Wrapped, stackSpace, sizeOfNativeElement);
}
public ReadOnlySpan<T> GetManagedValuesSource() => _marshaller.GetManagedValuesSource();
@@ -276,7 +276,7 @@ namespace SharedTypes
public void FromNativeValue(byte* value) => _marshaller.FromNativeValue(value);
- public WrappedList<T> ToManaged() => new(_marshaller.ToManaged());
+ public WrappedList_V1<T> ToManaged() => new(_marshaller.ToManaged());
public void FreeNative() => _marshaller.FreeNative();
}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.cs b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.cs
index f9f34a6e4de..b01337b9973 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.cs
@@ -166,7 +166,6 @@ namespace SharedTypes
}
}
-
[CustomMarshaller(typeof(IntWrapper), Scenario.Default, typeof(Marshaller))]
public static unsafe class IntWrapperMarshallerStateful
{
@@ -282,4 +281,92 @@ namespace SharedTypes
}
}
}
+
+ [CustomMarshaller(typeof(List<>), Scenario.Default, typeof(ListMarshaller<,>))]
+ public unsafe static class ListMarshaller<T, [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged
+ {
+ public static byte* AllocateContainerForUnmanagedElements(List<T> managed, out int numElements)
+ => AllocateContainerForUnmanagedElements(managed, Span<byte>.Empty, out numElements);
+
+ public static byte* AllocateContainerForUnmanagedElements(List<T> managed, Span<byte> buffer, out int numElements)
+ {
+ if (managed is null)
+ {
+ numElements = 0;
+ return null;
+ }
+
+ numElements = managed.Count;
+
+ // Always allocate at least one byte when the list is zero-length.
+ int spaceToAllocate = Math.Max(checked(sizeof(TUnmanagedElement) * numElements), 1);
+ if (spaceToAllocate <= buffer.Length)
+ {
+ return (byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(buffer));
+ }
+ else
+ {
+ return (byte*)Marshal.AllocCoTaskMem(spaceToAllocate);
+ }
+ }
+
+ public static ReadOnlySpan<T> GetManagedValuesSource(List<T> managed)
+ => CollectionsMarshal.AsSpan(managed);
+
+ public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(byte* unmanaged, int numElements)
+ => new Span<TUnmanagedElement>(unmanaged, numElements);
+
+ public static List<T> AllocateContainerForManagedElements(byte* unmanaged, int length)
+ {
+ if (unmanaged is null)
+ return null;
+
+ var list = new List<T>(length);
+ for (int i = 0; i < length; i++)
+ {
+ list.Add(default);
+ }
+
+ return list;
+ }
+
+ public static Span<T> GetManagedValuesDestination(List<T> managed)
+ => CollectionsMarshal.AsSpan(managed);
+
+ public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(byte* nativeValue, int numElements)
+ => new ReadOnlySpan<TUnmanagedElement>(nativeValue, numElements);
+
+ public static void Free(byte* unmanaged)
+ => Marshal.FreeCoTaskMem((IntPtr)unmanaged);
+ }
+
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), Scenario.Default, typeof(CustomArrayMarshaller<,>))]
+ public unsafe static class CustomArrayMarshaller<T, [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged
+ {
+ public static byte* AllocateContainerForUnmanagedElements(T[]? managed, out int numElements)
+ {
+ if (managed is null)
+ {
+ numElements = 0;
+ return null;
+ }
+
+ numElements = managed.Length;
+ return (byte*)Marshal.AllocCoTaskMem(checked(sizeof(TUnmanagedElement) * numElements));
+ }
+
+ public static ReadOnlySpan<T> GetManagedValuesSource(T[] managed) => managed;
+
+ public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(byte* unmanaged, int numElements)
+ => new Span<TUnmanagedElement>(unmanaged, numElements);
+
+ public static T[] AllocateContainerForManagedElements(byte* unmanaged, int length) => unmanaged is null ? null : new T[length];
+
+ public static Span<T> GetManagedValuesDestination(T[] managed) => managed;
+
+ public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(byte* unmanaged, int numElements)
+ => new Span<TUnmanagedElement>(unmanaged, numElements);
+
+ public static void Free(byte* unmanaged) => Marshal.FreeCoTaskMem((IntPtr)unmanaged);
+ }
}