Skip to content

Commit 29b981a

Browse files
committed
ProtocolGenerator: support interfaces with more than 64 readable properties.
1 parent b4a7fed commit 29b981a

8 files changed

Lines changed: 2046 additions & 43 deletions

src/Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />
33
<PropertyGroup>
44
<PublishRepositoryUrl>true</PublishRepositoryUrl>
5-
<VersionPrefix>0.94.1</VersionPrefix>
5+
<VersionPrefix>0.94.2</VersionPrefix>
66
<DeterministicSourcePaths Condition="'$(Configuration)' == 'Release'">true</DeterministicSourcePaths>
77
</PropertyGroup>
88
</Project>

src/Tmds.DBus.Tool/ProtocolGenerator.cs

Lines changed: 105 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,10 +1237,7 @@ private void AppendPropertyTypes(string name, XElement interfaceXml, bool genera
12371237
string nullableInterfaceName = $"INullable{propertiesClassName}";
12381238
string changedInterfaceName = $"IChanged{propertiesClassName}";
12391239

1240-
if (readableProperties.Length > 64)
1241-
{
1242-
throw new NotSupportedException($"Interface '{name}' has {readableProperties.Length} readable properties, but the maximum supported is 64.");
1243-
}
1240+
bool useByteArray = readableProperties.Length > 64;
12441241

12451242
AppendLine($"interface {nullableInterfaceName}");
12461243
StartBlock();
@@ -1263,26 +1260,45 @@ private void AppendPropertyTypes(string name, XElement interfaceXml, bool genera
12631260
AppendLine($"sealed class {propertiesClassName} : {changedInterfaceName}, I{name}Properties");
12641261
StartBlock();
12651262

1266-
string flagType = readableProperties.Length <= 32 ? "uint" : "ulong";
1267-
string one = readableProperties.Length <= 32 ? "1U" : "1UL";
1268-
1269-
string allSetValue;
1270-
if (readableProperties.Length <= 32)
1263+
if (useByteArray)
12711264
{
1272-
uint value = readableProperties.Length == 32 ? uint.MaxValue : (1U << readableProperties.Length) - 1;
1273-
allSetValue = $"0x{value:X}U";
1265+
int byteCount = (readableProperties.Length + 7) / 8;
1266+
var allSetBytes = new byte[byteCount];
1267+
for (int i = 0; i < byteCount - 1; i++)
1268+
allSetBytes[i] = 0xFF;
1269+
int remainder = readableProperties.Length % 8;
1270+
allSetBytes[byteCount - 1] = remainder == 0 ? (byte)0xFF : (byte)((1 << remainder) - 1);
1271+
string allSetLiteral = string.Join(", ", allSetBytes.Select(b => $"0x{b:X2}"));
1272+
1273+
AppendLine($"private byte[] __set = new byte[{byteCount}];");
1274+
AppendLine($"private byte[] __invalidated = new byte[{byteCount}];");
1275+
AppendLine($"private static ReadOnlySpan<byte> PropertiesAllSet => new byte[] {{ {allSetLiteral} }}; // {readableProperties.Length} properties");
1276+
AppendLine($"private static int FlagIndex({propertyEnumName} property) => ((int)property - 1) / 8;");
1277+
AppendLine($"private static byte FlagMask({propertyEnumName} property) => (byte)(1 << (((int)property - 1) % 8));");
12741278
}
12751279
else
12761280
{
1277-
ulong value = readableProperties.Length == 64 ? ulong.MaxValue : (1UL << readableProperties.Length) - 1;
1278-
allSetValue = $"0x{value:X}UL";
1279-
}
1281+
string flagType = readableProperties.Length <= 32 ? "uint" : "ulong";
1282+
string one = readableProperties.Length <= 32 ? "1U" : "1UL";
1283+
1284+
string allSetValue;
1285+
if (readableProperties.Length <= 32)
1286+
{
1287+
uint value = readableProperties.Length == 32 ? uint.MaxValue : (1U << readableProperties.Length) - 1;
1288+
allSetValue = $"0x{value:X}U";
1289+
}
1290+
else
1291+
{
1292+
ulong value = readableProperties.Length == 64 ? ulong.MaxValue : (1UL << readableProperties.Length) - 1;
1293+
allSetValue = $"0x{value:X}UL";
1294+
}
12801295

1281-
AppendLine($"private {flagType} __set;");
1282-
AppendLine($"private {flagType} __invalidated;");
1283-
AppendLine($"private const {flagType} PropertiesAllSet = {allSetValue}; // {readableProperties.Length} properties");
1296+
AppendLine($"private {flagType} __set;");
1297+
AppendLine($"private {flagType} __invalidated;");
1298+
AppendLine($"private const {flagType} PropertiesAllSet = {allSetValue}; // {readableProperties.Length} properties");
12841299

1285-
AppendLine($"private static {flagType} Flag({propertyEnumName} property) => property == 0 ? 0 : {one} << ((int)property - 1);");
1300+
AppendLine($"private static {flagType} Flag({propertyEnumName} property) => property == 0 ? 0 : {one} << ((int)property - 1);");
1301+
}
12861302

12871303
AppendLine($"public {propertiesClassName}() {{ }}");
12881304
AppendLine("#nullable disable");
@@ -1304,7 +1320,14 @@ private void AppendPropertyTypes(string name, XElement interfaceXml, bool genera
13041320
AppendLine($"public required {property.DotnetReadType} {property.NameUpper}");
13051321
StartBlock();
13061322
AppendLine($"get {{ EnsureSet({propertyEnumName}.{property.NameUpper}); return {property.UnderscoreNameLower}; }}");
1307-
AppendLine($"set {{ {property.UnderscoreNameLower} = value; __set |= Flag({propertyEnumName}.{property.NameUpper}); }}");
1323+
if (useByteArray)
1324+
{
1325+
AppendLine($"set {{ {property.UnderscoreNameLower} = value; __set[FlagIndex({propertyEnumName}.{property.NameUpper})] |= FlagMask({propertyEnumName}.{property.NameUpper}); }}");
1326+
}
1327+
else
1328+
{
1329+
AppendLine($"set {{ {property.UnderscoreNameLower} = value; __set |= Flag({propertyEnumName}.{property.NameUpper}); }}");
1330+
}
13081331
EndBlock();
13091332
}
13101333

@@ -1333,10 +1356,21 @@ private void AppendPropertyTypes(string name, XElement interfaceXml, bool genera
13331356

13341357
AppendLine($"public static {propertiesClassName} CreateUninitialized() => new {propertiesClassName}(false);");
13351358

1336-
AppendLine($"private bool HasFlag({flagType} flags, {propertyEnumName} property)");
1337-
_indentation++;
1338-
AppendLine($"=> property != 0 && (flags & Flag(property)) != 0;");
1339-
_indentation--;
1359+
if (useByteArray)
1360+
{
1361+
AppendLine($"private bool HasFlag(byte[] flags, {propertyEnumName} property)");
1362+
_indentation++;
1363+
AppendLine($"=> property != 0 && (flags[FlagIndex(property)] & FlagMask(property)) != 0;");
1364+
_indentation--;
1365+
}
1366+
else
1367+
{
1368+
string flagType = readableProperties.Length <= 32 ? "uint" : "ulong";
1369+
AppendLine($"private bool HasFlag({flagType} flags, {propertyEnumName} property)");
1370+
_indentation++;
1371+
AppendLine($"=> property != 0 && (flags & Flag(property)) != 0;");
1372+
_indentation--;
1373+
}
13401374

13411375
AppendLine($"public bool IsSet({propertyEnumName} property) => HasFlag(__set, property);");
13421376
AppendLine($"public bool IsInvalidated({propertyEnumName} property) => HasFlag(__invalidated, property);");
@@ -1345,17 +1379,38 @@ private void AppendPropertyTypes(string name, XElement interfaceXml, bool genera
13451379
StartBlock();
13461380
AppendLine("if (property != 0)");
13471381
StartBlock();
1348-
AppendLine("__invalidated |= Flag(property);");
1382+
if (useByteArray)
1383+
{
1384+
AppendLine("__invalidated[FlagIndex(property)] |= FlagMask(property);");
1385+
}
1386+
else
1387+
{
1388+
AppendLine("__invalidated |= Flag(property);");
1389+
}
13491390
EndBlock();
13501391
EndBlock();
13511392

1352-
AppendLine($"public bool AreAllPropertiesSet() => __set == PropertiesAllSet;");
1393+
if (useByteArray)
1394+
{
1395+
AppendLine($"public bool AreAllPropertiesSet() => __set.AsSpan().SequenceEqual(PropertiesAllSet);");
1396+
}
1397+
else
1398+
{
1399+
AppendLine($"public bool AreAllPropertiesSet() => __set == PropertiesAllSet;");
1400+
}
13531401

13541402
AppendLine("public void EnsureAllPropertiesSet()");
13551403
StartBlock();
13561404
AppendLine("if (!AreAllPropertiesSet())");
13571405
StartBlock();
1358-
AppendLine("throw new DBusUnexpectedValueException($\"Not all properties have been set (0x{__set:x}).\");");
1406+
if (useByteArray)
1407+
{
1408+
AppendLine("throw new DBusUnexpectedValueException($\"Not all properties have been set ({BitConverter.ToString(__set)}).\");");
1409+
}
1410+
else
1411+
{
1412+
AppendLine("throw new DBusUnexpectedValueException($\"Not all properties have been set (0x{__set:x}).\");");
1413+
}
13591414
EndBlock();
13601415
EndBlock();
13611416

@@ -1395,15 +1450,32 @@ private void AppendPropertyTypes(string name, XElement interfaceXml, bool genera
13951450
AppendLine("while (reader.HasNext(invalidatedEnd))");
13961451
StartBlock();
13971452
AppendLine("var propertyName = reader.ReadString();");
1398-
AppendLine("props.__invalidated |= propertyName switch");
1399-
StartBlock();
1400-
foreach (var property in readableProperties)
1453+
if (useByteArray)
14011454
{
1402-
AppendLine($"\"{property.Name}\" => Flag({propertyEnumName}.{property.NameUpper}),");
1455+
AppendLine("switch (propertyName)");
1456+
StartBlock();
1457+
foreach (var property in readableProperties)
1458+
{
1459+
AppendLine($"case \"{property.Name}\":");
1460+
_indentation++;
1461+
AppendLine($"props.__invalidated[FlagIndex({propertyEnumName}.{property.NameUpper})] |= FlagMask({propertyEnumName}.{property.NameUpper});");
1462+
AppendLine("break;");
1463+
_indentation--;
1464+
}
1465+
EndBlock();
1466+
}
1467+
else
1468+
{
1469+
AppendLine("props.__invalidated |= propertyName switch");
1470+
StartBlock();
1471+
foreach (var property in readableProperties)
1472+
{
1473+
AppendLine($"\"{property.Name}\" => Flag({propertyEnumName}.{property.NameUpper}),");
1474+
}
1475+
AppendLine("_ => 0");
1476+
_indentation--;
1477+
AppendLine("};");
14031478
}
1404-
AppendLine("_ => 0");
1405-
_indentation--;
1406-
AppendLine("};");
14071479
EndBlock(); // while
14081480
EndBlock(); // if
14091481

test/Tmds.DBus.Generator.Tests/CodeGenerationTests.VerifyGeneratedOutput_HandlerOnly.verified.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Generated by Tmds.DBus.Generator v0.94.1
1+
// Generated by Tmds.DBus.Generator v0.94.2
22
// <auto-generated/>
33
#nullable enable
44
namespace TestNamespace
@@ -958,7 +958,7 @@ namespace TestNamespace
958958
}
959959
}
960960

961-
// Generated by Tmds.DBus.Generator v0.94.1
961+
// Generated by Tmds.DBus.Generator v0.94.2
962962
// <auto-generated/>
963963
#nullable enable
964964
namespace Tmds.DBus.Protocol

0 commit comments

Comments
 (0)