Skip to content

Commit

Permalink
Added ability to read vectors/matrices directly via Schema.
Browse files Browse the repository at this point in the history
  • Loading branch information
MeltyPlayer committed Nov 20, 2024
1 parent 18f6a3b commit dd1be2b
Show file tree
Hide file tree
Showing 11 changed files with 310 additions and 7 deletions.
34 changes: 34 additions & 0 deletions Schema Build Tests/binary/KnownStructTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.Numerics;

using NUnit.Framework;

using schema.testing;


namespace schema.binary;

public partial class KnownStructTests {
[BinarySchema]
private partial class Vector2Wrapper : IBinaryConvertible {
public Vector2 Value { get; private set; }
}

[Test]
public void TestReadingVector2() {
using var br = SchemaMemoryStream.From([123f, 456f]).GetBinaryReader();
Assert.AreEqual(new Vector2(123, 456), br.ReadNew<Vector2Wrapper>().Value);
}


[BinarySchema]
private partial class Vector4Wrapper : IBinaryConvertible {
public Vector4 Value { get; private set; }
}

[Test]
public void TestReadingVector4() {
using var br = SchemaMemoryStream.From([12f, 23f, 34f, 45f])
.GetBinaryReader();
Assert.AreEqual(new Vector4(12, 23, 34, 45), br.ReadNew<Vector4Wrapper>().Value);
}
}
56 changes: 56 additions & 0 deletions Schema Tests/binary/generator/KnownStructTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using NUnit.Framework;


namespace schema.binary.text;

internal class KnownStructTests {
[Test]
[TestCase("Vector2")]
[TestCase("Vector3")]
[TestCase("Vector4")]
[TestCase("Matrix3x2")]
[TestCase("Matrix4x4")]
public void TestSystemNumerics(string knownStructName) {
BinarySchemaTestUtil.AssertGenerated(
$$"""
using System.Numerics;
using schema.binary;
namespace foo.bar {
[BinarySchema]
public partial class Wrapper {
public {{knownStructName}} Field { get; set; }
public {{knownStructName}} PrivateField { get; private set; }
}
}
""",
$$"""
using System;
using schema.binary;
namespace foo.bar {
public partial class Wrapper {
public void Read(IBinaryReader br) {
this.Field = br.Read{{knownStructName}}();
this.PrivateField = br.Read{{knownStructName}}();
}
}
}
""",
$$"""
using System;
using schema.binary;
namespace foo.bar {
public partial class Wrapper {
public void Write(IBinaryWriter bw) {
bw.Write{{knownStructName}}(this.Field);
bw.Write{{knownStructName}}(this.PrivateField);
}
}
}
""");
}
}
27 changes: 25 additions & 2 deletions Schema/src/binary/BinarySchemaStructureParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@ public interface IContainerMemberType : IMemberType {
bool IsChild { get; }
}

public enum KnownStruct {
VECTOR2,
VECTOR3,
VECTOR4,
MATRIX4X4,
MATRIX3X2
}

public interface IKnownStructMemberType : IMemberType {
KnownStruct KnownStruct { get; }
}

public interface IGenericMemberType : IMemberType {
IMemberType? ConstraintType { get; }
}
Expand Down Expand Up @@ -191,7 +203,7 @@ public IBinarySchemaContainer ParseContainer(
continue;
}

if (memberSymbol is IPropertySymbol {IsIndexer: true}) {
if (memberSymbol is IPropertySymbol { IsIndexer: true }) {
continue;
}

Expand Down Expand Up @@ -298,7 +310,9 @@ public IBinarySchemaContainer ParseContainer(
}

// Makes sure the member is serializable
if (memberTypeInfo is IContainerTypeInfo) {
if (memberTypeInfo is IContainerTypeInfo containerTypeInfo &&
!MemberReferenceUtil.IsKnownStruct(containerTypeInfo.TypeSymbol,
out _)) {
if (!memberTypeInfo.TypeSymbol.IsAtLeastAsBinaryConvertibleAs(
containerTypeSymbol)) {
memberBetterSymbol.ReportDiagnostic(
Expand Down Expand Up @@ -629,6 +643,15 @@ public class ContainerMemberType : IContainerMemberType {
public bool IsChild { get; set; }
}

public class KnownStructMemberType : IKnownStructMemberType {
public IContainerTypeInfo ContainerTypeInfo { get; set; }
public ITypeInfo TypeInfo => this.ContainerTypeInfo;
public ITypeSymbol TypeSymbol => TypeInfo.TypeSymbol;
public bool IsReadOnly => this.TypeInfo.IsReadOnly;

public KnownStruct KnownStruct { get; set; }
}

public class GenericMemberType : IGenericMemberType {
public IMemberType? ConstraintType { get; set; }
public IGenericTypeInfo GenericTypeInfo { get; set; }
Expand Down
39 changes: 39 additions & 0 deletions Schema/src/binary/parser/MemberReferenceUtil.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Linq;
using System.Numerics;

using Microsoft.CodeAnalysis;

Expand Down Expand Up @@ -60,6 +61,12 @@ public static IMemberType WrapTypeInfoWithMemberType(
};
}
case IContainerTypeInfo containerTypeInfo: {
if (IsKnownStruct(containerTypeInfo.TypeSymbol, out var knownStruct)) {
return new BinarySchemaContainerParser.KnownStructMemberType {
ContainerTypeInfo = containerTypeInfo, KnownStruct = knownStruct
};
}

return new BinarySchemaContainerParser.ContainerMemberType {
ContainerTypeInfo = containerTypeInfo,
};
Expand Down Expand Up @@ -128,4 +135,36 @@ public static BinarySchemaContainerParser.SchemaValueMember
MemberType = MemberReferenceUtil.WrapTypeInfoWithMemberType(
memberReference.MemberTypeInfo),
};

public static bool IsKnownStruct(ITypeSymbol typeSymbol,
out KnownStruct knownStruct) {
if (typeSymbol.IsType<Vector2>()) {
knownStruct = KnownStruct.VECTOR2;
return true;
}

if (typeSymbol.IsType<Vector3>()) {
knownStruct = KnownStruct.VECTOR3;
return true;
}

if (typeSymbol.IsType<Vector4>()) {
knownStruct = KnownStruct.VECTOR4;
return true;
}

if (typeSymbol.IsType<Matrix3x2>()) {
knownStruct = KnownStruct.MATRIX3X2;
return true;
}


if (typeSymbol.IsType<Matrix4x4>()) {
knownStruct = KnownStruct.MATRIX4X4;
return true;
}

knownStruct = default;
return false;
}
}
41 changes: 41 additions & 0 deletions Schema/src/binary/reader/BinaryReaderExtensions_Known.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System;
using System.Numerics;
using System.Runtime.CompilerServices;

using CommunityToolkit.HighPerformance;

namespace schema.binary;

public static partial class BinaryReaderExtensions {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe T ReadFloatArrayStruct_<T>(this IBinaryReader br)
where T : unmanaged {
T value;

T* ptr = &value;
var span = new Span<T>(ptr, 1);
br.ReadSingles(span.Cast<T, float>());

return value;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 ReadVector2(this IBinaryReader br)
=> br.ReadFloatArrayStruct_<Vector2>();

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 ReadVector3(this IBinaryReader br)
=> br.ReadFloatArrayStruct_<Vector3>();

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 ReadVector4(this IBinaryReader br)
=> br.ReadFloatArrayStruct_<Vector4>();

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Matrix3x2 ReadMatrix3x2(this IBinaryReader br)
=> br.ReadFloatArrayStruct_<Matrix3x2>();

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Matrix4x4 ReadMatrix4x4(this IBinaryReader br)
=> br.ReadFloatArrayStruct_<Matrix4x4>();
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace schema.binary;

public static class BinaryReaderExtensions {
public static partial class BinaryReaderExtensions {
public static byte SubreadByteAt(this IBinaryReader br, long position) {
var tmp = br.Position;
br.Position = position;
Expand Down
34 changes: 33 additions & 1 deletion Schema/src/binary/text/BinarySchemaReaderGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,12 @@ member.MemberType is not ISequenceMemberType {
member);
break;
}
case IKnownStructMemberType knownStructMemberType: {
BinarySchemaReaderGenerator.ReadKnownStruct_(sw,
knownStructMemberType,
member);
break;
}
case ISequenceMemberType: {
BinarySchemaReaderGenerator.ReadArray_(sw, sourceSymbol, member);
break;
Expand Down Expand Up @@ -509,6 +515,29 @@ var qualifiedTypeName
() => sw.WriteLine($"this.{member.Name} = default;"));
}

private static void ReadKnownStruct_(
ISourceWriter sw,
IKnownStructMemberType knownStructMemberType,
ISchemaValueMember member) {
HandleMemberEndiannessAndAtPosition_(
sw,
member,
_ => {
var memberName = member.Name;
var knownStructName
= SchemaGeneratorUtil.GetKnownStructName(
knownStructMemberType.KnownStruct);
sw.WriteLine(
$"this.{memberName} = {READER}.Read{knownStructName}();");

// TODO: Handle assertions
if (knownStructMemberType.IsReadOnly) {
throw new NotImplementedException();
}
},
() => sw.WriteLine($"this.{member.Name} = default;"));
}

private static void ReadArray_(
ISourceWriter sw,
ITypeSymbol sourceSymbol,
Expand Down Expand Up @@ -665,7 +694,10 @@ arrayType.ElementType is IPrimitiveMemberType
}
}

BinarySchemaReaderGenerator.ReadIntoArray_(sw, sourceSymbol, member);
BinarySchemaReaderGenerator.ReadIntoArray_(
sw,
sourceSymbol,
member);
},
falseHandler);
}
Expand Down
24 changes: 24 additions & 0 deletions Schema/src/binary/text/BinarySchemaWriterGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection.PortableExecutable;
using System.Text;

using Microsoft.CodeAnalysis;
Expand Down Expand Up @@ -140,6 +141,13 @@ private static void WriteValueMember_(
member);
break;
}
case IKnownStructMemberType knownStructMemberType: {
BinarySchemaWriterGenerator.WriteKnownStruct_(
sw,
knownStructMemberType,
member);
break;
}
case ISequenceMemberType: {
BinarySchemaWriterGenerator.WriteArray_(sw, member);
break;
Expand Down Expand Up @@ -388,6 +396,22 @@ private static void WriteContainer_(
});
}

private static void WriteKnownStruct_(
ISourceWriter sw,
IKnownStructMemberType knownStructMemberType,
ISchemaValueMember member) {
HandleMemberEndiannessAndTracking_(
sw,
member,
() => {
var memberName = member.Name;
var knownStructName
= SchemaGeneratorUtil.GetKnownStructName(
knownStructMemberType.KnownStruct);
sw.WriteLine($"{WRITER}.Write{knownStructName}(this.{memberName});");
});
}

private static void WriteArray_(
ISourceWriter sw,
ISchemaValueMember member) {
Expand Down
13 changes: 13 additions & 0 deletions Schema/src/binary/text/SchemaGeneratorUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,17 @@ public static string GetEndiannessName(Endianness type)
Endianness.LittleEndian => "Endianness.LittleEndian",
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
};

public static string GetKnownStructName(KnownStruct knownStruct)
=> knownStruct switch {
KnownStruct.VECTOR2 => "Vector2",
KnownStruct.VECTOR3 => "Vector3",
KnownStruct.VECTOR4 => "Vector4",
KnownStruct.MATRIX4X4 => "Matrix4x4",
KnownStruct.MATRIX3X2 => "Matrix3x2",
_ => throw new ArgumentOutOfRangeException(
nameof(knownStruct),
knownStruct,
null)
};
}
Loading

0 comments on commit dd1be2b

Please sign in to comment.