Skip to content

Commit

Permalink
feat: BebopSerializer, IIDecodable
Browse files Browse the repository at this point in the history
- adds a new BebopSerializer class which handles encoding and decoding in a single place.
- adds a new IDecodable<T> interface which allows generated code to implement static abstract Decode methods
- drops support for old .NET Framework and exclusively supports .NET 8 & 9

fix: ci

fix: tests

fix: language version

fix: workflow
  • Loading branch information
andrewmd5 committed Jul 15, 2024
1 parent 4ba387c commit e0b09f3
Show file tree
Hide file tree
Showing 11 changed files with 202 additions and 73 deletions.
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

0 comments on commit e0b09f3

Please sign in to comment.