Skip to content

Commit

Permalink
Allowed multiple WLengthOf attributes on a single field/property.
Browse files Browse the repository at this point in the history
  • Loading branch information
MeltyPlayer committed Jul 30, 2023
1 parent 72ac6f4 commit a2eeb50
Show file tree
Hide file tree
Showing 12 changed files with 278 additions and 49 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using System.IO;

using schema.binary;
using schema.binary.attributes;

namespace build {
public partial class StringLengthSourceTests {
[BinarySchema]
public partial class MultipleStringWrapper : IBinaryConvertible {
[WLengthOfString(nameof(String1))]
[WLengthOfString(nameof(String2))]
private uint length_;

[RStringLengthSource(nameof(length_))]
public string String1 { get; set; }

[RStringLengthSource(nameof(length_))]
public string String2 { get; set; }

public override bool Equals(object other) {
if (other is MultipleStringWrapper otherStringWrapper) {
return this.String1.Equals(
otherStringWrapper.String1) &&
this.String2.Equals(
otherStringWrapper.String2);
}

return false;
}

public override string ToString()
=> $"{this.String1}, {this.String2}";
}

[Test]
public void TestWriteAndReadMultiple() {
var expectedSw = new MultipleStringWrapper {
String1 = "holy",
String2 = "moly",
};

var ms = new MemoryStream();

var endianness = Endianness.BigEndian;
var ew = new EndianBinaryWriter(endianness);

expectedSw.Write(ew);
ew.CompleteAndCopyToDelayed(ms).Wait();

ms.Position = 0;
var er = new EndianBinaryReader(ms, endianness);
var actualSw = er.ReadNew<MultipleStringWrapper>();

Assert.AreEqual(expectedSw, actualSw);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,5 +90,60 @@ public void Write(ISubEndianBinaryWriter ew) {
}
");
}

[Test]
public void TestMultiple() {
BinarySchemaTestUtil.AssertGenerated(@"
using System.Collections.Generic;
using schema.binary;
using schema.binary.attributes;
namespace foo.bar {
[BinarySchema]
public partial class SequenceWrapper : IBinaryConvertible {
[WLengthOfSequence(nameof(Sequence1)]
[WLengthOfSequence(nameof(Sequence2)]
public int Length { get; private set; }
[RSequenceLengthSource(nameof(Length))]
public byte[] Sequence1 { get; set; }
[RSequenceLengthSource(nameof(Length))]
public List<byte> Sequence2 { get; set; }
}
}",
@"using System;
using System.IO;
using schema.util.sequences;
namespace foo.bar {
public partial class SequenceWrapper {
public void Read(IEndianBinaryReader er) {
this.Length = er.ReadInt32();
this.Sequence1 = SequencesUtil.CloneAndResizeSequence(this.Sequence1, this.Length);
er.ReadBytes(this.Sequence1);
SequencesUtil.ResizeSequenceInPlace(this.Sequence2, this.Length);
er.ReadBytes(this.Sequence2);
}
}
}
",
@"using System;
using System.IO;
using schema.util;
namespace foo.bar {
public partial class SequenceWrapper {
public void Write(ISubEndianBinaryWriter ew) {
Asserts.AllEqual(Sequence1.Length, Sequence2.Count);
ew.WriteInt32(Sequence1.Length);
ew.WriteBytes(this.Sequence1);
ew.WriteBytes(this.Sequence2);
}
}
}
");
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,56 @@ public void Write(ISubEndianBinaryWriter ew) {
}
}
}
");
}

[Test]
public void TestMultipleStrings() {
BinarySchemaTestUtil.AssertGenerated(@"
using schema.binary;
using schema.binary.attributes;
namespace foo.bar {
[BinarySchema]
public partial class NtsWrapper : IBinaryConvertible {
[WLengthOfString(nameof(Text1)]
[WLengthOfString(nameof(Text2)]
public uint Length { get; private set; }
[RStringLengthSource(nameof(Length))]
public string Text1 { get; set; }
[RStringLengthSource(nameof(Length))]
public string Text2 { get; set; }
}
}",
@"using System;
using System.IO;
namespace foo.bar {
public partial class NtsWrapper {
public void Read(IEndianBinaryReader er) {
this.Length = er.ReadUInt32();
this.Text1 = er.ReadString(Length);
this.Text2 = er.ReadString(Length);
}
}
}
",
@"using System;
using System.IO;
using schema.util;
namespace foo.bar {
public partial class NtsWrapper {
public void Write(ISubEndianBinaryWriter ew) {
Asserts.AllEqual(Text1.Length, Text2.Length);
ew.WriteUInt32((uint) Text1.Length);
ew.WriteString(this.Text1);
ew.WriteString(this.Text2);
}
}
}
");
}
}
Expand Down
8 changes: 4 additions & 4 deletions Schema/src/binary/BinarySchemaStructureParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ public interface IPrimitiveMemberType : IMemberType {
SchemaNumberType AltFormat { get; }

bool SizeOfStream { get; }
IMemberReference<string>? LengthOfStringMember { get; }
IMemberReference? LengthOfSequenceMember { get; }
IMemberReference<string>[]? LengthOfStringMembers { get; }
IMemberReference[]? LengthOfSequenceMembers { get; }
IChain<IAccessChainNode>? AccessChainToSizeOf { get; }
IChain<IAccessChainNode>? AccessChainToPointer { get; }
}
Expand Down Expand Up @@ -629,8 +629,8 @@ public SchemaPrimitiveType PrimitiveType
public SchemaNumberType AltFormat { get; set; }

public bool SizeOfStream { get; set; }
public IMemberReference<string>? LengthOfStringMember { get; set; }
public IMemberReference? LengthOfSequenceMember { get; set; }
public IMemberReference<string>[]? LengthOfStringMembers { get; set; }
public IMemberReference[]? LengthOfSequenceMembers { get; set; }
public IChain<IAccessChainNode>? AccessChainToSizeOf { get; set; }
public IChain<IAccessChainNode>? AccessChainToPointer { get; set; }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ namespace schema.binary.attributes {
/// length source.
/// </para>
/// </summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property,
AllowMultiple = true)]
public class WLengthOfSequenceAttribute : BMemberAttribute {
private string otherMemberName_;

Expand Down
15 changes: 8 additions & 7 deletions Schema/src/binary/attributes/sequence/WLengthOfSequenceParser.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.CodeAnalysis;

using System.Collections.Generic;
using System.Linq;

using schema.binary.parser;

Expand All @@ -11,19 +12,19 @@ public void ParseIntoMemberType(IList<Diagnostic> diagnostics,
ISymbol memberSymbol,
ITypeInfo memberTypeInfo,
IMemberType memberType) {
var lengthOfSequenceAttribute =
SymbolTypeUtil.GetAttribute<WLengthOfSequenceAttribute>(
diagnostics,
memberSymbol);
if (lengthOfSequenceAttribute == null) {
var lengthOfSequenceAttributes =
memberSymbol.GetAttributes<WLengthOfSequenceAttribute>(diagnostics)
.ToArray();
if (lengthOfSequenceAttributes.Length == 0) {
return;
}

if (memberTypeInfo is IIntegerTypeInfo &&
memberType is BinarySchemaStructureParser.PrimitiveMemberType
primitiveMemberType) {
primitiveMemberType.LengthOfSequenceMember =
lengthOfSequenceAttribute.OtherMember;
primitiveMemberType.LengthOfSequenceMembers =
lengthOfSequenceAttributes.Select(attr => attr.OtherMember)
.ToArray();
} else {
diagnostics.Add(
Rules.CreateDiagnostic(memberSymbol, Rules.NotSupported));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ namespace schema.binary.attributes {
/// length source.
/// </para>
/// </summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property,
AllowMultiple = true)]
public class WLengthOfStringAttribute : BMemberAttribute {
private string otherMemberName_;

Expand Down
15 changes: 8 additions & 7 deletions Schema/src/binary/attributes/string/WLengthOfStringParser.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.CodeAnalysis;

using System.Collections.Generic;
using System.Linq;

using schema.binary.parser;

Expand All @@ -11,19 +12,19 @@ public void ParseIntoMemberType(IList<Diagnostic> diagnostics,
ISymbol memberSymbol,
ITypeInfo memberTypeInfo,
IMemberType memberType) {
var lengthOfStringAttribute =
SymbolTypeUtil.GetAttribute<WLengthOfStringAttribute>(
diagnostics,
memberSymbol);
if (lengthOfStringAttribute == null) {
var lengthOfStringAttributes =
memberSymbol.GetAttributes<WLengthOfStringAttribute>(diagnostics)
.ToArray();
if (lengthOfStringAttributes.Length == 0) {
return;
}

if (memberTypeInfo is IIntegerTypeInfo &&
memberType is BinarySchemaStructureParser.PrimitiveMemberType
primitiveMemberType) {
primitiveMemberType.LengthOfStringMember =
lengthOfStringAttribute.OtherMember;
primitiveMemberType.LengthOfStringMembers =
lengthOfStringAttributes.Select(attr => attr.OtherMember)
.ToArray();
} else {
diagnostics.Add(
Rules.CreateDiagnostic(memberSymbol, Rules.NotSupported));
Expand Down
34 changes: 25 additions & 9 deletions Schema/src/binary/dependencies/DependencyExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,36 @@ public static bool DependsOnSchemaAttributes(
EncodingType: not StringEncodingType.ASCII,
});


public static bool DependsOnSchemaUtil(
this IBinarySchemaStructure structure)
=> structure
.Members
.OfType<ISchemaValueMember>()
.Any(
member
=> member.MemberType is
IPrimitiveMemberType {
LengthOfStringMembers.Length: > 1
} or
IPrimitiveMemberType {
LengthOfSequenceMembers.Length: > 1
});

public static bool DependsOnCollectionsImports(
this IBinarySchemaStructure structure)
=> structure
.Members
.OfType<ISchemaValueMember>()
.Any(
member => member is {
MemberType: ISequenceMemberType {
LengthSourceType: SequenceLengthSourceType
.UNTIL_END_OF_STREAM
}
} or {
MemberType: ISequenceMemberType,
IfBoolean: { },
});
member => member is {
MemberType: ISequenceMemberType {
LengthSourceType: SequenceLengthSourceType
.UNTIL_END_OF_STREAM
}
} or {
MemberType: ISequenceMemberType,
IfBoolean: { },
});
}
}
43 changes: 31 additions & 12 deletions Schema/src/binary/text/BinarySchemaWriterGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ public string Generate(IBinarySchemaStructure structure) {
dependencies.Add("schema.binary.attributes");
}

if (structure.DependsOnSchemaUtil()) {
dependencies.Add("schema.util");
}

dependencies.Sort(StringComparer.Ordinal);
foreach (var dependency in dependencies) {
cbsb.WriteLine($"using {dependency};");
Expand Down Expand Up @@ -250,24 +254,39 @@ private static void WritePrimitive_(
if (member.MemberType is IPrimitiveMemberType
primitiveMemberType) {
var isLengthOfString =
primitiveMemberType.LengthOfStringMember != null;
var isLengthOfSequence =
primitiveMemberType.LengthOfSequenceMember != null;
var lengthOfStringMembers =
primitiveMemberType.LengthOfStringMembers;
var isLengthOfString = lengthOfStringMembers is { Length: > 0 };
if (isLengthOfString) {
accessText =
$"{primitiveMemberType.LengthOfStringMember!.Name}.Length";
accessText = $"{lengthOfStringMembers[0].Name}.Length";
if (lengthOfStringMembers.Length > 1) {
cbsb.WriteLine(
$"Asserts.AllEqual({string.Join(", ", lengthOfStringMembers.Select(member => $"{member.Name}.Length"))});");
}
}
var lengthOfSequenceMembers =
primitiveMemberType.LengthOfSequenceMembers;
var isLengthOfSequence = lengthOfSequenceMembers is
{ Length: > 0 };
if (isLengthOfSequence) {
var lengthName =
(primitiveMemberType.LengthOfSequenceMember.MemberTypeInfo
as ISequenceTypeInfo).LengthName;
accessText =
$"{primitiveMemberType.LengthOfSequenceMember.Name}.{lengthName}";
var first = lengthOfSequenceMembers[0];
var firstLengthName =
(first.MemberTypeInfo as ISequenceTypeInfo).LengthName;
accessText = $"{first.Name}.{firstLengthName}";
if (lengthOfSequenceMembers.Length > 1) {
cbsb.WriteLine(
$"Asserts.AllEqual({string.Join(", ", lengthOfSequenceMembers.Select(
member => {
var lengthName =
(member.MemberTypeInfo as ISequenceTypeInfo).LengthName;
return $"{member.Name}.{lengthName}";
}))});");
}
}
if (isLengthOfSequence) { }
if ((isLengthOfString || isLengthOfSequence) &&
primitiveType.PrimitiveType != SchemaPrimitiveType.INT32) {
var castType =
Expand Down
Loading

0 comments on commit a2eeb50

Please sign in to comment.