Skip to content

Commit

Permalink
Added TaskCompletionSource support
Browse files Browse the repository at this point in the history
  • Loading branch information
Aragas committed Feb 23, 2025
1 parent 8eaf833 commit b0452f5
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 31 deletions.
20 changes: 10 additions & 10 deletions src/BUTR.NativeAOT.Shared/Common.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public unsafe interface IReturnValueWithValue<TSelf, in TValue>
public unsafe interface IReturnValueWithValueJson<TSelf>
where TSelf : unmanaged, IReturnValueWithValueJson<TSelf>
{
static abstract TSelf* AsValue<TValue>(TValue value, JsonTypeInfo<TValue> jsonTypeInfo, bool isOwner) where TValue: class;
static abstract TSelf* AsValue<TValue>(TValue value, JsonTypeInfo<TValue> jsonTypeInfo, bool isOwner) where TValue : class;
}
public unsafe interface IReturnValueWithValueLength<TSelf, TValue>
where TSelf : unmanaged, IReturnValueWithValueLength<TSelf, TValue>
Expand Down Expand Up @@ -145,9 +145,9 @@ public param_bool() { }
private param_bool(bool value) => Value = (byte) (value ? 1 : 0);

public string ToString(string? format, IFormatProvider? formatProvider) => Value.ToString(format, formatProvider);
public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider) =>
public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider) =>
Value.TryFormat(destination, out charsWritten, format, provider);
public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, ReadOnlySpan<char> format, IFormatProvider? provider) =>
public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, ReadOnlySpan<char> format, IFormatProvider? provider) =>
Value.TryFormat(utf8Destination, out bytesWritten, format, provider);
}

Expand All @@ -172,9 +172,9 @@ public param_int() { }
private param_int(int value) => Value = value;

public string ToString(string? format, IFormatProvider? formatProvider) => Value.ToString(format, formatProvider);
public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider) =>
public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider) =>
Value.TryFormat(destination, out charsWritten, format, provider);
public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, ReadOnlySpan<char> format, IFormatProvider? provider) =>
public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, ReadOnlySpan<char> format, IFormatProvider? provider) =>
Value.TryFormat(utf8Destination, out bytesWritten, format, provider);
}

Expand All @@ -199,9 +199,9 @@ public param_uint() { }
private param_uint(uint value) => Value = value;

public string ToString(string? format, IFormatProvider? formatProvider) => Value.ToString(format, formatProvider);
public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider) =>
public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider) =>
Value.TryFormat(destination, out charsWritten, format, provider);
public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, ReadOnlySpan<char> format, IFormatProvider? provider) =>
public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, ReadOnlySpan<char> format, IFormatProvider? provider) =>
Value.TryFormat(utf8Destination, out bytesWritten, format, provider);
}

Expand Down Expand Up @@ -247,7 +247,7 @@ public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, ReadOnly
public static char* ToRawPtr(param_json* ptr) => (char*) ptr;

public readonly char* Value;

public string ToString(string? format, IFormatProvider? formatProvider) => $"[{new IntPtr(Value):x16}]: {ToSpan(this).ToString()}";
}

Expand All @@ -273,7 +273,7 @@ public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, ReadOnly
public static byte* ToRawPtr(param_data* ptr) => (byte*) ptr;

public readonly byte* Value;

public string ToString(string? format, IFormatProvider? formatProvider) => $"[{new IntPtr(Value):x16}]";
}

Expand Down Expand Up @@ -346,7 +346,7 @@ private return_value_string(char* value, char* error)
IReturnValueWithError<return_value_json>,
IReturnValueWithException<return_value_json>
{
public static return_value_json* AsValue<TValue>(TValue value, JsonTypeInfo<TValue> jsonTypeInfo, bool isOwner) where TValue: class => AsValue(Utils.SerializeJsonCopy(value, jsonTypeInfo, isOwner), isOwner);
public static return_value_json* AsValue<TValue>(TValue value, JsonTypeInfo<TValue> jsonTypeInfo, bool isOwner) where TValue : class => AsValue(Utils.SerializeJsonCopy(value, jsonTypeInfo, isOwner), isOwner);
public static return_value_json* AsValue(char* value, bool isOwner) => Utils.Create(new return_value_json(value, null), isOwner);
public static return_value_json* AsError(char* error, bool isOwner) => Utils.Create(new return_value_json(null, error), isOwner);
public static return_value_json* AsException(Exception e, bool isOwner) => Utils.AsException<return_value_json>(e, isOwner);
Expand Down
189 changes: 173 additions & 16 deletions src/BUTR.NativeAOT.Shared/SafeStructMallocHandle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ namespace BUTR.NativeAOT.Shared
using global::System;
using global::System.Runtime.CompilerServices;
using global::System.Text.Json.Serialization.Metadata;
using global::System.Threading.Tasks;

internal unsafe class SafeStructMallocHandle : SafeHandleZeroOrMinusOneIsInvalid
{
Expand Down Expand Up @@ -96,20 +97,6 @@ public SafeStringMallocHandle ValueAsString()
throw new NativeCallException(new string(hError));
}

public SafeStringMallocHandle ValueAsJson<TValue>()
{
if (typeof(TStruct) != typeof(return_value_json))
throw new Exception();

var ptr = (return_value_json*) Value;
if (ptr->Error is null)
{
return new SafeStringMallocHandle(ptr->Value, IsOwner);
}

using var hError = new SafeStringMallocHandle(ptr->Error, IsOwner);
throw new NativeCallException(new string(hError));
}
public TValue? ValueAsJson<TValue>(JsonTypeInfo<TValue> jsonTypeInfo, [CallerMemberName] string? caller = null) where TValue : class
{
if (typeof(TStruct) != typeof(return_value_json))
Expand All @@ -136,11 +123,11 @@ public SafeDataMallocHandle ValueAsData()
{
return new SafeDataMallocHandle(ptr->Value, ptr->Length, IsOwner);
}

using var hError = new SafeStringMallocHandle(ptr->Error, IsOwner);
throw new NativeCallException(new string(hError));
}

public bool ValueAsBool()
{
if (typeof(TStruct) != typeof(return_value_bool))
Expand Down Expand Up @@ -200,6 +187,176 @@ public int ValueAsInt32()
using var hError = new SafeStringMallocHandle(ptr->Error, IsOwner);
throw new NativeCallException(new string(hError));
}


public void SetAsVoid(TaskCompletionSource<object?> tcs)
{
if (typeof(TStruct) != typeof(return_value_void))
{
tcs.TrySetException(new Exception());
return;
}

var ptr = (return_value_void*) Value;
if (ptr->Error is null)
{
tcs.TrySetResult(null);
return;
}

using var hError = new SafeStringMallocHandle(ptr->Error, IsOwner);
tcs.TrySetException(new NativeCallException(new string(hError)));
}

public void SetAsString(TaskCompletionSource<string?> tcs)
{
if (typeof(TStruct) != typeof(return_value_string))
{
tcs.TrySetException(new Exception());
return;
}

var ptr = (return_value_string*) Value;
if (ptr->Error is null)
{
if (ptr->Value is null)
{
tcs.TrySetResult(null);
}
else
{
using var hValue = new SafeStringMallocHandle(ptr->Value, IsOwner);
tcs.TrySetResult(hValue.ToString());
}
return;
}

using var hError = new SafeStringMallocHandle(ptr->Error, IsOwner);
tcs.TrySetException(new NativeCallException(new string(hError)));
}

public void SetAsJson<TValue>(TaskCompletionSource<TValue?> tcs, JsonTypeInfo<TValue> jsonTypeInfo, [CallerMemberName] string? caller = null) where TValue : class
{
if (typeof(TStruct) != typeof(return_value_json))
{
tcs.TrySetException(new Exception());
return;
}

var ptr = (return_value_json*) Value;
if (ptr->Error is null)
{
using var json = new SafeStringMallocHandle(ptr->Value, IsOwner);
tcs.TrySetResult(Utils.DeserializeJson(json, jsonTypeInfo, caller));
return;
}

using var hError = new SafeStringMallocHandle(ptr->Error, IsOwner);
tcs.TrySetException(new NativeCallException(new string(hError)));
}

public void SetAsData(TaskCompletionSource<byte[]?> tcs)
{
if (typeof(TStruct) != typeof(return_value_data))
{
tcs.TrySetException(new Exception());
return;
}

var ptr = (return_value_data*) Value;
if (ptr->Error is null)
{
if (ptr->Value is null)
{
tcs.TrySetResult(null);
}
else
{
using var hValue = new SafeDataMallocHandle(ptr->Value, ptr->Length, IsOwner);
tcs.TrySetResult(hValue.ToSpan().ToArray());
}
return;
}

using var hError = new SafeStringMallocHandle(ptr->Error, IsOwner);
tcs.TrySetException(new NativeCallException(new string(hError)));
}

public void SetAsBool(TaskCompletionSource<bool> tcs)
{
if (typeof(TStruct) != typeof(return_value_bool))
{
tcs.TrySetException(new Exception());
return;
}

var ptr = (return_value_bool*) Value;
if (ptr->Error is null)
{
tcs.TrySetResult(ptr->Value == 1);
return;
}

using var hError = new SafeStringMallocHandle(ptr->Error, IsOwner);
tcs.TrySetException(new NativeCallException(new string(hError)));
}

public void SetAsUInt32(TaskCompletionSource<uint> tcs)
{
if (typeof(TStruct) != typeof(return_value_uint32))
{
tcs.TrySetException(new Exception());
return;
}

var ptr = (return_value_uint32*) Value;
if (ptr->Error is null)
{
tcs.TrySetResult(ptr->Value);
return;
}

using var hError = new SafeStringMallocHandle(ptr->Error, IsOwner);
tcs.TrySetException(new NativeCallException(new string(hError)));
}

public void SetAsInt32(TaskCompletionSource<int> tcs)
{
if (typeof(TStruct) != typeof(return_value_int32))
{
tcs.TrySetException(new Exception());
return;
}

var ptr = (return_value_int32*) Value;
if (ptr->Error is null)
{
tcs.TrySetResult(ptr->Value);
return;
}

using var hError = new SafeStringMallocHandle(ptr->Error, IsOwner);
tcs.TrySetException(new NativeCallException(new string(hError)));
}

public void SetAsPointer(TaskCompletionSource<IntPtr> tcs)
{
if (typeof(TStruct) != typeof(return_value_ptr))
{
tcs.TrySetException(new Exception());
return;
}

var ptr = (return_value_ptr*) Value;
if (ptr->Error is null)
{
tcs.TrySetResult(new(ptr->Value));
return;
}

using var hError = new SafeStringMallocHandle(ptr->Error, IsOwner);
tcs.TrySetException(new NativeCallException(new string(hError)));
}
}
}
#nullable restore
Expand Down
10 changes: 5 additions & 5 deletions src/BUTR.NativeAOT.Shared/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,17 @@ internal static class Utils
where TSelf : unmanaged, IReturnValueWithError<TSelf> => TSelf.AsError(Copy(e.ToString(), isOwner), isOwner);

public static SafeStringMallocHandle SerializeJsonCopy<TValue>(TValue value, JsonTypeInfo<TValue> jsonTypeInfo, bool isOwner)
where TValue: class => Copy(SerializeJson(value, jsonTypeInfo), isOwner);
where TValue : class => Copy(SerializeJson(value, jsonTypeInfo), isOwner);

public static string SerializeJson<TValue>(TValue? value, JsonTypeInfo<TValue> jsonTypeInfo)
where TValue: class => value is null ? string.Empty : JsonSerializer.Serialize(value, jsonTypeInfo);
where TValue : class => value is null ? string.Empty : JsonSerializer.Serialize(value, jsonTypeInfo);

public static TValue? DeserializeJson<TValue>(SafeStringMallocHandle json, JsonTypeInfo<TValue> jsonTypeInfo, [CallerMemberName] string? caller = null)
where TValue: class => json.IsInvalid ? null : DeserializeJson(json.ToSpan(), jsonTypeInfo, caller);
where TValue : class => json.IsInvalid ? null : DeserializeJson(json.ToSpan(), jsonTypeInfo, caller);

[return: NotNullIfNotNull(nameof(json))]
public static unsafe TValue? DeserializeJson<TValue>(param_json* json, JsonTypeInfo<TValue> jsonTypeInfo, [CallerMemberName] string? caller = null)
where TValue: class => json is null ? null : DeserializeJson(param_json.ToSpan(json), jsonTypeInfo, caller);
where TValue : class => json is null ? null : DeserializeJson(param_json.ToSpan(json), jsonTypeInfo, caller);

private static TValue? DeserializeJson<TValue>([StringSyntax(StringSyntaxAttribute.Json)] ReadOnlySpan<char> json, JsonTypeInfo<TValue> jsonTypeInfo, [CallerMemberName] string? caller = null)
{
Expand All @@ -73,7 +73,7 @@ public static unsafe SafeDataMallocHandle Copy(in ReadOnlySpan<byte> data, bool
data.CopyTo(new Span<byte>(dst, data.Length));
return new(dst, data.Length, isOwner);
}

public static unsafe SafeStringMallocHandle Copy(in ReadOnlySpan<char> str, bool isOwner)
{
var size = (uint) ((str.Length + 1) * 2);
Expand Down

0 comments on commit b0452f5

Please sign in to comment.