Skip to content

Commit 25ef95f

Browse files
author
Vadim Platonov
committed
[Rust] Derive Default when possible
1 parent 7278e18 commit 25ef95f

File tree

2 files changed

+61
-28
lines changed

2 files changed

+61
-28
lines changed

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

Lines changed: 59 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ private void generateGroupFieldRepresentations(
106106
{
107107
final RustStruct struct = RustStruct.fromTokens(node.contextualName + "Member",
108108
node.simpleNamedFields,
109-
EnumSet.of(RustStruct.Modifier.PACKED));
109+
EnumSet.of(RustStruct.Modifier.PACKED, RustStruct.Modifier.DEFAULT));
110110
struct.appendDefinitionTo(appendable);
111111

112112
generateConstantAccessorImpl(appendable, node.contextualName + "Member", node.rawFields);
@@ -124,7 +124,7 @@ private static RustStruct generateMessageFieldStruct(
124124

125125
final String representationStruct = messageTypeName + "Fields";
126126
final RustStruct struct = RustStruct.fromTokens(representationStruct, namedFieldTokens,
127-
EnumSet.of(RustStruct.Modifier.PACKED));
127+
EnumSet.of(RustStruct.Modifier.PACKED, RustStruct.Modifier.DEFAULT));
128128

129129
try (Writer writer = outputManager.createOutput(
130130
messageTypeName + " Fixed-size Fields (" + struct.sizeBytes() + " bytes)"))
@@ -410,7 +410,7 @@ private static String writeGroupEncoderTopTypes(
410410
final String headerCoderType = node.contextualName + "HeaderEncoder";
411411
try (Writer out = outputManager.createOutput(node.contextualName + " Encoder for fields and header"))
412412
{
413-
appendStructHeader(out, withLifetime(memberCoderType), false);
413+
appendStructHeader(out, withLifetime(memberCoderType));
414414
final String rustCountType = rustTypeName(node.dimensionsNumInGroupType());
415415
final String contentProperty;
416416
final String contentBearingType;
@@ -460,7 +460,7 @@ private static String writeGroupEncoderTopTypes(
460460
format("%s::wrap(self.%s)", afterGroupCoderType, contentProperty));
461461
indent(out).append("}\n").append("}\n");
462462

463-
appendStructHeader(out, withLifetime(headerCoderType), false);
463+
appendStructHeader(out, withLifetime(headerCoderType));
464464
indent(out, 1, "%s: %s,\n", contentProperty, contentBearingType);
465465
out.append("}\n");
466466

@@ -558,7 +558,7 @@ private static void writeGroupDecoderTopTypes(
558558
{
559559
try (Writer out = outputManager.createOutput(node.contextualName + " Decoder for fields and header"))
560560
{
561-
appendStructHeader(out, withLifetime(memberDecoderType), false);
561+
appendStructHeader(out, withLifetime(memberDecoderType));
562562
final String rustCountType = rustTypeName(node.dimensionsNumInGroupType());
563563
final String contentProperty;
564564
final String contentBearingType;
@@ -609,7 +609,7 @@ private static void writeGroupDecoderTopTypes(
609609
format("%s::wrap(self.%s)", initialNextDecoderType, contentProperty)));
610610
indent(out, 2).append("}\n").append(INDENT).append("}\n").append("}\n");
611611

612-
appendStructHeader(out, withLifetime(headerDecoderType), false);
612+
appendStructHeader(out, withLifetime(headerDecoderType));
613613
indent(out, 1, "%s: %s,\n", contentProperty, contentBearingType).append("}\n");
614614

615615
appendImplWithLifetimeHeader(out, headerDecoderType);
@@ -922,7 +922,7 @@ String generateVarDataEncoder(
922922
final String decoderType = parentContextualName + formatTypeName(name) + codecType.name();
923923
try (Writer writer = outputManager.createOutput(name + " variable-length data"))
924924
{
925-
appendStructHeader(writer, withLifetime(decoderType), false);
925+
appendStructHeader(writer, withLifetime(decoderType));
926926
final String contentPropertyName = groupDepth > 0 ? "parent" : codecType.scratchProperty();
927927
indent(writer, 1, "%s: %s,\n", contentPropertyName, withLifetime(contentType));
928928
writer.append("}\n");
@@ -973,7 +973,7 @@ String generateVarDataDecoder(
973973
final String decoderType = parentContextualName + formatTypeName(name) + "Decoder";
974974
try (Writer writer = outputManager.createOutput(name + " variable-length data"))
975975
{
976-
appendStructHeader(writer, withLifetime(decoderType), false);
976+
appendStructHeader(writer, withLifetime(decoderType));
977977
final String contentPropertyName = groupDepth > 0 ? "parent" : SCRATCH_DECODER_PROPERTY;
978978
indent(writer, 1, "%s: %s,\n", contentPropertyName, withLifetime(contentType));
979979
writer.append("}\n");
@@ -1402,7 +1402,7 @@ private static void generateSingleComposite(final List<Token> tokens, final Outp
14021402
{
14031403
final RustStruct struct = RustStruct.fromTokens(formattedTypeName,
14041404
splitTokens.nonConstantEncodingTokens(),
1405-
EnumSet.of(RustStruct.Modifier.PACKED));
1405+
EnumSet.of(RustStruct.Modifier.PACKED, RustStruct.Modifier.DEFAULT));
14061406
struct.appendDefinitionTo(writer);
14071407

14081408
generateConstantAccessorImpl(writer, formattedTypeName, getMessageBody(tokens));
@@ -1411,6 +1411,8 @@ private static void generateSingleComposite(final List<Token> tokens, final Outp
14111411

14121412
private interface RustTypeDescriptor
14131413
{
1414+
String DEFAULT_VALUE = "Default::default()";
1415+
14141416
String name();
14151417

14161418
String literalValue(String valueRep);
@@ -1419,7 +1421,7 @@ private interface RustTypeDescriptor
14191421

14201422
default String defaultValue()
14211423
{
1422-
return "Default::default()";
1424+
return DEFAULT_VALUE;
14231425
}
14241426
}
14251427

@@ -1571,7 +1573,7 @@ private static final class RustStruct
15711573
{
15721574
enum Modifier
15731575
{
1574-
PACKED
1576+
PACKED, DEFAULT
15751577
}
15761578

15771579
final String name;
@@ -1598,7 +1600,7 @@ static RustStruct fromHeader(final HeaderStructure header)
15981600
final SplitCompositeTokens splitTokens = SplitCompositeTokens.splitInnerTokens(tokens);
15991601
return RustStruct.fromTokens(formattedTypeName,
16001602
splitTokens.nonConstantEncodingTokens(),
1601-
EnumSet.of(RustStruct.Modifier.PACKED));
1603+
EnumSet.of(Modifier.PACKED, Modifier.DEFAULT));
16021604
}
16031605

16041606
static RustStruct fromTokens(final String name, final List<NamedToken> tokens,
@@ -1609,13 +1611,13 @@ static RustStruct fromTokens(final String name, final List<NamedToken> tokens,
16091611

16101612
// No way to create struct with default values.
16111613
// Rust RFC: https://github.com/Centril/rfcs/pull/19
1612-
// TODO: #[derive(Default)] ?
1614+
// Used when struct contains a field which doesn't have a Default impl
16131615
void appendDefaultConstructorTo(final Appendable appendable) throws IOException
16141616
{
16151617
indent(appendable, 0, "impl Default for %s {\n", name);
16161618
indent(appendable, 1, "fn default() -> Self {\n");
16171619

1618-
appendInstanceTo(appendable, 2);
1620+
appendInstanceTo(appendable, 2, Collections.emptyMap());
16191621

16201622
indent(appendable, 1, "}\n");
16211623

@@ -1624,7 +1626,17 @@ void appendDefaultConstructorTo(final Appendable appendable) throws IOException
16241626

16251627
void appendDefinitionTo(final Appendable appendable) throws IOException
16261628
{
1627-
appendStructHeader(appendable, name, modifiers.contains(Modifier.PACKED));
1629+
final boolean needsDefault = modifiers.contains(Modifier.DEFAULT);
1630+
final boolean canDeriveDefault = fields.stream()
1631+
.allMatch(v -> v.type.defaultValue() == RustTypeDescriptor.DEFAULT_VALUE);
1632+
1633+
final Set<Modifier> modifiers = this.modifiers.clone();
1634+
if (needsDefault && !canDeriveDefault)
1635+
{
1636+
modifiers.remove(Modifier.DEFAULT);
1637+
}
1638+
1639+
appendStructHeader(appendable, name, modifiers);
16281640
for (final RustStructField field: fields)
16291641
{
16301642
indent(appendable);
@@ -1635,12 +1647,11 @@ void appendDefinitionTo(final Appendable appendable) throws IOException
16351647
appendable.append(field.name).append(":").append(field.type.name()).append(",\n");
16361648
}
16371649
appendable.append("}\n");
1638-
appendDefaultConstructorTo(appendable);
1639-
}
16401650

1641-
void appendInstanceTo(final Appendable appendable, final int indent) throws IOException
1642-
{
1643-
appendInstanceTo(appendable, indent, Collections.emptyMap());
1651+
if (needsDefault && !canDeriveDefault)
1652+
{
1653+
appendDefaultConstructorTo(appendable);
1654+
}
16441655
}
16451656

16461657
void appendInstanceTo(final Appendable appendable, final int indent,
@@ -1708,8 +1719,18 @@ private static List<RustStructField> collectStructFields(final List<NamedToken>
17081719
final int offset = typeToken.offset();
17091720
if (offset != totalSize)
17101721
{
1711-
final RustTypeDescriptor type = RustTypes.arrayOf(RustTypes.U_8, offset - totalSize);
1712-
fields.add(new RustStructField(propertyName + "_padding", type));
1722+
int rem = offset - totalSize;
1723+
int idx = 1;
1724+
while (rem > 0)
1725+
{
1726+
// split padding arrays to 32 as larger arrays do not have an `impl Default`
1727+
final int padding = Math.min(rem, 32);
1728+
final RustTypeDescriptor type = RustTypes.arrayOf(RustTypes.U_8, padding);
1729+
fields.add(new RustStructField(propertyName + "_padding_" + idx, type));
1730+
1731+
idx += 1;
1732+
rem -= padding;
1733+
}
17131734
}
17141735
totalSize = offset + typeToken.encodedLength();
17151736

@@ -1750,7 +1771,7 @@ private void generateMessageHeaderDefault(
17501771

17511772
try (Writer writer = outputManager.createOutput(messageTypeName + " specific Message Header "))
17521773
{
1753-
appendStructHeader(writer, wrapperName, true);
1774+
appendStructHeader(writer, wrapperName, EnumSet.of(RustStruct.Modifier.PACKED));
17541775
indent(writer, 1, "pub message_header: MessageHeader\n");
17551776
writer.append("}\n");
17561777

@@ -1777,14 +1798,26 @@ private void generateMessageHeaderDefault(
17771798
}
17781799
}
17791800

1801+
private static void appendStructHeader(final Appendable appendable, final String structName) throws IOException
1802+
{
1803+
appendStructHeader(appendable, structName, EnumSet.noneOf(RustStruct.Modifier.class));
1804+
}
1805+
17801806
private static void appendStructHeader(
17811807
final Appendable appendable,
17821808
final String structName,
1783-
final boolean packedCRepresentation) throws IOException
1809+
final Set<RustStruct.Modifier> modifiers) throws IOException
17841810
{
1785-
if (packedCRepresentation)
1811+
if (!modifiers.isEmpty())
17861812
{
1787-
appendable.append("#[repr(C,packed)]\n");
1813+
if (modifiers.contains(RustStruct.Modifier.PACKED))
1814+
{
1815+
appendable.append("#[repr(C,packed)]\n");
1816+
}
1817+
if (modifiers.contains(RustStruct.Modifier.DEFAULT))
1818+
{
1819+
appendable.append("#[derive(Default)]\n");
1820+
}
17881821
}
17891822

17901823
appendable.append(format("pub struct %s {\n", structName));

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -301,9 +301,9 @@ public void messageWithOffsets()
301301
final String expectedHeader =
302302
"pub struct MessageHeader {\n" +
303303
" pub block_length:u16,\n" +
304-
" template_id_padding:[u8;2],\n" +
304+
" template_id_padding_1:[u8;2],\n" +
305305
" pub template_id:u16,\n" +
306-
" schema_id_padding:[u8;2],\n" +
306+
" schema_id_padding_1:[u8;2],\n" +
307307
" pub schema_id:u16,\n" +
308308
" pub version:u16,\n" +
309309
"}";

0 commit comments

Comments
 (0)