@@ -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 ));
0 commit comments