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

[Swift language feature] Implement Swift.String wrapper in C# #2983

Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Swift;
using BindingsGeneration.Tests;
using Swift;
using Swift.Runtime;
using Swift.Runtime.InteropServices;
using Xunit;

using Bindings = Swift.RuntimeTests;


namespace BindingsGeneration.FunctionalTests
{
public class RuntimeTests : IClassFixture<RuntimeTests.TestFixture>
{
private readonly TestFixture _fixture;

public RuntimeTests(TestFixture fixture)
{
_fixture = fixture;
}

public class TestFixture
{
static TestFixture()
{
InitializeResources();
}

private static void InitializeResources()
{
// Initialize
}
}

[Fact]
public void SmokeTestArray()
{
var array = GetArray(3);
Assert.Equal(3, array.Count);
Assert.Equal(0, array[0]);
Assert.Equal(1, array[1]);
Assert.Equal(2, array[2]);
Assert.Equal(3, SumArray(array));
}

[Fact]
public void TestEmptyArray()
{
var array = GetArray(0);
Assert.Equal(0, array.Count);
Assert.Equal(0, SumArray(array));
}

[Fact]
public void TestOneElementArray()
{
var array = GetArray(1);
Assert.Equal(1, array.Count);
Assert.Equal(0, array[0]);
Assert.Equal(0, SumArray(array));
}

[Fact]
public void TestBigArray()
{
var array = GetArray(10000);
Assert.Equal(10000, array.Count);
var sum = 0;
for (int i = 0; i < 10000; i++)
{
Assert.Equal(i, array[i]);
sum += i;
}
Assert.Equal(sum, SumArray(array));
}

// TODO: Remove helper methods when https://github.com/dotnet/runtimelab/issues/2970
private static unsafe SwiftArray<int> GetArray(int count)
{
ArrayBuffer buffer = PInvoke_GetArray(count);
return SwiftMarshal.MarshalFromSwift<SwiftArray<int>>((SwiftHandle)new IntPtr(&buffer));
}

[UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })]
[DllImport("Runtime/libRuntimeTests.dylib", EntryPoint = "$s12RuntimeTests8getArray5countSays5Int32VGAE_tF")]
private static extern ArrayBuffer PInvoke_GetArray(int count);

private static unsafe int SumArray(SwiftArray<int> array)
{
ArrayBuffer buffer = new ArrayBuffer();
SwiftMarshal.MarshalToSwift<SwiftArray<int>>(array, new IntPtr(&buffer));
return PInvoke_SumArray(buffer);
}

[UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })]
[DllImport("Runtime/libRuntimeTests.dylib", EntryPoint = "$s12RuntimeTests8sumArray5arrays5Int32VSayAEG_tF")]
private static extern int PInvoke_SumArray(ArrayBuffer array);

[Fact]
public void SmokeTestSet()
{
var set = GetSet(3);
Assert.Equal(3, set.Count);
Assert.Equal(3, SumSet(set));
}

[Fact]
public void TestEmptySet()
{
var set = GetSet(0);
Assert.Equal(0, set.Count);
Assert.Equal(0, SumSet(set));
}

[Fact]
public void TestOneElementSet()
{
var set = GetSet(1);
Assert.Equal(1, set.Count);
Assert.Equal(0, SumSet(set));
}

[Fact]
public void TestBigSet()
{
var set = GetSet(10000);
Assert.Equal(10000, set.Count);
Assert.Equal(49995000, SumSet(set));

}

// TODO: Remove helper methods when https://github.com/dotnet/runtimelab/issues/2970
private static unsafe SwiftSet<SwiftIntMock> GetSet(int count)
{
Variant variant = PInvoke_GetSet(count);
return SwiftMarshal.MarshalFromSwift<SwiftSet<SwiftIntMock>>((SwiftHandle)new IntPtr(&variant));
}

private static unsafe int SumSet(SwiftSet<SwiftIntMock> set)
{
Variant variant = new Variant();
SwiftMarshal.MarshalToSwift<SwiftSet<SwiftIntMock>>(set, new IntPtr(&variant));
return PInvoke_SumSet(variant);
}

[UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })]
[DllImport("Runtime/libRuntimeTests.dylib", EntryPoint = "$s12RuntimeTests8getArray5countSays5Int32VGAE_tF")]
private static extern Variant PInvoke_GetSet(int count);

[UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })]
[DllImport("Runtime/libRuntimeTests.dylib", EntryPoint = "$s12RuntimeTests8sumArray5arrays5Int32VSayAEG_tF")]
private static extern int PInvoke_SumSet(Variant set);

[Fact]
public void SmokeTestString()
{
var str = Bindings.RuntimeTests.getString(3);
Assert.Equal(3, str.Length);
Assert.Equal("aaa", str.ToString());
}

[Fact]
public void TestEmptyString()
{
var str = Bindings.RuntimeTests.getString(0);
Assert.Equal(0, str.Length);
Assert.Equal(string.Empty, str.ToString());
Assert.Equal(str.Length, Bindings.RuntimeTests.verifyString(str));
}

[Fact]
public void TestOneElementString()
{
var str = Bindings.RuntimeTests.getString(1);
Assert.Equal(1, str.Length);
Assert.Equal("a", str.ToString());
Assert.Equal(str.Length, Bindings.RuntimeTests.verifyString(str));
}

[Fact]
public void TestBigString()
{
var str = Bindings.RuntimeTests.getString(10000);
Assert.Equal(10000, str.Length);
Assert.Equal(new string('a', 10000), str.ToString());
Assert.Equal(str.Length, Bindings.RuntimeTests.verifyString(str));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import Foundation

public func getArray(count: Int32) -> Array<Int32> {
var array = Array<Int32>()
for i in 0..<count {
array.append(i)
}
return array
}

public func sumArray(array: Array<Int32>) -> Int32
{
return array.reduce(0, +)
}

public func getString(count: Int32) -> String {
return String(repeating: "a", count: Int(count))
}

public func verifyString(str: String) -> Int32 {
let count = str.count
return str.allSatisfy { $0 == "a" } ? Int32(count) : -1
}

Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using Swift;
using Swift.Runtime;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,75 +323,5 @@ public async Task TestAsyncStruct()
stopwatch.Stop();
Assert.True(Math.Abs(stopwatch.Elapsed.TotalSeconds - seconds) <= 1);
}

[Fact]
public void TestSwiftArray()
{
var array = GetArray(42, 17);
Assert.Equal(2, array.Count);
Assert.Equal(42, array[0]);
Assert.Equal(17, array[1]);
int sum = SumArray(array);
Assert.Equal(42 + 17, sum);
}

// TODO: Remove helper methods when https://github.com/dotnet/runtimelab/issues/2970
private static unsafe SwiftArray<int> GetArray(int a, int b)
{
ArrayBuffer buffer = PInvoke_GetArray(a, b);
return SwiftMarshal.MarshalFromSwift<SwiftArray<int>>((SwiftHandle)new IntPtr(&buffer));
}

[UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })]
[DllImport("Structs/libStructsTests.dylib", EntryPoint = "$s12StructsTests8getArray1a1bSays5Int32VGAF_AFtF")]
private static extern ArrayBuffer PInvoke_GetArray(int a, int b);

private static unsafe int SumArray(SwiftArray<int> array)
{
ArrayBuffer buffer = new ArrayBuffer();
SwiftMarshal.MarshalToSwift<SwiftArray<int>>(array, new IntPtr(&buffer));
return PInvoke_SumArray(buffer);
}

[UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })]
[DllImport("Structs/libStructsTests.dylib", EntryPoint = "$s12StructsTests8sumArray5arrays5Int32VSayAEG_tF")]
private static extern int PInvoke_SumArray(ArrayBuffer array);

[Fact]
public void TestSwiftSet()
{
var set = GetSet(42, 17);
Assert.Equal(2, set.Count);
int sum = SumSet(set);
Assert.Equal(42 + 17, sum);

set = new SwiftSet<SwiftIntMock>();
sum = SumSet(set);
Assert.Equal(0, sum);
}

// TODO: Remove helper methods when https://github.com/dotnet/runtimelab/issues/2970
private static unsafe SwiftSet<SwiftIntMock> GetSet(int a, int b)
{
Variant variant = PInvoke_GetSet(a, b);
return SwiftMarshal.MarshalFromSwift<SwiftSet<SwiftIntMock>>((SwiftHandle)new IntPtr(&variant));
}

private static unsafe int SumSet(SwiftSet<SwiftIntMock> set)
{
Variant variant = new Variant();
SwiftMarshal.MarshalToSwift<SwiftSet<SwiftIntMock>>(set, new IntPtr(&variant));
return PInvoke_SumSet(variant);
}

[UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })]
[DllImport("Structs/libStructsTests.dylib", EntryPoint = "$s12StructsTests8getArray1a1bSays5Int32VGAF_AFtF")]
private static extern Variant PInvoke_GetSet(int a, int b);

[UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })]
[DllImport("Structs/libStructsTests.dylib", EntryPoint = "$s12StructsTests8sumArray5arrays5Int32VSayAEG_tF")]
private static extern int PInvoke_SumSet(Variant array);


}
}
Original file line number Diff line number Diff line change
Expand Up @@ -247,13 +247,3 @@ public struct TimerStruct {
try? await Task.sleep(nanoseconds: 5_000_000_000)
}
}

public func getArray(a: Int32, b: Int32) -> Array<Int32>
{
return [a, b]
}

public func sumArray(array: Array<Int32>) -> Int32
{
return array.reduce(0, +)
}
10 changes: 10 additions & 0 deletions src/Swift.Runtime/src/Swift/Data.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/// <summary>
/// Represents Foundation.Data type.
/// </summary>

// TODO: https://github.com/dotnet/runtimelab/issues/2992
public struct Data
{
private long _flags;
private IntPtr _object;
}
3 changes: 3 additions & 0 deletions src/Swift.Runtime/src/Swift/FoundationDatabase.xml
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,8 @@
<entity managedNameSpace="Swift" managedTypeName="UnsafeMutableBufferPointer&lt;System.Byte&gt;">
<typedeclaration kind="struct" name="UnsafeMutableBufferPointer&lt;Swift.UInt8&gt;" module="Swift" mangledName="sSr" frozen="true" blittable="true"/>
</entity>
<entity managedNameSpace="Swift" managedTypeName="SwiftString">
<typedeclaration kind="struct" name="String" module="Swift" mangledName="sSS" frozen="true" blittable="true"/>
</entity>
</entities>
</swifttypedatabase>
9 changes: 7 additions & 2 deletions src/Swift.Runtime/src/Swift/SwiftArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ public unsafe void Dispose()
{
if (_buffer.storage != IntPtr.Zero)
{
Arc.Release(*(IntPtr*)_buffer.storage);
// TODO: https://github.com/dotnet/runtimelab/issues/2851
Arc.Release(_buffer.storage);
_buffer.storage = IntPtr.Zero;
GC.SuppressFinalize(this);
}
Expand All @@ -75,7 +76,8 @@ public unsafe void Dispose()
{
if (_buffer.storage != IntPtr.Zero)
{
Arc.Release(*(IntPtr*)_buffer.storage);
// TODO: https://github.com/dotnet/runtimelab/issues/2851
Arc.Release(_buffer.storage);
_buffer.storage = IntPtr.Zero;
}
}
Expand Down Expand Up @@ -272,9 +274,11 @@ public unsafe Element this[int index]

internal static class SwiftArrayPInvokes
{
[UnmanagedCallConv(CallConvs = [typeof(CallConvSwift)])]
[DllImport(KnownLibraries.SwiftCore, EntryPoint = "$sSaMa")]
public static extern TypeMetadata PInvoke_getMetadata(TypeMetadataRequest request, TypeMetadata typeMetadata);

[UnmanagedCallConv(CallConvs = [typeof(CallConvSwift)])]
[DllImport(KnownLibraries.SwiftCore, EntryPoint = "$sS2ayxGycfC")]
public static extern ArrayBuffer Init(TypeMetadata typeMetadata);

Expand All @@ -286,6 +290,7 @@ internal static class SwiftArrayPInvokes
[DllImport(KnownLibraries.SwiftCore, EntryPoint = "$sSayxSicis")]
public static unsafe extern void Set(SwiftHandle value, nint index, TypeMetadata elementMetadata, SwiftSelf self);

[UnmanagedCallConv(CallConvs = [typeof(CallConvSwift)])]
[DllImport(KnownLibraries.SwiftCore, EntryPoint = "$sSa5countSivg")]
public static extern nint Count(ArrayBuffer handle, TypeMetadata elementMetadata);

Expand Down
Loading