Skip to content

Commit dc55547

Browse files
author
Vadim Platonov
committed
[Rust] Handle messages with blockLength > fixed field size
1 parent 5f0a7ba commit dc55547

File tree

3 files changed

+52
-11
lines changed

3 files changed

+52
-11
lines changed

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

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,18 @@ void appendDirectCodeMethods(
4444
final String methodName,
4545
final String representationType,
4646
final String nextCoderType,
47-
final int numBytes) throws IOException
47+
final int numBytes,
48+
final int trailingBytes) throws IOException
4849
{
4950
indent(appendable, 1, "pub fn %s(mut self) -> CodecResult<(&%s %s, %s)> {\n",
5051
methodName, DATA_LIFETIME, representationType, RustGenerator.withLifetime(nextCoderType));
5152
indent(appendable, 2, "let v = self.%s.read_type::<%s>(%s)?;\n",
5253
RustCodecType.Decoder.scratchProperty(), representationType, numBytes);
54+
if (trailingBytes > 0)
55+
{
56+
indent(appendable, 2, "self.%s.skip_bytes(%s)?;\n",
57+
RustCodecType.Decoder.scratchProperty(), trailingBytes);
58+
}
5359
indent(appendable, 2, "Ok((v, %s::wrap(self.%s)))\n",
5460
nextCoderType, RustCodecType.Decoder.scratchProperty());
5561
indent(appendable).append("}\n");
@@ -78,15 +84,20 @@ void appendDirectCodeMethods(
7884
final String methodName,
7985
final String representationType,
8086
final String nextCoderType,
81-
final int numBytes) throws IOException
87+
final int numBytes,
88+
final int trailingBytes) throws IOException
8289
{
8390
indent(appendable, 1, "\n/// Create a mutable struct reference overlaid atop the data buffer\n");
8491
indent(appendable, 1, "/// such that changes to the struct directly edit the buffer. \n");
8592
indent(appendable, 1, "/// Note that the initial content of the struct's fields may be garbage.\n");
8693
indent(appendable, 1, "pub fn %s(mut self) -> CodecResult<(&%s mut %s, %s)> {\n",
8794
methodName, DATA_LIFETIME, representationType, RustGenerator.withLifetime(nextCoderType));
88-
indent(appendable, 2, "let v = self.%s.writable_overlay::<%s>(%s)?;\n",
89-
RustCodecType.Encoder.scratchProperty(), representationType, numBytes);
95+
if (trailingBytes > 0)
96+
{
97+
indent(appendable, 2, "// add trailing bytes to extend the end position of the scratch buffer\n");
98+
}
99+
indent(appendable, 2, "let v = self.%s.writable_overlay::<%s>(%s+%s)?;\n",
100+
RustCodecType.Encoder.scratchProperty(), representationType, numBytes, trailingBytes);
90101
indent(appendable, 2, "Ok((v, %s::wrap(self.%s)))\n",
91102
nextCoderType, RustCodecType.Encoder.scratchProperty());
92103
indent(appendable).append("}\n\n");
@@ -97,6 +108,12 @@ void appendDirectCodeMethods(
97108
indent(appendable, 2)
98109
.append(format("self.%s.write_type::<%s>(t, %s)?;\n",
99110
RustCodecType.Encoder.scratchProperty(), representationType, numBytes));
111+
if (trailingBytes > 0)
112+
{
113+
indent(appendable, 2, "// fixed message length > sum of field lengths\n");
114+
indent(appendable, 2, "self.%s.skip_bytes(%s)?;\n",
115+
RustCodecType.Decoder.scratchProperty(), trailingBytes);
116+
}
100117
indent(appendable, 2).append(format("Ok(%s::wrap(self.%s))\n",
101118
nextCoderType, RustCodecType.Encoder.scratchProperty()));
102119
indent(appendable).append("}\n");
@@ -125,7 +142,8 @@ abstract void appendDirectCodeMethods(
125142
String methodName,
126143
String representationType,
127144
String nextCoderType,
128-
int numBytes) throws IOException;
145+
int numBytes,
146+
int trailingBytes) throws IOException;
129147

130148
abstract String gerund();
131149

@@ -175,7 +193,7 @@ String generateMessageHeaderCoder(
175193
appendScratchWrappingStruct(writer, headerCoderType);
176194
RustGenerator.appendImplWithLifetimeHeader(writer, headerCoderType);
177195
appendWrapMethod(writer, headerCoderType);
178-
appendDirectCodeMethods(writer, "header", messageHeaderRepresentation, topType, headerSize);
196+
appendDirectCodeMethods(writer, "header", messageHeaderRepresentation, topType, headerSize, 0);
179197
writer.append("}\n");
180198
}
181199

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

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ private static void generateMessageEncoder(
212212
String topType = codecType.generateDoneCoderType(outputManager, messageTypeName);
213213
topType = generateTopVarDataCoders(messageTypeName, components.varData, outputManager, topType, codecType);
214214
topType = generateGroupsCoders(groupTree, outputManager, topType, codecType);
215-
topType = generateFixedFieldCoder(messageTypeName, outputManager, topType, fieldStruct, codecType);
215+
topType = generateFixedFieldCoder(messageTypeName, msgToken.encodedLength(), outputManager, topType, fieldStruct, codecType);
216216
topType = codecType.generateMessageHeaderCoder(messageTypeName, outputManager, topType, headerSize);
217217
generateEntryPoint(messageTypeName, outputManager, topType, codecType);
218218
}
@@ -231,7 +231,7 @@ private static void generateMessageDecoder(
231231
String topType = codecType.generateDoneCoderType(outputManager, messageTypeName);
232232
topType = generateTopVarDataCoders(messageTypeName, components.varData, outputManager, topType, codecType);
233233
topType = generateGroupsCoders(groupTree, outputManager, topType, codecType);
234-
topType = generateFixedFieldCoder(messageTypeName, outputManager, topType, fieldStruct, codecType);
234+
topType = generateFixedFieldCoder(messageTypeName, msgToken.encodedLength(), outputManager, topType, fieldStruct, codecType);
235235
topType = codecType.generateMessageHeaderCoder(messageTypeName, outputManager, topType, headerSize);
236236
generateEntryPoint(messageTypeName, outputManager, topType, codecType);
237237
}
@@ -262,6 +262,7 @@ static String withLifetime(final String typeName)
262262

263263
private static String generateFixedFieldCoder(
264264
final String messageTypeName,
265+
final int messageEncodedLength,
265266
final OutputManager outputManager,
266267
final String topType,
267268
final RustStruct fieldStruct,
@@ -274,10 +275,9 @@ private static String generateFixedFieldCoder(
274275
appendImplWithLifetimeHeader(writer, decoderName);
275276
codecType.appendWrapMethod(writer, decoderName);
276277
codecType.appendDirectCodeMethods(writer, formatMethodName(messageTypeName) + "_fields",
277-
fieldStruct.name, topType, fieldStruct.sizeBytes());
278+
fieldStruct.name, topType, fieldStruct.sizeBytes(),
279+
messageEncodedLength - fieldStruct.sizeBytes());
278280
writer.append("}\n");
279-
// TODO - Move read position further if in-message blockLength exceeds fixed fields representation size
280-
// will require piping some data from the previously-read message header
281281
return decoderName;
282282
}
283283
}
@@ -1151,6 +1151,18 @@ static void generateEncoderScratchStruct(final Ir ir, final OutputManager output
11511151
indent(writer, 2).append("}\n");
11521152
indent(writer).append("}\n\n");
11531153

1154+
indent(writer, 1, "/// Advances the `pos` index by a set number of bytes.\n");
1155+
indent(writer).append("#[inline]\n");
1156+
indent(writer).append("fn skip_bytes(&mut self, num_bytes: usize) -> CodecResult<()> {\n");
1157+
indent(writer, 2).append("let end = self.pos + num_bytes;\n");
1158+
indent(writer, 2).append("if end <= self.data.len() {\n");
1159+
indent(writer, 3).append("self.pos = end;\n");
1160+
indent(writer, 3).append("Ok(())\n");
1161+
indent(writer, 2).append("} else {\n");
1162+
indent(writer, 3).append("Err(CodecErr::NotEnoughBytes)\n");
1163+
indent(writer, 2).append("}\n");
1164+
indent(writer).append("}\n\n");
1165+
11541166
indent(writer, 1, "/// Create a struct reference overlaid atop the data buffer\n");
11551167
indent(writer, 1, "/// such that changes to the struct directly edit the buffer. \n");
11561168
indent(writer, 1, "/// Note that the initial content of the struct's fields may be garbage.\n");

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,17 @@ public void messageWithOffsets()
306306
assertContains(rust, expectedHeader);
307307
}
308308

309+
@Test
310+
public void messageBlockLengthExceedingSumOfFieldLengths()
311+
{
312+
final String rust = fullGenerateForResource(outputManager, "message-block-length-test");
313+
final String expectedEncoderSegment = "let v = self.scratch.writable_overlay::<MsgNameFields>(9+2)?;";
314+
assertContains(rust, expectedEncoderSegment);
315+
final String expectedDecoderSegment = "let v = self.scratch.read_type::<MsgNameFields>(9)?;\n" +
316+
" self.scratch.skip_bytes(2)?;";
317+
assertContains(rust, expectedDecoderSegment);
318+
}
319+
309320
@Test
310321
public void constantEnumFields() throws IOException, InterruptedException
311322
{

0 commit comments

Comments
 (0)