Skip to content

Commit

Permalink
Fix AOT build (#2747)
Browse files Browse the repository at this point in the history
* Fix AOT build

* Add TargetType

* Make Enums AOT ready

* use new serializer in tests

* add some missing enums
  • Loading branch information
kblok authored Aug 20, 2024
1 parent 4a007ae commit bdd47e2
Show file tree
Hide file tree
Showing 40 changed files with 164 additions and 52 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/demo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ jobs:
run: |
dotnet run --project PuppeteerSharpPdfDemo-Local.csproj auto-exit -f net8.0
- name: Run with AOT
if: matrix.os == 'macos-latest'
if: matrix.os == 'windows-2022'
working-directory: ./demos/PuppeteerSharpPdfDemo
run: |
dotnet run --project PuppeteerSharpPdfDemo-Local.csproj -r osx-arm64 -c Release -f net8.0 auto-exit
dotnet publish PuppeteerSharpPdfDemo-Local.csproj -r win-x64 -o build -f net8.0
build/PuppeteerSharpPdfDemo-Local.exe auto-exit
- name: Run on .NET Framework
if: matrix.os == 'windows-2022'
working-directory: ./demos/PuppeteerSharpPdfDemo
Expand Down
8 changes: 2 additions & 6 deletions lib/PuppeteerSharp.Nunit/PuppeteerTestAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,13 +172,9 @@ private static TestExpectation[] GetUpstreamExpectations() =>
_upstreamExpectations ??= LoadExpectationsFromResource("PuppeteerSharp.Nunit.TestExpectations.TestExpectations.upstream.json");

private static readonly JsonSerializerOptions DefaultJsonSerializerOptions =
new JsonSerializerOptions()
new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
Converters =
{
new JsonStringEnumMemberConverter(),
},
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};

private static TestExpectation[] LoadExpectationsFromResource(string resourceName)
Expand Down
5 changes: 5 additions & 0 deletions lib/PuppeteerSharp.Nunit/TestExpectations/TestExpectation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
// * SOFTWARE.

using System.Runtime.Serialization;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using PuppeteerSharp.Helpers.Json;

namespace PuppeteerSharp.Nunit.TestExpectations;

Expand Down Expand Up @@ -54,6 +56,7 @@ public Regex TestIdRegex

public TestExpectationResult[] Expectations { get; set; }

[JsonConverter(typeof(JsonStringEnumMemberConverter<TestExpectationResult>))]
public enum TestExpectationResult
{
[EnumMember(Value = "FAIL")] Fail,
Expand All @@ -62,6 +65,7 @@ public enum TestExpectationResult
[EnumMember(Value = "TIMEOUT")] Timeout,
}

[JsonConverter(typeof(JsonStringEnumMemberConverter<TestExpectationsParameter>))]
public enum TestExpectationsParameter
{
[EnumMember(Value = "firefox")]
Expand All @@ -80,6 +84,7 @@ public enum TestExpectationsParameter
Headful,
}

[JsonConverter(typeof(JsonStringEnumMemberConverter<TestExpectationPlatform>))]
public enum TestExpectationPlatform
{
[EnumMember(Value = "darwin")]
Expand Down
3 changes: 3 additions & 0 deletions lib/PuppeteerSharp/BrowserData/FirefoxChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,15 @@
// * SOFTWARE.

using System.Runtime.Serialization;
using System.Text.Json.Serialization;
using PuppeteerSharp.Helpers.Json;

namespace PuppeteerSharp.BrowserData;

/// <summary>
/// Firefox channels.
/// </summary>
[JsonConverter(typeof(JsonStringEnumMemberConverter<FirefoxChannel>))]
public enum FirefoxChannel
{
/// <summary>
Expand Down
3 changes: 3 additions & 0 deletions lib/PuppeteerSharp/Cdp/Messaging/DispatchKeyEventType.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
using System.Runtime.Serialization;
using System.Text.Json.Serialization;
using PuppeteerSharp.Helpers.Json;

namespace PuppeteerSharp.Cdp.Messaging
{
[JsonConverter(typeof(JsonStringEnumMemberConverter<DispatchKeyEventType>))]
internal enum DispatchKeyEventType
{
/// <summary>
Expand Down
3 changes: 3 additions & 0 deletions lib/PuppeteerSharp/Cdp/Messaging/DragEventType.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
using System.Runtime.Serialization;
using System.Text.Json.Serialization;
using PuppeteerSharp.Helpers.Json;

namespace PuppeteerSharp.Cdp.Messaging
{
[JsonConverter(typeof(JsonStringEnumMemberConverter<DragEventType>))]
internal enum DragEventType
{
/// <summary>
Expand Down
3 changes: 3 additions & 0 deletions lib/PuppeteerSharp/Cdp/Messaging/FileChooserAction.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
using System.Runtime.Serialization;
using System.Text.Json.Serialization;
using PuppeteerSharp.Helpers.Json;

namespace PuppeteerSharp.Cdp.Messaging
{
[JsonConverter(typeof(JsonStringEnumMemberConverter<FileChooserAction>))]
internal enum FileChooserAction
{
/// <summary>
Expand Down
4 changes: 4 additions & 0 deletions lib/PuppeteerSharp/Cdp/Messaging/LogSource.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
using System.Text.Json.Serialization;
using PuppeteerSharp.Helpers.Json;

namespace PuppeteerSharp.Cdp.Messaging;

[JsonConverter(typeof(JsonStringEnumMemberConverter<LogSource>))]
internal enum LogSource
{
Xml = 0,
Expand Down
3 changes: 3 additions & 0 deletions lib/PuppeteerSharp/Cdp/Messaging/MouseEventType.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
using System.Runtime.Serialization;
using System.Text.Json.Serialization;
using PuppeteerSharp.Helpers.Json;

namespace PuppeteerSharp.Cdp.Messaging
{
[JsonConverter(typeof(JsonStringEnumMemberConverter<MouseEventType>))]
internal enum MouseEventType
{
/// <summary>
Expand Down
4 changes: 4 additions & 0 deletions lib/PuppeteerSharp/Cdp/Messaging/NavigationType.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
using System.Text.Json.Serialization;
using PuppeteerSharp.Helpers.Json;

namespace PuppeteerSharp.Cdp.Messaging;

/// <summary>
/// Navigation types.
/// </summary>
[JsonConverter(typeof(JsonStringEnumMemberConverter<NavigationType>))]
public enum NavigationType
{
/// <summary>
Expand Down
4 changes: 4 additions & 0 deletions lib/PuppeteerSharp/Cdp/Messaging/PageFrameDetachedResponse.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
using System.Text.Json.Serialization;
using PuppeteerSharp.Helpers.Json;

namespace PuppeteerSharp.Cdp.Messaging
{
[JsonConverter(typeof(JsonStringEnumMemberConverter<FrameDetachedReason>))]
internal enum FrameDetachedReason
{
/// <summary>
Expand Down
2 changes: 2 additions & 0 deletions lib/PuppeteerSharp/Cdp/Messaging/RemoteObjectSubtype.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using System.Text.Json.Serialization;
using PuppeteerSharp.Helpers.Json;

namespace PuppeteerSharp.Cdp.Messaging
{
/// <summary>
/// Remote object subtype.
/// </summary>
[JsonConverter(typeof(JsonStringEnumMemberConverter<RemoteObjectSubtype>))]
[DefaultEnumValue((int)Other)]
public enum RemoteObjectSubtype
{
Expand Down
2 changes: 2 additions & 0 deletions lib/PuppeteerSharp/Cdp/Messaging/RemoteObjectType.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using System.Text.Json.Serialization;
using PuppeteerSharp.Helpers.Json;

namespace PuppeteerSharp.Cdp.Messaging
{
/// <summary>
/// Remote object type.
/// </summary>
[JsonConverter(typeof(JsonStringEnumMemberConverter<RemoteObjectType>))]
[DefaultEnumValue((int)Other)]
public enum RemoteObjectType
{
Expand Down
3 changes: 3 additions & 0 deletions lib/PuppeteerSharp/ConsoleType.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
using System.Runtime.Serialization;
using System.Text.Json.Serialization;
using PuppeteerSharp.Helpers.Json;

namespace PuppeteerSharp
{
/// <summary>
/// Console type used on <see cref="ConsoleMessage"/>.
/// </summary>
[JsonConverter(typeof(JsonStringEnumMemberConverter<ConsoleType>))]
public enum ConsoleType
{
/// <summary>
Expand Down
4 changes: 4 additions & 0 deletions lib/PuppeteerSharp/CookiePriority.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,15 @@
// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// * SOFTWARE.

using System.Text.Json.Serialization;
using PuppeteerSharp.Helpers.Json;

namespace PuppeteerSharp;

/// <summary>
/// Represents the cookie's 'Priority' status.
/// </summary>
[JsonConverter(typeof(JsonStringEnumMemberConverter<CookiePriority>))]
public enum CookiePriority
{
/// <summary>
Expand Down
4 changes: 4 additions & 0 deletions lib/PuppeteerSharp/CookieSourceScheme.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,17 @@
// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// * SOFTWARE.

using System.Text.Json.Serialization;
using PuppeteerSharp.Helpers.Json;

namespace PuppeteerSharp;

/// <summary>
/// Represents the source scheme of the origin that originally set the cookie. A value of
/// "Unset" allows protocol clients to emulate legacy cookie scope for the scheme.
/// This is a temporary ability and it will be removed in the future.
/// </summary>
[JsonConverter(typeof(JsonStringEnumMemberConverter<CookieSourceScheme>))]
public enum CookieSourceScheme
{
/// <summary>
Expand Down
2 changes: 2 additions & 0 deletions lib/PuppeteerSharp/DOMWorldType.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System.Runtime.Serialization;
using System.Text.Json.Serialization;
using PuppeteerSharp.Helpers.Json;

namespace PuppeteerSharp
{
[JsonConverter(typeof(JsonStringEnumMemberConverter<DOMWorldType>))]
[DefaultEnumValue((int)Other)]
internal enum DOMWorldType
{
Expand Down
3 changes: 3 additions & 0 deletions lib/PuppeteerSharp/DialogType.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
using System.Runtime.Serialization;
using System.Text.Json.Serialization;
using PuppeteerSharp.Helpers.Json;

namespace PuppeteerSharp
{
/// <summary>
/// Dialog type.
/// </summary>
/// <seealso cref="Dialog"/>
[JsonConverter(typeof(JsonStringEnumMemberConverter<DialogType>))]
public enum DialogType
{
/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion lib/PuppeteerSharp/Helpers/Json/JsonHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ internal static class JsonHelper
#endif
Converters =
{
new HttpMethodConverter(), new JSHandleConverter(), new JsonStringEnumMemberConverter(),
new HttpMethodConverter(), new JSHandleConverter(),
},
};
});
Expand Down
81 changes: 42 additions & 39 deletions lib/PuppeteerSharp/Helpers/Json/JsonStringEnumMemberConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*/

using System;
using System.Collections.Concurrent;
using System.Text.Json;
using System.Text.Json.Serialization;

Expand All @@ -31,26 +32,28 @@ namespace PuppeteerSharp.Helpers.Json;
/// <summary>
/// Converts an enum value to or from a JSON string.
/// </summary>
internal sealed class JsonStringEnumMemberConverter : JsonConverterFactory
/// <typeparam name="TEnum">The enum type.</typeparam>
internal class JsonStringEnumMemberConverter<TEnum> : JsonConverterFactory
where TEnum : struct, Enum
{
/// <inheritdoc />
public override bool CanConvert(Type typeToConvert)
=> (typeToConvert.IsEnum || Nullable.GetUnderlyingType(typeToConvert)?.IsEnum == true) &&
!Attribute.IsDefined(typeToConvert, typeof(JsonStringIgnoreAttribute));
private static readonly ConcurrentDictionary<Type, JsonConverter> _jsonConverterCache = new();

/// <inheritdoc />
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
public static JsonConverter CreateJsonConverter()
{
var nullableType = Nullable.GetUnderlyingType(typeToConvert);

return (JsonConverter)Activator.CreateInstance(
nullableType == null ?
typeof(EnumMemberConverter<>).MakeGenericType(typeToConvert) :
typeof(NullableEnumMemberConverter<>).MakeGenericType(nullableType));
var nullableType = Nullable.GetUnderlyingType(typeof(TEnum));
JsonConverter jsonConverter = nullableType == null ? new EnumMemberConverter<TEnum>() : new NullableEnumMemberConverter<TEnum>();
_jsonConverterCache.TryAdd(typeof(TEnum), jsonConverter);
return jsonConverter;
}

private static TEnum? Read<TEnum>(ref Utf8JsonReader reader)
where TEnum : struct, Enum
public override bool CanConvert(Type typeToConvert)
=> typeToConvert.IsEnum || Nullable.GetUnderlyingType(typeToConvert)?.IsEnum == true;

public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
=> _jsonConverterCache.TryGetValue(typeToConvert, out var jsonConverter) ? jsonConverter : CreateJsonConverter();

private static T? Read<T>(ref Utf8JsonReader reader)
where T : struct, Enum
{
if (reader.TokenType == JsonTokenType.Null)
{
Expand All @@ -59,31 +62,31 @@ public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializer

if (reader.TokenType == JsonTokenType.String)
{
return EnumHelper.FromValueString<TEnum>(reader.GetString());
return EnumHelper.FromValueString<T>(reader.GetString());
}

if (reader.TokenType == JsonTokenType.Number)
{
var enumTypeCode = Type.GetTypeCode(typeof(TEnum));
var enumTypeCode = Type.GetTypeCode(typeof(T));
return enumTypeCode switch
{
TypeCode.Int32 => (TEnum)(object)reader.GetInt32(),
TypeCode.Int64 => (TEnum)(object)reader.GetInt64(),
TypeCode.Int16 => (TEnum)(object)reader.GetInt16(),
TypeCode.Byte => (TEnum)(object)reader.GetByte(),
TypeCode.UInt32 => (TEnum)(object)reader.GetUInt32(),
TypeCode.UInt64 => (TEnum)(object)reader.GetUInt64(),
TypeCode.UInt16 => (TEnum)(object)reader.GetUInt16(),
TypeCode.SByte => (TEnum)(object)reader.GetSByte(),
TypeCode.Int32 => (T)(object)reader.GetInt32(),
TypeCode.Int64 => (T)(object)reader.GetInt64(),
TypeCode.Int16 => (T)(object)reader.GetInt16(),
TypeCode.Byte => (T)(object)reader.GetByte(),
TypeCode.UInt32 => (T)(object)reader.GetUInt32(),
TypeCode.UInt64 => (T)(object)reader.GetUInt64(),
TypeCode.UInt16 => (T)(object)reader.GetUInt16(),
TypeCode.SByte => (T)(object)reader.GetSByte(),
_ => throw new JsonException($"Enum '{typeof(TEnum).Name}' of {enumTypeCode} type is not supported."),
};
}

throw new JsonException();
}

private static void Write<TEnum>(Utf8JsonWriter writer, TEnum? value)
where TEnum : struct, Enum
private static void Write<T>(Utf8JsonWriter writer, T? value)
where T : struct, Enum
{
if (value.HasValue)
{
Expand All @@ -95,23 +98,23 @@ private static void Write<TEnum>(Utf8JsonWriter writer, TEnum? value)
}
}

private class EnumMemberConverter<TEnum> : JsonConverter<TEnum>
where TEnum : struct, Enum
private class EnumMemberConverter<T> : JsonConverter<T>
where T : struct, Enum
{
public override TEnum Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> Read<TEnum>(ref reader) ?? default;
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> Read<T>(ref reader) ?? default;

public override void Write(Utf8JsonWriter writer, TEnum value, JsonSerializerOptions options)
=> Write<TEnum>(writer, value);
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
=> Write<T>(writer, value);
}

private class NullableEnumMemberConverter<TEnum> : JsonConverter<TEnum?>
where TEnum : struct, Enum
private class NullableEnumMemberConverter<T> : JsonConverter<T?>
where T : struct, Enum
{
public override TEnum? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> Read<TEnum>(ref reader);
public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> Read<T>(ref reader);

public override void Write(Utf8JsonWriter writer, TEnum? value, JsonSerializerOptions options)
=> Write<TEnum>(writer, value);
public override void Write(Utf8JsonWriter writer, T? value, JsonSerializerOptions options)
=> Write<T>(writer, value);
}
}
Loading

0 comments on commit bdd47e2

Please sign in to comment.