Skip to content

Commit 02437c8

Browse files
author
Vadim Platonov
committed
[Rust] Pad struct fields - basic AST
1 parent c85dd0b commit 02437c8

File tree

2 files changed

+183
-33
lines changed

2 files changed

+183
-33
lines changed

sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java

Lines changed: 164 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,10 @@ private void generateGroupFieldRepresentations(
106106
{
107107
for (final GroupTreeNode node : groupTree)
108108
{
109-
appendStructHeader(appendable, node.contextualName + "Member", true);
110-
appendStructFields(appendable, node.simpleNamedFields);
111-
appendable.append("}\n");
109+
final RustStruct struct = RustStruct.fromTokens(node.contextualName + "Member",
110+
node.simpleNamedFields,
111+
EnumSet.of(RustStruct.Modifier.PACKED));
112+
struct.appendDefinitionTo(appendable);
112113

113114
generateConstantAccessorImpl(appendable, node.contextualName + "Member", node.rawFields);
114115

@@ -138,9 +139,10 @@ private static Optional<FieldsRepresentationSummary> generateFieldsRepresentatio
138139
final String representationStruct = messageTypeName + "Fields";
139140
try (Writer writer = outputManager.createOutput(messageTypeName + " Fixed-size Fields"))
140141
{
141-
appendStructHeader(writer, representationStruct, true);
142-
appendStructFields(writer, namedFieldTokens);
143-
writer.append("}\n");
142+
final RustStruct struct = RustStruct.fromTokens(representationStruct, namedFieldTokens,
143+
EnumSet.of(RustStruct.Modifier.PACKED));
144+
struct.appendDefinitionTo(writer);
145+
writer.append("\n");
144146

145147
generateConstantAccessorImpl(writer, representationStruct, components.fields);
146148
}
@@ -1391,29 +1393,166 @@ private static void generateSingleComposite(final List<Token> tokens, final Outp
13911393

13921394
try (Writer writer = outputManager.createOutput(formattedTypeName))
13931395
{
1394-
appendStructHeader(writer, formattedTypeName, true);
1395-
appendStructFields(writer, splitTokens.nonConstantEncodingTokens());
1396-
writer.append("}\n");
1396+
final RustStruct struct = RustStruct.fromTokens(formattedTypeName,
1397+
splitTokens.nonConstantEncodingTokens(),
1398+
EnumSet.of(RustStruct.Modifier.PACKED));
1399+
struct.appendDefinitionTo(writer);
13971400

13981401
generateConstantAccessorImpl(writer, formattedTypeName, getMessageBody(tokens));
13991402
}
14001403
}
14011404

1405+
private interface RustTypeDescriptor
1406+
{
1407+
String name();
1408+
String literal(String valueRep);
1409+
}
1410+
1411+
private static final class RustArrayType implements RustTypeDescriptor
1412+
{
1413+
private final RustTypeDescriptor componentType;
1414+
private final int length;
1415+
1416+
private RustArrayType(RustTypeDescriptor component, int length) {
1417+
this.componentType = component;
1418+
this.length = length;
1419+
}
1420+
1421+
@Override
1422+
public String name()
1423+
{
1424+
return getRustStaticArrayString(componentType.name(), length);
1425+
}
1426+
1427+
@Override
1428+
public String literal(String valueRep)
1429+
{
1430+
return getRustStaticArrayString(valueRep + componentType.name(), length);
1431+
}
1432+
}
1433+
1434+
private static final class RustPrimitiveType implements RustTypeDescriptor
1435+
{
1436+
private final String name;
1437+
1438+
private RustPrimitiveType(String name) {
1439+
this.name = name;
1440+
}
1441+
1442+
@Override
1443+
public String name()
1444+
{
1445+
return name;
1446+
}
1447+
1448+
@Override
1449+
public String literal(String valueRep)
1450+
{
1451+
return valueRep + name;
1452+
}
1453+
}
1454+
1455+
private static final class AnyRustType implements RustTypeDescriptor
1456+
{
1457+
private final String name;
1458+
1459+
private AnyRustType(String name) {
1460+
this.name = name;
1461+
}
1462+
1463+
@Override
1464+
public String name()
1465+
{
1466+
return name;
1467+
}
1468+
1469+
@Override
1470+
public String literal(String valueRep)
1471+
{
1472+
final String msg = String.format("Cannot produce a literal value %s of type %s!", valueRep, name);
1473+
throw new UnsupportedOperationException(msg);
1474+
}
1475+
}
1476+
1477+
private static final class RustTypes
1478+
{
1479+
static final RustTypeDescriptor u8 = new RustPrimitiveType("u8");
1480+
1481+
static RustTypeDescriptor ofPrimitiveToken(Token token)
1482+
{
1483+
final PrimitiveType primitiveType = token.encoding().primitiveType();
1484+
final String rustPrimitiveType = RustUtil.rustTypeName(primitiveType);
1485+
final RustPrimitiveType type = new RustPrimitiveType(rustPrimitiveType);
1486+
if (token.arrayLength() > 1) {
1487+
return new RustArrayType(type, token.arrayLength());
1488+
}
1489+
return type;
1490+
}
1491+
1492+
static RustTypeDescriptor ofGeneratedToken(Token token)
1493+
{
1494+
return new AnyRustType(formatTypeName(token.applicableTypeName()));
1495+
}
1496+
1497+
static RustTypeDescriptor arrayOf(RustTypeDescriptor type, int len)
1498+
{
1499+
return new RustArrayType(type, len);
1500+
}
1501+
}
1502+
1503+
private static final class RustStruct
1504+
{
1505+
enum Modifier {
1506+
PACKED
1507+
}
1508+
1509+
final String name;
1510+
final List<RustStructField> fields;
1511+
final EnumSet<Modifier> modifiers;
1512+
1513+
private RustStruct(String name, List<RustStructField> fields, EnumSet<Modifier> modifiers) {
1514+
this.name = name;
1515+
this.fields = fields;
1516+
this.modifiers = modifiers;
1517+
}
1518+
1519+
public static RustStruct fromTokens(String name, List<NamedToken> tokens, EnumSet<Modifier> modifiers) {
1520+
return new RustStruct(name, collectStructFields(tokens), modifiers);
1521+
}
1522+
1523+
void appendDefinitionTo(final Appendable appendable) throws IOException {
1524+
appendStructHeader(appendable, name, modifiers.contains(Modifier.PACKED));
1525+
for (RustStructField field: fields) {
1526+
indent(appendable);
1527+
if (field.modifiers.contains(RustStructField.Modifier.PUBLIC)) appendable.append("pub ");
1528+
appendable.append(field.name).append(":").append(field.type.name()).append(",\n");
1529+
}
1530+
appendable.append("}");
1531+
}
1532+
}
1533+
14021534
private static final class RustStructField
14031535
{
1404-
final boolean isPub;
1536+
enum Modifier {
1537+
PUBLIC
1538+
}
1539+
14051540
final String name;
1406-
final String value;
1541+
final RustTypeDescriptor type;
1542+
final EnumSet<Modifier> modifiers;
14071543

1408-
private RustStructField(boolean isPub, String name, String value) {
1409-
this.isPub = isPub;
1544+
private RustStructField(String name, RustTypeDescriptor type, EnumSet<Modifier> modifiers) {
14101545
this.name = name;
1411-
this.value = value;
1546+
this.type = type;
1547+
this.modifiers = modifiers;
1548+
}
1549+
1550+
private RustStructField(String name, RustTypeDescriptor type) {
1551+
this(name, type, EnumSet.noneOf(Modifier.class));
14121552
}
14131553
}
14141554

1415-
private static void appendStructFields(final Appendable appendable, final List<NamedToken> namedTokens)
1416-
throws IOException
1555+
private static List<RustStructField> collectStructFields(final List<NamedToken> namedTokens)
14171556
{
14181557
final List<RustStructField> fields = new ArrayList<>();
14191558
int totalSize = 0;
@@ -1430,37 +1569,32 @@ private static void appendStructFields(final Appendable appendable, final List<N
14301569
// need padding when field offsets imply gaps
14311570
final int offset = typeToken.offset();
14321571
if (offset != totalSize) {
1433-
final String value = getRustStaticArrayString("u8", offset - totalSize);
1434-
fields.add(new RustStructField(false, propertyName + "_padding", value));
1572+
final RustTypeDescriptor type = RustTypes.arrayOf(RustTypes.u8, offset - totalSize);
1573+
fields.add(new RustStructField(propertyName + "_padding", type));
14351574
}
1436-
totalSize += typeToken.encodedLength();
1575+
totalSize = offset + typeToken.encodedLength();
14371576

1577+
final RustTypeDescriptor type;
14381578
switch (typeToken.signal())
14391579
{
14401580
case ENCODING:
1441-
final String rustPrimitiveType = RustUtil.rustTypeName(typeToken.encoding().primitiveType());
1442-
final String rustFieldType = getRustTypeForPrimitivePossiblyArray(typeToken, rustPrimitiveType);
1443-
fields.add(new RustStructField(true, propertyName, rustFieldType));
1581+
type = RustTypes.ofPrimitiveToken(typeToken);
1582+
fields.add(new RustStructField(propertyName, type, EnumSet.of(RustStructField.Modifier.PUBLIC)));
14441583
break;
14451584

14461585
case BEGIN_ENUM:
14471586
case BEGIN_SET:
14481587
case BEGIN_COMPOSITE:
1449-
fields.add(new RustStructField(true, propertyName, formatTypeName(typeToken.applicableTypeName())));
1588+
type = RustTypes.ofGeneratedToken(typeToken);
1589+
fields.add(new RustStructField(propertyName, type, EnumSet.of(RustStructField.Modifier.PUBLIC)));
14501590
break;
14511591

14521592
default:
14531593
throw new IllegalStateException(
14541594
format("Unsupported struct property from %s", typeToken.toString()));
14551595
}
1456-
1457-
for (RustStructField field: fields) {
1458-
indent(appendable);
1459-
if (field.isPub) appendable.append("pub ");
1460-
appendable.append(field.name).append(":").append(field.value).append(",\n");
1461-
}
1462-
fields.clear();
14631596
}
1597+
return fields;
14641598
}
14651599

14661600
private void generateMessageHeaderDefault(

sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustGeneratorTest.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,14 +187,26 @@ private File writeCargoFolderWrapper(final String name, final String generatedRu
187187
return folder;
188188
}
189189

190-
private static boolean cargoCheckInDirectory(final File folder) throws IOException, InterruptedException
190+
private static class CargoCheckResult
191+
{
192+
final boolean isSuccess;
193+
final String error;
194+
195+
private CargoCheckResult(boolean isSuccess, String error) {
196+
this.isSuccess = isSuccess;
197+
this.error = error;
198+
}
199+
}
200+
201+
private static CargoCheckResult cargoCheckInDirectory(final File folder) throws IOException, InterruptedException
191202
{
192203
final ProcessBuilder builder = new ProcessBuilder("cargo", "check");
193204
builder.directory(folder);
194205
final Process process = builder.start();
195206
process.waitFor(30, TimeUnit.SECONDS);
196207
final boolean success = process.exitValue() == 0;
197208

209+
final StringBuilder errorString = new StringBuilder();
198210
if (!success)
199211
{
200212
// Include output as a debugging aid when things go wrong
@@ -206,12 +218,15 @@ private static boolean cargoCheckInDirectory(final File folder) throws IOExcepti
206218
if (line == null)
207219
{
208220
break;
221+
} else {
222+
errorString.append(line);
223+
errorString.append('\n');
209224
}
210225
}
211226
}
212227
}
213228

214-
return success;
229+
return new CargoCheckResult(success, errorString.toString());
215230
}
216231

217232
private static boolean cargoExists()
@@ -234,7 +249,8 @@ private void assertRustBuildable(final String generatedRust, final Optional<Stri
234249
{
235250
Assume.assumeTrue(cargoExists());
236251
final File folder = writeCargoFolderWrapper(name.orElse("test"), generatedRust, folderRule.newFolder());
237-
assertTrue(String.format("Generated Rust (%s) should be buildable with cargo", name), cargoCheckInDirectory(folder));
252+
final CargoCheckResult result = cargoCheckInDirectory(folder);
253+
assertTrue(String.format("Generated Rust (%s) should be buildable with cargo", name) + result.error, result.isSuccess);
238254
}
239255

240256
private void assertSchemaInterpretableAsRust(final String localResourceSchema)

0 commit comments

Comments
 (0)