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

feat: BebopSerializer, IIDecodable #335

Merged
merged 1 commit into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 5 additions & 15 deletions .github/workflows/build-runtime-cs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,19 @@ jobs:
uses: actions/setup-dotnet@v3
with:
dotnet-version: |
5.0.x
6.0.x
7.0.x
8.0.x
9.0.x
dotnet-quality: 'preview'
- name: Generate Output.g.cs
working-directory: "./Laboratory/C#"
run: dotnet run --project ../../Compiler/ --include $(ls -p ../Schemas/Valid/*.bop | tr '\n' ' ') build --generator "cs:./GeneratedTestCode/Output.g.cs,namespace=Bebop.Codegen"

- name: Run Test .NET 6
run: dotnet test -c Release -f net6.0
- name: Run Test .NET 8
run: dotnet test -c Release -f net8.0
working-directory: ${{env.TEST_ROOT}}

- name: Run Test .NET 5
run: dotnet test -c Release -f net5.0
working-directory: ${{env.TEST_ROOT}}

- name: Run Test .NET Framework 4.7.2
run: dotnet test -c Release -f net472
working-directory: ${{env.TEST_ROOT}}

- name: Run Test .NET Framework 4.8
run: dotnet test -c Release -f net48
- name: Run Test .NET 9
run: dotnet test -c Release -f net9.0
working-directory: ${{env.TEST_ROOT}}

- name: Restore Project
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 8.0.x
dotnet-version: 9.0.x
- name: Setup Rust
uses: actions-rs/toolchain@v1
with:
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,10 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: "8.0.x"
dotnet-quality: "preview"
dotnet-version: |
8.0.x
9.0.x
dotnet-quality: 'preview'

- name: Test .NET Runtime
run: |
Expand Down
4 changes: 1 addition & 3 deletions .github/workflows/test-csharp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,8 @@ jobs:
- uses: actions/setup-dotnet@v3
with:
dotnet-version: |
5.0.x
6.0.x
7.0.x
8.0.x
9.0.x
dotnet-quality: 'preview'
- name: Build and run tests
shell: bash
Expand Down
5 changes: 3 additions & 2 deletions Core/Generators/CSharp/CSharpGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public override ValueTask<string> Compile(BebopSchema schema, GeneratorConfig co
_ => string.Empty
};
builder.AppendLine(recordAttribute);
builder.AppendLine($"public partial class {definition.ClassName()} : {BebopRecord}, global::System.IEquatable<{definition.ClassName()}> {{");
builder.AppendLine($"public partial class {definition.ClassName()} : {BebopRecord}, {IDecodable}<{definition.ClassName()}>, global::System.IEquatable<{definition.ClassName()}> {{");
builder.Indent(indentStep);

if (fd is MessageDefinition)
Expand Down Expand Up @@ -646,7 +646,7 @@ void CompileUnionConcreteClass()
builder.AppendLine("/// <inheritdoc />");
builder.AppendLine(GeneratedAttribute);
builder.AppendLine(recordAttribute);
builder.AppendLine($"public partial class {ud.ClassName()} : {PrefixNamespace(ud.BaseClassName())}<{genericTypeArguments}> {{").Indent(indentStep).AppendLine();
builder.AppendLine($"public partial class {ud.ClassName()} : {PrefixNamespace(ud.BaseClassName())}<{genericTypeArguments}>, {IDecodable}<{ud.ClassName()}> {{").Indent(indentStep).AppendLine();
if (ud.OpcodeDecorator is not null && ud.OpcodeDecorator.Arguments.TryGetValue("fourcc", out var fourcc))
{
builder.AppendLine($"public const uint OpCode = {fourcc};");
Expand Down Expand Up @@ -1346,6 +1346,7 @@ public override void WriteAuxiliaryFile(string outputPath)
private const string StringGetByteCount = "global::System.Text.Encoding.UTF8.GetByteCount";
private const string StringGetMaxByteCount = "global::System.Text.Encoding.UTF8.GetMaxByteCount";
private const string BebopRecord = "global::Bebop.Runtime.BaseBebopRecord";
private const string IDecodable = "global::Bebop.Runtime.IDecodable";

private static readonly string[] DecodeBufferTypes = { "byte[]", "global::System.ReadOnlySpan<byte>", "global::System.ReadOnlyMemory<byte>", "global::System.ArraySegment<byte>", ImmutableByteArrayType };
/// <summary>
Expand Down
4 changes: 2 additions & 2 deletions Laboratory/C#/Benchmarks/Benchmarks.csproj
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net6.0;net5.0;net472</TargetFrameworks>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<Nullable>enable</Nullable>
<LangVersion>9.0</LangVersion>
<LangVersion>preview</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.1" />
Expand Down
4 changes: 2 additions & 2 deletions Laboratory/C#/Test/Test.csproj
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net6.0;net5.0;net472</TargetFrameworks>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<Nullable>enable</Nullable>
<LangVersion>9.0</LangVersion>
<LangVersion>preview</LangVersion>

<IsPackable>false</IsPackable>
</PropertyGroup>
Expand Down
2 changes: 1 addition & 1 deletion Laboratory/Integration/IntegrationTesting.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>

<OutputType>Exe</OutputType>
<LangVersion>12</LangVersion>
<LangVersion>preview</LangVersion>
<TargetFramework>net8.0</TargetFramework>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<NoWarn>$(NoWarn);CS9193</NoWarn>
Expand Down
48 changes: 6 additions & 42 deletions Runtime/C#/Bebop.csproj
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net472;netstandard2.0;netstandard2.1;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<Nullable>enable</Nullable>
<LangVersion>10.0</LangVersion>
<LangVersion>preview</LangVersion>
<Description>The .NET runtime for Bebop, a schema-based binary serialization format.</Description>
<PackageId>bebop</PackageId>
<Authors>The Bebop Authors</Authors>
Expand All @@ -13,52 +13,18 @@
<VersionPrefix Condition="'$(ReleaseVersion)' == ''">0.0.1</VersionPrefix>
<VersionSuffix Condition="'$(ReleaseVersion)' == ''">$([System.DateTime]::UtcNow.ToString(`yyyyMMdd-HHmm`))</VersionSuffix>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/RainwayApp/bebop</PackageProjectUrl>
<PackageProjectUrl>https://github.com/betwixt-labs/bebop</PackageProjectUrl>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<DocumentationFile>./bin/$(AssemblyName).xml</DocumentationFile>
<IncludeContentInPack>true</IncludeContentInPack>
<Company></Company>
<PackageIcon>128.png</PackageIcon>
<RepositoryUrl>https://github.com/RainwayApp/bebop.git</RepositoryUrl>
<RepositoryUrl>https://github.com/betwixt-labs/bebop.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>binary serialization bebop encoding decoding</PackageTags>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
</PropertyGroup>

<ItemGroup Condition="$(TargetFramework.StartsWith('net4')) Or $(TargetFramework.StartsWith('netcoreapp')) Or $(TargetFramework.StartsWith('netstandard'))">
<!--
IsExternalInit will not be added to legacy .NET Framework and as such this dependency needs to flow
to projects that reference our package so generated code works.
-->
<PackageReference Include="IsExternalInit" Version="1.0.2">
<PrivateAssets>none</PrivateAssets>
<ExcludeAssets>none</ExcludeAssets>
<IncludeAssets>all</IncludeAssets>
</PackageReference>

</ItemGroup>

<ItemGroup Condition="$(TargetFramework.StartsWith('net4')) Or $(TargetFramework.StartsWith('netstandard'))">
<PackageReference Include="System.Collections.Immutable" Version="6.0.0" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
</ItemGroup>


<ItemGroup Condition="$(TargetFramework.StartsWith('net4')) Or '$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="System.Memory" Version="4.5.4" />
<PackageReference Include="System.Buffers" Version="4.5.1" />
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
<!--
Nullable will not be added to legacy .NET Framework and as such this dependency needs to flow
to projects that reference our package so generated code works.
-->
<PackageReference Include="Nullable" Version="1.3.0">
<PrivateAssets>none</PrivateAssets>
<ExcludeAssets>none</ExcludeAssets>
<IncludeAssets>all</IncludeAssets>
</PackageReference>
</ItemGroup>


<ItemGroup>
<PackageReference Include="ErrorProne.NET.CoreAnalyzers" Version="0.3.0-beta.0">
Expand All @@ -71,19 +37,17 @@
</PackageReference>
</ItemGroup>


<ItemGroup>
<None Include="..\..\assets\128.png">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
</ItemGroup>

<PropertyGroup Condition="'$(TargetFramework)' == 'net5.0' Or '$(TargetFramework)' == 'netcoreapp3.1' Or '$(TargetFramework)' == 'net6.0' Or '$(TargetFramework)' == 'net7.0' Or '$(TargetFramework)' == 'net8.0'">
<PropertyGroup Condition="'$(TargetFramework)' == 'net8.0' Or '$(TargetFramework)' == 'net9.0'">
<DefineConstants>TRACE;AGGRESSIVE_OPTIMIZE</DefineConstants>
</PropertyGroup>


<PropertyGroup Condition="'$(Configuration)'=='Release'">
<Optimize>true</Optimize>
</PropertyGroup>
Expand All @@ -92,4 +56,4 @@
<Optimize>false</Optimize>
</PropertyGroup>

</Project>
</Project>
52 changes: 49 additions & 3 deletions Runtime/C#/Runtime/BebopRecord.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,51 @@

namespace Bebop.Runtime
{

/// <summary>
/// Provides a contract for decoding various byte-based data representations into instances of Bebop records of type <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">The type of Bebop record that implements the decoding methods, constrained to <see cref="BaseBebopRecord"/>.</typeparam>
public interface IDecodable<T> where T : BaseBebopRecord
{
/// <summary>
/// Decodes the specified byte array into an instance of the Bebop record <typeparamref name="T"/>.
/// </summary>
/// <param name="record">The byte array containing the encoded Bebop record data.</param>
/// <returns>An instance of the Bebop record <typeparamref name="T"/> decoded from the byte array.</returns>
static abstract T Decode(byte[] record);

/// <summary>
/// Decodes the specified read-only span of bytes into an instance of the Bebop record <typeparamref name="T"/>.
/// </summary>
/// <param name="record">The read-only span of bytes containing the encoded Bebop record data.</param>
/// <returns>An instance of the Bebop record <typeparamref name="T"/> decoded from the read-only span of bytes.</returns>
static abstract T Decode(ReadOnlySpan<byte> record);

/// <summary>
/// Decodes the specified read-only memory of bytes into an instance of the Bebop record <typeparamref name="T"/>.
/// </summary>
/// <param name="record">The read-only memory of bytes containing the encoded Bebop record data.</param>
/// <returns>An instance of the Bebop record <typeparamref name="T"/> decoded from the read-only memory of bytes.</returns>
static abstract T Decode(ReadOnlyMemory<byte> record);

/// <summary>
/// Decodes the specified array segment of bytes into an instance of the Bebop record <typeparamref name="T"/>.
/// </summary>
/// <param name="record">The array segment of bytes containing the encoded Bebop record data.</param>
/// <returns>An instance of the Bebop record <typeparamref name="T"/> decoded from the array segment of bytes.</returns>
static abstract T Decode(ArraySegment<byte> record);

/// <summary>
/// Decodes the specified immutable array of bytes into an instance of the Bebop record <typeparamref name="T"/>.
/// </summary>
/// <param name="record">The immutable array of bytes containing the encoded Bebop record data.</param>
/// <returns>An instance of the Bebop record <typeparamref name="T"/> decoded from the immutable array of bytes.</returns>
static abstract T Decode(ImmutableArray<byte> record);
}



/// <summary>
/// A base class which is implemented by all bebopc generated classes.
/// </summary>
Expand Down Expand Up @@ -39,6 +84,7 @@ protected BaseBebopRecord() { }
/// <para><see cref="ByteCount"/> calculates the exact number of bytes that will be produced when the current record is encoded.</para>
/// </remarks>
public abstract int ByteCount { get; }

/// <summary>
/// Encodes the current record.
/// </summary>
Expand Down Expand Up @@ -281,7 +327,7 @@ internal override void AssignHandler(MethodInfo methodInfo, object handlerInstan
if (methodInfo.IsValueTask())
{
_handlerValueTaskDelegate =
(Func<object, T, ValueTask>) (isStaticHandler
(Func<object, T, ValueTask>)(isStaticHandler
? Delegate.CreateDelegate(delegateType,
methodInfo)
: Delegate.CreateDelegate(delegateType, handlerInstance,
Expand All @@ -290,15 +336,15 @@ internal override void AssignHandler(MethodInfo methodInfo, object handlerInstan
else if (methodInfo.IsTask())
{
_handlerTaskDelegate =
(Func<object, T, Task>) (isStaticHandler
(Func<object, T, Task>)(isStaticHandler
? Delegate.CreateDelegate(delegateType,
methodInfo)
: Delegate.CreateDelegate(delegateType, handlerInstance, methodInfo));
}
else
{
_handlerVoidDelegate =
(Action<object, T>) (isStaticHandler
(Action<object, T>)(isStaticHandler
? Delegate.CreateDelegate(delegateType,
methodInfo)
: Delegate.CreateDelegate(delegateType, handlerInstance, methodInfo));
Expand Down
Loading
Loading