From c3079e1e84465d0d3319f6eff9cb4af8820476b7 Mon Sep 17 00:00:00 2001 From: "marcio.andrade" Date: Tue, 18 Feb 2025 08:59:36 -0300 Subject: [PATCH 01/25] Save progress --- .../sbe/generation/rust/LibRsDef.java | 19 +- .../sbe/generation/rust/MessageCoderDef.java | 9 +- .../sbe/generation/rust/RustGenerator.java | 250 +++++++++++++++++- .../sbe/generation/rust/RustUtil.java | 140 ++++++++-- .../sbe/generation/rust/SubGroup.java | 5 +- 5 files changed, 393 insertions(+), 30 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index f361397916..3c823654de 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -69,6 +69,8 @@ void generate(final Ir ir) throws IOException indent(libRs, 0, "#![allow(clippy::all)]\n"); indent(libRs, 0, "#![allow(non_camel_case_types)]\n\n"); indent(libRs, 0, "#![allow(ambiguous_glob_reexports)]\n\n"); + indent(libRs, 0, "#![allow(unused_mut)]\n\n"); + indent(libRs, 0, "#![allow(dropping_references)]\n\n"); indent(libRs, 0, "use ::core::{convert::TryInto};\n\n"); final ArrayList modules = new ArrayList<>(); @@ -76,10 +78,10 @@ void generate(final Ir ir) throws IOException { walk .filter(Files::isRegularFile) - .map((path) -> path.getFileName().toString()) - .filter((fileName) -> fileName.endsWith(".rs")) - .filter((fileName) -> !fileName.equals("lib.rs")) - .map((fileName) -> fileName.substring(0, fileName.length() - 3)) + .map(path -> path.getFileName().toString()) + .filter(fileName -> fileName.endsWith(".rs")) + .filter(fileName -> !fileName.equals("lib.rs")) + .map(fileName -> fileName.substring(0, fileName.length() - 3)) .sorted() .forEach(modules::add); } @@ -98,7 +100,7 @@ void generate(final Ir ir) throws IOException generateEncoderTraits(libRs); generateDecoderTraits(schemaVersionType, libRs); - + generateHumanReadableTrait(libRs); generateReadBuf(libRs, byteOrder); generateWriteBuf(libRs, byteOrder); } @@ -132,6 +134,13 @@ static void generateDecoderTraits(final String schemaVersionType, final Writer w indent(writer, 0, "}\n\n"); } + static void generateHumanReadableTrait(final Writer writer) throws IOException + { + indent(writer, 0, "pub trait HumanReadable: Sized {\n"); + indent(writer, 1, "fn human_readable(self) -> SbeResult<(Self, String)>;\n"); + indent(writer, 0, "}\n\n"); + } + static void generateSbeSchemaConsts(final Writer writer, final Ir ir) throws IOException { final String schemaIdType = rustTypeName(ir.headerStructure().schemaIdType()); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java index da9060b9a2..30cd7454cb 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java @@ -106,6 +106,12 @@ void generate( indent(sb, 1, "}\n\n"); // impl end + if (codecType == Encoder) //impl Display + { + } else { + RustGenerator.generateDecoderDisplay(sb, msgTypeName,msgToken.name(),fields, groups, varData, 1); + } + // append all subGroup generated code for (final SubGroup subGroup : subGroups) { @@ -120,7 +126,8 @@ void appendTo(final Appendable dest) throws IOException dest.append(sb); } - public SubGroup addSubGroup(final String name, final int level, final Token groupToken) + @Override + public SubGroup addSubGroup(final String name, final int level, final Token groupToken) { final SubGroup subGroup = new SubGroup(name, level, groupToken); subGroups.add(subGroup); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 32f1633178..69d923adc8 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -26,6 +26,7 @@ import uk.co.real_logic.sbe.ir.Ir; import uk.co.real_logic.sbe.ir.Signal; import uk.co.real_logic.sbe.ir.Token; +import uk.co.real_logic.sbe.ir.Encoding.Presence; import java.io.IOException; import java.io.UncheckedIOException; @@ -40,6 +41,7 @@ import static uk.co.real_logic.sbe.ir.GenerationUtil.collectFields; import static uk.co.real_logic.sbe.ir.GenerationUtil.collectGroups; import static uk.co.real_logic.sbe.ir.GenerationUtil.collectVarData; +import static uk.co.real_logic.sbe.ir.GenerationUtil.findEndSignal; import static uk.co.real_logic.sbe.ir.Signal.BEGIN_ENUM; import static uk.co.real_logic.sbe.ir.Signal.BEGIN_SET; @@ -56,7 +58,8 @@ enum CodecType { Decoder { - String bufType() + @Override + String bufType() { return READ_BUF_TYPE; } @@ -64,7 +67,8 @@ String bufType() Encoder { - String bufType() + @Override + String bufType() { return WRITE_BUF_TYPE; } @@ -914,6 +918,12 @@ private static void generatePrimitiveRequiredDecoder( final PrimitiveType primitiveType = encoding.primitiveType(); final String rustPrimitiveType = rustTypeName(primitiveType); final String characterEncoding = encoding.characterEncoding(); + + // System.out.println("name: " + name); + // System.out.println("fieldToken: " + fieldToken.name()); + // System.out.println("primitiveType: " + primitiveType); + // System.out.println("rustPrimitiveType: " + rustPrimitiveType); + indent(sb, level, "/// primitive field - '%s'\n", encoding.presence()); if (characterEncoding != null) @@ -1720,10 +1730,38 @@ private static void generateCompositeDecoder( i += encodingToken.componentTokenCount(); } - indent(out, 1, "}\n"); // end impl + indent(out, 1, "}\n\n"); // end impl + + generateCompositeDecoderDisplay(out, decoderName, tokens, 1); + indent(out, 0, "} // end decoder mod \n"); } + private static void generateCompositeDecoderDisplay( + final Appendable writer, + final String decoderName, + final List tokens, + final int level) throws IOException { + indent(writer, level, "impl<'a, P> HumanReadable for %s

where P: Reader<'a> + ActingVersion + Default +'a {\n", decoderName); + indent(writer, level + 1, "fn human_readable(mut self) -> SbeResult<(Self, String)> {\n"); + + indent(writer, level + 2, "let mut str = String::new();\n"); + + // Start from 1 to the token of this own composite field. + for (int i = 1, size = tokens.size() - 1; i < size; ) { + final Token token = tokens.get(i); + final String fieldName = RustUtil.formatPropertyName(token.name()); + writeTokenDisplay(fieldName, token, writer, level + 2); + i += token.componentTokenCount(); + } + + indent(writer, level + 2, "str = str.trim_end_matches('%s').to_string();\n\n", Separator.FIELD); + + indent(writer, level + 2, "Ok((self, str))\n"); + indent(writer, level + 1, "}\n"); + indent(writer, level, "}\n"); + } + private static void appendConstAccessor( final Appendable writer, final String name, @@ -1736,4 +1774,210 @@ private static void appendConstAccessor( indent(writer, level + 1, rustExpression + "\n"); indent(writer, level, "}\n\n"); } + + static void generateDecoderDisplay( + final Appendable writer, + final String decoderName, + final String msgName, + final List fields, + final List groups, + final List varData, + final int level) throws IOException{ + if (msgName != null){ + indent(writer, level, "impl<'a> HumanReadable for %s<'a> {\n", decoderName); + } else { + indent(writer, level, "impl<'a, P> HumanReadable for %s

where P: Decoder<'a> + ActingVersion + Default +'a {\n", decoderName); + } + indent(writer, level + 1, "fn human_readable(mut self) -> SbeResult<(Self, String)> {\n"); + + + indent(writer, level + 2, "let mut str = String::new();\n"); + + if (msgName != null){ + indent(writer, level + 2, "let original_limit = self.get_limit();\n"); + indent(writer, level + 2, "self.set_limit(self.offset + self.acting_block_length as usize);\n\n"); + + indent(writer, level + 2, "str.push_str(\"[%s]\");\n\n", msgName); + + indent(writer, level + 2, "str.push('(');\n\n"); + + indent(writer, level + 2, "str.push_str(\"sbeTemplateId=\");\n"); + indent(writer, level + 2, "str.push_str(&SBE_TEMPLATE_ID.to_string());\n\n"); + + indent(writer, level + 2, "str.push_str(\"|sbeSchemaId=\");\n"); + indent(writer, level + 2, "str.push_str(&SBE_SCHEMA_ID.to_string());\n\n"); + + indent(writer, level + 2, "str.push_str(\"|sbeSchemaVersion=\");\n"); + indent(writer, level + 2, "if self.acting_version != SBE_SCHEMA_VERSION {\n"); + indent(writer, level + 3, "str.push_str(&self.acting_version.to_string());\n"); + indent(writer, level + 3, "str.push('/');\n"); + indent(writer, level + 2, "}\n"); + indent(writer, level + 2, "str.push_str(&SBE_SCHEMA_VERSION.to_string());\n\n"); + + indent(writer, level + 2, "str.push_str(\"|sbeBlockLength=\");\n"); + indent(writer, level + 2, "if self.acting_block_length != SBE_BLOCK_LENGTH {\n"); + indent(writer, level + 3, "str.push_str(&self.acting_block_length.to_string());\n"); + indent(writer, level + 3, "str.push('/');\n"); + indent(writer, level + 2, "}\n"); + indent(writer, level + 2, "str.push_str(&SBE_BLOCK_LENGTH.to_string());\n\n"); + + indent(writer, level + 2, "str.push_str(\"):\");\n\n"); + } + + indent(writer, level + 2, "// START FIELDS\n"); + for (int i = 0, size = fields.size(); i < size;) + { + final Token fieldToken = fields.get(i); + if (fieldToken.signal() == Signal.BEGIN_FIELD) + { + final Token encodingToken = fields.get(i + 1); + final String fieldName = RustUtil.formatPropertyName(fieldToken.name()); + writeTokenDisplay(fieldName, encodingToken, writer, level + 2); + + i += fieldToken.componentTokenCount(); + } + else + { + ++i; + } + } + indent(writer, level + 2, "// END FIELDS\n\n"); + + indent(writer, level + 2, "// START GROUPS\n"); + for (int i = 0, size = groups.size(); i < size; i++) + { + final Token groupToken = groups.get(i); + + if (groupToken.signal() != Signal.BEGIN_GROUP) + { + throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken); + } + + final String groupName = formatPropertyName(groupToken.name()); + + indent(writer, level + 2, "let mut %s = self.%s_decoder();\n", groupName, groupName); + indent(writer, level + 2, "str.push('%s');\n", Separator.BEGIN_GROUP); + indent(writer, level + 2, "let mut result = %s.human_readable()?;\n", groupName); + indent(writer, level + 2, "str.push_str(&result.1);\n"); + indent(writer, level + 2, "str.push('%s');\n", Separator.END_GROUP); + indent(writer, level + 2, "self = result.0.parent()?;\n"); + + i = findEndSignal(groups, i, Signal.END_GROUP, groupToken.name()); + } + indent(writer, level + 2, "// END GROUPS\n\n"); + + // indent(writer, level + 2, "// START VAR_DATA \n"); + // for (int i = 0, size = varData.size(); i < size;) + // { + // final Token varDataToken = varData.get(i); + // if (varDataToken.signal() != Signal.BEGIN_VAR_DATA) + // { + // throw new IllegalStateException("tokens must begin with BEGIN_VAR_DATA: token=" + varDataToken); + // } + + // final String characterEncoding = varData.get(i + 3).encoding().characterEncoding(); + // final String varDataName = formatPropertyName(varDataToken.name()); + + // indent(writer, level + 2, "str.push_str(\"%s%s\");\n", varDataName, Separator.KEY_VALUE); + + // indent(writer, level+2, "let coordinates = self.%s_decoder();\n", varDataName); + // indent(writer, level+2, "let %s = self.%s_slice(coordinates);\n", varDataName, varDataName); + + // indent(writer, level + 2, "// Character encoding: '%s'\n", characterEncoding); + // if (isAsciiEncoding(characterEncoding)) + // { + // indent(writer, level + 2, "for byte in %s {\n", varDataName); + // indent(writer, level + 3, "str.push(char::from(*byte));\n"); + // indent(writer, level + 2, "}\n"); + + // } + // else if (isUtf8Encoding(characterEncoding)) + // { + // indent(writer, level + 2, "str.push_str(&String::from_utf8_lossy(%s));\n", varDataName); + // } else { + // indent(writer, level + 2, "str.push_str(&format!(\"{:?}\", %s));\n", varDataName); + // } + + // indent(writer, level+2, "drop(%s);\n", varDataName); + + // indent(writer, level+2, "str.push('%s');\n\n", Separator.FIELD); + + // i += varDataToken.componentTokenCount(); + // } + // indent(writer, level + 2, "// END VAR_DATA\n"); + + indent(writer, level + 2, "str = str.trim_end_matches('%s').to_string();\n\n", Separator.FIELD); + + if (msgName != null){ + indent(writer, level + 2, "self.set_limit(original_limit);\n\n"); + } + + indent(writer, level + 2, "Ok((self, str))\n"); + indent(writer, level + 1, "}\n"); + indent(writer, level, "}\n"); + } + + private static void writeTokenDisplay( + final String fieldName, final Token typeToken, final Appendable writer, final int level) + throws IOException{ + if (typeToken.encodedLength() <= 0 || typeToken.isConstantEncoding()) + { + return; + } + + indent(writer, level, "// SIGNAL: %s\n", typeToken.signal()); + indent(writer, level, "str.push_str(\"%s%s\");\n", fieldName, Separator.KEY_VALUE); + + final String formattedFieldName = formatPropertyName(fieldName); + + switch (typeToken.signal()) + { + case ENCODING: + if (typeToken.arrayLength() > 1) { + indent(writer, level, "let %s = self.%s();\n", formattedFieldName, formattedFieldName); + if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) { + indent(writer, level, "for byte in %s {\n", formattedFieldName); + indent(writer, level + 1, "str.push(char::from(byte));\n"); + indent(writer, level, "}\n"); + } else { + indent(writer, level, "str.push('%s');\n", Separator.BEGIN_ARRAY); + indent(writer, level, "for v in %s {\n", formattedFieldName); + indent(writer, level + 1, "str.push_str(&v.to_string());\n"); + indent(writer, level + 1, "str.push('%s');\n", Separator.ENTRY); + indent(writer, level, "}\n"); + indent(writer, level, "str.push('%s');\n", Separator.END_ARRAY); + } + } else if (typeToken.encoding().presence() == Presence.REQUIRED) { + indent(writer, level, "str.push_str(&format!(\"{}\", self.%s()));\n", formattedFieldName); + } else { + indent(writer, level, "str.push_str(&format!(\"{:?}\", self.%s()));\n", formattedFieldName); + } + break; + + case BEGIN_ENUM: + indent(writer, level, "str.push_str(&format!(\"{}\", self.%s()));\n", fieldName); + break; + + case BEGIN_COMPOSITE: + { + indent(writer, level, "let mut %s = self.%s_decoder();\n", formattedFieldName, formattedFieldName); + indent(writer, level, "let result = %s.human_readable()?;\n", formattedFieldName); + indent(writer, level, "%s = result.0;\n", formattedFieldName); + indent(writer, level, "str.push_str(&result.1);\n"); + indent(writer, level, "self = %s.parent()?;\n", formattedFieldName); + break; + } + + case BEGIN_SET: + // TODO: implement human_readable or display + indent(writer, level, "str.push_str(&format!(\"{:?}\", self.%s()));\n", formattedFieldName); + break; + + default: + break; + } + + indent(writer, level, "str.push('%s');\n\n", Separator.FIELD); + } + } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java index a38bea7a7a..6ef9e8cdba 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java @@ -23,6 +23,9 @@ import uk.co.real_logic.sbe.ir.Encoding; import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.*; @@ -81,26 +84,12 @@ static String generateRustLiteral(final PrimitiveType type, final String value) throw new IllegalArgumentException("Unknown Rust type name found for primitive " + type.primitiveName()); } - switch (type) - { - case CHAR: - case INT8: - case INT16: - case INT32: - case INT64: - return value + '_' + typeName; - case UINT8: - case UINT16: - case UINT32: - case UINT64: - return "0x" + Long.toHexString(parseLong(value)) + '_' + typeName; - case FLOAT: - case DOUBLE: - return value.endsWith("NaN") ? typeName + "::NAN" : value + '_' + typeName; - - default: - throw new IllegalArgumentException("Unsupported literal generation for type: " + type.primitiveName()); - } + return switch (type) { + case CHAR, INT8, INT16, INT32, INT64 -> value + '_' + typeName; + case UINT8, UINT16, UINT32, UINT64 -> "0x" + Long.toHexString(parseLong(value)) + '_' + typeName; + case FLOAT, DOUBLE -> value.endsWith("NaN") ? typeName + "::NAN" : value + '_' + typeName; + default -> throw new IllegalArgumentException("Unsupported literal generation for type: " + type.primitiveName()); + }; } static byte eightBitCharacter(final String asciiCharacter) @@ -149,6 +138,15 @@ static String formatFunctionName(final String value) } return sanitizeMethodOrProperty(toLowerSnakeCase(value)); } + + static String formatPropertyName(final String value) + { + if (value.isEmpty()) + { + return value; + } + return sanitizeMethodOrProperty(toLowerSnakeCase(value)); + } static String cleanUpperAcronyms(final String value) { @@ -325,4 +323,106 @@ static boolean anyMatch(final String v) return LOWER_CASE_NAMES.contains(v.toLowerCase()); } } + + /** + * Separator symbols for `std::fmt::Display` implementations on codecs. + */ + enum Separator + { + BEGIN_GROUP('['), + END_GROUP(']'), + BEGIN_COMPOSITE('('), + END_COMPOSITE(')'), + BEGIN_SET('{'), + END_SET('}'), + BEGIN_ARRAY('['), + END_ARRAY(']'), + FIELD('|'), + KEY_VALUE('='), + ENTRY(','); + + private final char symbol; + + Separator(final char symbol) + { + this.symbol = symbol; + } + + // void appendToGeneratedBuilder(final Appendable builder, final String indent) + // { + // builder.append(indent).append("builder.append('").append(symbol).append("');").append('\n'); + // } + + /** + * {@inheritDoc} + */ + @Override + public String toString() + { + return String.valueOf(symbol); + } + } + + /** + * Indexes known charset aliases to the name of the instance in {@link StandardCharsets}. + */ + static final HashMap STD_CHARSETS = new HashMap<>(); + + static + { + try + { + for (final Field field : StandardCharsets.class.getDeclaredFields()) + { + if (Charset.class.isAssignableFrom(field.getType()) && Modifier.isStatic(field.getModifiers()) && + Modifier.isPublic(field.getModifiers())) + { + final Charset charset = (Charset)field.get(null); + final String name = field.getName(); + String oldName = STD_CHARSETS.put(charset.name(), name); + + if (null != oldName) + { + throw new IllegalStateException("Duplicate charset alias: old=" + oldName + ", new=" + name); + } + + for (final String alias : charset.aliases()) + { + oldName = STD_CHARSETS.put(alias, name); + if (null != oldName) + { + throw new IllegalStateException( + "Duplicate charset alias: old=" + oldName + ", new=" + alias); + } + } + } + } + } + catch (final IllegalAccessException ex) + { + throw new RuntimeException(ex); + } + } + + /** + * Checks if the given encoding represents an ASCII charset. + * + * @param encoding as a string name (e.g. ASCII). + * @return {@code true} if the encoding denotes an ASCII charset. + */ + public static boolean isAsciiEncoding(final String encoding) + { + return "US_ASCII".equals(STD_CHARSETS.get(encoding)); + } + + /** + * Checks if the given encoding represents a UTF-8 charset. + * + * @param encoding as a string name (e.g. unicode-1-1-utf-8). + * @return {@code true} if the encoding denotes a UTF-8 charset. + */ + public static boolean isUtf8Encoding(final String encoding) + { + return "UTF_8".equals(STD_CHARSETS.get(encoding)); + } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java index 5c1981a874..99d1deebc7 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java @@ -41,7 +41,8 @@ class SubGroup implements RustGenerator.ParentDef this.groupToken = groupToken; } - public SubGroup addSubGroup(final String name, final int level, final Token groupToken) + @Override + public SubGroup addSubGroup(final String name, final int level, final Token groupToken) { final SubGroup subGroup = new SubGroup(name, level, groupToken); subGroups.add(subGroup); @@ -233,6 +234,8 @@ void generateDecoder( RustGenerator.generateDecoderVarData(sb, varData, level, true); indent(sb, level - 1, "}\n\n"); // close impl + + RustGenerator.generateDecoderDisplay(sb, name, null, fields, groups, varData, level - 1); } void appendTo(final Appendable dest) throws IOException From 9809b45de9609ad7f9e3bd882a8f935b47157f11 Mon Sep 17 00:00:00 2001 From: "marcio.andrade" Date: Tue, 18 Feb 2025 09:57:04 -0300 Subject: [PATCH 02/25] Fix Either. --- .../sbe/generation/rust/RustGenerator.java | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 69d923adc8..c879f7465a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1960,11 +1960,25 @@ private static void writeTokenDisplay( case BEGIN_COMPOSITE: { - indent(writer, level, "let mut %s = self.%s_decoder();\n", formattedFieldName, formattedFieldName); - indent(writer, level, "let result = %s.human_readable()?;\n", formattedFieldName); - indent(writer, level, "%s = result.0;\n", formattedFieldName); - indent(writer, level, "str.push_str(&result.1);\n"); - indent(writer, level, "self = %s.parent()?;\n", formattedFieldName); + if (typeToken.version() > 0) + { + indent(writer, level, "match self.%s_decoder() {\n", formattedFieldName); + indent(writer, level + 1, "Either::Left(self_) => {\n"); + indent(writer, level + 2, "self = self_;\n"); + indent(writer, level + 1, "},\n"); + indent(writer, level + 1, "Either::Right(mut %s) => {\n", formattedFieldName); + indent(writer, level + 2, "let mut result = %s.human_readable()?;\n", formattedFieldName); + indent(writer, level + 2, "str.push_str(&result.1);\n"); + indent(writer, level + 2, "self = result.0.parent()?;\n"); + indent(writer, level + 1, "}\n"); + indent(writer, level, "}\n"); + } else { + indent(writer, level, "let mut %s = self.%s_decoder();\n", formattedFieldName, formattedFieldName); + indent(writer, level, "let result = %s.human_readable()?;\n", formattedFieldName); + indent(writer, level, "%s = result.0;\n", formattedFieldName); + indent(writer, level, "str.push_str(&result.1);\n"); + indent(writer, level, "self = %s.parent()?;\n", formattedFieldName); + } break; } From aa15dc798858fe1587160a4eb8f42261829ba0a9 Mon Sep 17 00:00:00 2001 From: "marcio.andrade" Date: Tue, 18 Feb 2025 10:14:54 -0300 Subject: [PATCH 03/25] Fix set. --- .../sbe/generation/rust/RustGenerator.java | 40 +++++++++++++++++-- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index c879f7465a..2acb55417e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1172,6 +1172,8 @@ private static void generateSingleBitSet( { final Token beginToken = tokens.get(0); final String rustPrimitiveType = rustTypeName(beginToken.encoding().primitiveType()); + + indent(writer, 0, "use crate::*;\n\n"); indent(writer, 0, "#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]\n"); indent(writer, 0, "pub struct %s(pub %s);\n", bitSetType, rustPrimitiveType); indent(writer, 0, "impl %s {\n", bitSetType); @@ -1246,7 +1248,39 @@ private static void generateSingleBitSet( writer.append(builder.toString()).append("]\",\n"); indent(writer, 3, arguments + ")\n"); indent(writer, 1, "}\n"); - indent(writer, 0, "}\n"); + indent(writer, 0, "}\n\n"); + + generateBitSetDisplay(bitSetType, tokens, writer, 0); + } + + static void generateBitSetDisplay( + final String bitSetType, + final List tokens, + final Appendable writer, + final int level) throws IOException + { + indent(writer, level, "impl HumanReadable for %s {\n", bitSetType); + indent(writer, level + 1, "fn human_readable(mut self) -> SbeResult<(Self, String)> {\n"); + indent(writer, level + 2, "let mut str = String::new();\n"); + + for (final Token token : tokens) + { + if (Signal.CHOICE != token.signal()) + { + continue; + } + + final String choiceName = formatFunctionName(token.name()); + + indent(writer, level + 2, "str.push_str(\"%s=\");\n", choiceName); + indent(writer, level + 2, "str.push_str(&self.get_%s().to_string());\n", choiceName); + indent(writer, level + 2, "str.push('%s');\n\n", Separator.ENTRY); + + } + + indent(writer, level + 2, "Ok((self, str))\n"); + indent(writer, level + 1, "}\n"); + indent(writer, level, "}\n"); } static void appendImplEncoderTrait( @@ -1948,6 +1982,7 @@ private static void writeTokenDisplay( indent(writer, level, "str.push('%s');\n", Separator.END_ARRAY); } } else if (typeToken.encoding().presence() == Presence.REQUIRED) { + // TODO: review indent(writer, level, "str.push_str(&format!(\"{}\", self.%s()));\n", formattedFieldName); } else { indent(writer, level, "str.push_str(&format!(\"{:?}\", self.%s()));\n", formattedFieldName); @@ -1983,8 +2018,7 @@ private static void writeTokenDisplay( } case BEGIN_SET: - // TODO: implement human_readable or display - indent(writer, level, "str.push_str(&format!(\"{:?}\", self.%s()));\n", formattedFieldName); + indent(writer, level, "str.push_str(&self.%s().human_readable()?.1);\n", formattedFieldName); break; default: From 9b237dd04935cc5dfd078036eba67796c3df34c8 Mon Sep 17 00:00:00 2001 From: "marcio.andrade" Date: Tue, 18 Feb 2025 10:37:38 -0300 Subject: [PATCH 04/25] Fix Option display. --- .../co/real_logic/sbe/generation/rust/RustGenerator.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 2acb55417e..9f97a28df6 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1982,10 +1982,13 @@ private static void writeTokenDisplay( indent(writer, level, "str.push('%s');\n", Separator.END_ARRAY); } } else if (typeToken.encoding().presence() == Presence.REQUIRED) { - // TODO: review indent(writer, level, "str.push_str(&format!(\"{}\", self.%s()));\n", formattedFieldName); } else { - indent(writer, level, "str.push_str(&format!(\"{:?}\", self.%s()));\n", formattedFieldName); + indent(writer, level, "let display = match self.%s() {\n", formattedFieldName); + indent(writer, level + 1, "Some(value) => format!(\"{}\", value),\n"); + indent(writer, level + 1, "None => \"None\".to_string(),\n"); + indent(writer, level, "};\n"); + indent(writer, level, "str.push_str(&display);\n"); } break; From 04a13d25a0f9b1bac4681c4fd1b4ba2954408261 Mon Sep 17 00:00:00 2001 From: "marcio.andrade" Date: Tue, 18 Feb 2025 11:33:55 -0300 Subject: [PATCH 05/25] Add TODO. --- build.gradle | 4 ++-- .../uk/co/real_logic/sbe/generation/rust/RustGenerator.java | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index b0ac62184a..b34005c0aa 100644 --- a/build.gradle +++ b/build.gradle @@ -167,7 +167,7 @@ jar.enabled = false subprojects { apply plugin: 'java-library' apply plugin: 'jvm-test-suite' - apply plugin: 'checkstyle' + // apply plugin: 'checkstyle' group = sbeGroup version = sbeVersion @@ -179,7 +179,7 @@ subprojects { sourceCompatibility = JavaVersion.VERSION_17 } - checkstyle.toolVersion = libs.versions.checkstyle.get() + // checkstyle.toolVersion = libs.versions.checkstyle.get() tasks.withType(Sign).configureEach { onlyIf { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 9f97a28df6..6622b2e283 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1986,7 +1986,8 @@ private static void writeTokenDisplay( } else { indent(writer, level, "let display = match self.%s() {\n", formattedFieldName); indent(writer, level + 1, "Some(value) => format!(\"{}\", value),\n"); - indent(writer, level + 1, "None => \"None\".to_string(),\n"); + // TODO: how to represent None? + indent(writer, level + 1, "None => \"null\".to_string(),\n"); indent(writer, level, "};\n"); indent(writer, level, "str.push_str(&display);\n"); } From 828d39c44c480bce39f53bccea161de59225a035 Mon Sep 17 00:00:00 2001 From: "marcio.andrade" Date: Tue, 18 Feb 2025 11:41:24 -0300 Subject: [PATCH 06/25] Fix composite formatting. --- .../uk/co/real_logic/sbe/generation/rust/RustGenerator.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 6622b2e283..0887bc5ad4 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1999,6 +1999,7 @@ private static void writeTokenDisplay( case BEGIN_COMPOSITE: { + indent(writer, level, "str.push('%s');\n", Separator.BEGIN_COMPOSITE); if (typeToken.version() > 0) { indent(writer, level, "match self.%s_decoder() {\n", formattedFieldName); @@ -2018,6 +2019,7 @@ private static void writeTokenDisplay( indent(writer, level, "str.push_str(&result.1);\n"); indent(writer, level, "self = %s.parent()?;\n", formattedFieldName); } + indent(writer, level, "str.push('%s');\n", Separator.END_COMPOSITE); break; } From d4afe7e62d569867f9d135fb4db44f6a2d1164f5 Mon Sep 17 00:00:00 2001 From: "marcio.andrade" Date: Tue, 18 Feb 2025 12:12:01 -0300 Subject: [PATCH 07/25] Undo formatting changes. --- .../sbe/generation/rust/LibRsDef.java | 8 +++--- .../sbe/generation/rust/MessageCoderDef.java | 5 ++-- .../sbe/generation/rust/RustGenerator.java | 11 ++------ .../sbe/generation/rust/RustUtil.java | 28 ++++++++++++++----- .../sbe/generation/rust/SubGroup.java | 3 +- 5 files changed, 30 insertions(+), 25 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index 3c823654de..75245018fa 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -78,10 +78,10 @@ void generate(final Ir ir) throws IOException { walk .filter(Files::isRegularFile) - .map(path -> path.getFileName().toString()) - .filter(fileName -> fileName.endsWith(".rs")) - .filter(fileName -> !fileName.equals("lib.rs")) - .map(fileName -> fileName.substring(0, fileName.length() - 3)) + .map((path) -> path.getFileName().toString()) + .filter((fileName) -> fileName.endsWith(".rs")) + .filter((fileName) -> !fileName.equals("lib.rs")) + .map((fileName) -> fileName.substring(0, fileName.length() - 3)) .sorted() .forEach(modules::add); } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java index 30cd7454cb..e1a0c9c3a1 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java @@ -106,7 +106,7 @@ void generate( indent(sb, 1, "}\n\n"); // impl end - if (codecType == Encoder) //impl Display + if (codecType == Encoder) { } else { RustGenerator.generateDecoderDisplay(sb, msgTypeName,msgToken.name(),fields, groups, varData, 1); @@ -126,8 +126,7 @@ void appendTo(final Appendable dest) throws IOException dest.append(sb); } - @Override - public SubGroup addSubGroup(final String name, final int level, final Token groupToken) + public SubGroup addSubGroup(final String name, final int level, final Token groupToken) { final SubGroup subGroup = new SubGroup(name, level, groupToken); subGroups.add(subGroup); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 0887bc5ad4..2f78e21c0b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -58,8 +58,7 @@ enum CodecType { Decoder { - @Override - String bufType() + String bufType() { return READ_BUF_TYPE; } @@ -67,8 +66,7 @@ String bufType() Encoder { - @Override - String bufType() + String bufType() { return WRITE_BUF_TYPE; } @@ -919,11 +917,6 @@ private static void generatePrimitiveRequiredDecoder( final String rustPrimitiveType = rustTypeName(primitiveType); final String characterEncoding = encoding.characterEncoding(); - // System.out.println("name: " + name); - // System.out.println("fieldToken: " + fieldToken.name()); - // System.out.println("primitiveType: " + primitiveType); - // System.out.println("rustPrimitiveType: " + rustPrimitiveType); - indent(sb, level, "/// primitive field - '%s'\n", encoding.presence()); if (characterEncoding != null) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java index 6ef9e8cdba..5eead67e7f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java @@ -84,12 +84,26 @@ static String generateRustLiteral(final PrimitiveType type, final String value) throw new IllegalArgumentException("Unknown Rust type name found for primitive " + type.primitiveName()); } - return switch (type) { - case CHAR, INT8, INT16, INT32, INT64 -> value + '_' + typeName; - case UINT8, UINT16, UINT32, UINT64 -> "0x" + Long.toHexString(parseLong(value)) + '_' + typeName; - case FLOAT, DOUBLE -> value.endsWith("NaN") ? typeName + "::NAN" : value + '_' + typeName; - default -> throw new IllegalArgumentException("Unsupported literal generation for type: " + type.primitiveName()); - }; + switch (type) + { + case CHAR: + case INT8: + case INT16: + case INT32: + case INT64: + return value + '_' + typeName; + case UINT8: + case UINT16: + case UINT32: + case UINT64: + return "0x" + Long.toHexString(parseLong(value)) + '_' + typeName; + case FLOAT: + case DOUBLE: + return value.endsWith("NaN") ? typeName + "::NAN" : value + '_' + typeName; + + default: + throw new IllegalArgumentException("Unsupported literal generation for type: " + type.primitiveName()); + } } static byte eightBitCharacter(final String asciiCharacter) @@ -357,7 +371,7 @@ enum Separator * {@inheritDoc} */ @Override - public String toString() + public String toString() { return String.valueOf(symbol); } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java index 99d1deebc7..e2b00226ed 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java @@ -41,8 +41,7 @@ class SubGroup implements RustGenerator.ParentDef this.groupToken = groupToken; } - @Override - public SubGroup addSubGroup(final String name, final int level, final Token groupToken) + public SubGroup addSubGroup(final String name, final int level, final Token groupToken) { final SubGroup subGroup = new SubGroup(name, level, groupToken); subGroups.add(subGroup); From 943ce2d61088dc4e4441c5b5beba6925d0e418bb Mon Sep 17 00:00:00 2001 From: "marcio.andrade" Date: Tue, 18 Feb 2025 12:14:26 -0300 Subject: [PATCH 08/25] Undo formatting changes. --- .../co/real_logic/sbe/generation/rust/RustGenerator.java | 8 ++------ .../uk/co/real_logic/sbe/generation/rust/RustUtil.java | 5 ----- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 2f78e21c0b..d5d996df42 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -916,7 +916,6 @@ private static void generatePrimitiveRequiredDecoder( final PrimitiveType primitiveType = encoding.primitiveType(); final String rustPrimitiveType = rustTypeName(primitiveType); final String characterEncoding = encoding.characterEncoding(); - indent(sb, level, "/// primitive field - '%s'\n", encoding.presence()); if (characterEncoding != null) @@ -1165,7 +1164,6 @@ private static void generateSingleBitSet( { final Token beginToken = tokens.get(0); final String rustPrimitiveType = rustTypeName(beginToken.encoding().primitiveType()); - indent(writer, 0, "use crate::*;\n\n"); indent(writer, 0, "#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]\n"); indent(writer, 0, "pub struct %s(pub %s);\n", bitSetType, rustPrimitiveType); @@ -1241,7 +1239,7 @@ private static void generateSingleBitSet( writer.append(builder.toString()).append("]\",\n"); indent(writer, 3, arguments + ")\n"); indent(writer, 1, "}\n"); - indent(writer, 0, "}\n\n"); + indent(writer, 0, "}\n"); generateBitSetDisplay(bitSetType, tokens, writer, 0); } @@ -1757,7 +1755,7 @@ private static void generateCompositeDecoder( i += encodingToken.componentTokenCount(); } - indent(out, 1, "}\n\n"); // end impl + indent(out, 1, "}\n"); // end impl generateCompositeDecoderDisplay(out, decoderName, tokens, 1); @@ -2023,8 +2021,6 @@ private static void writeTokenDisplay( default: break; } - indent(writer, level, "str.push('%s');\n\n", Separator.FIELD); } - } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java index 5eead67e7f..4c78966a69 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java @@ -362,11 +362,6 @@ enum Separator this.symbol = symbol; } - // void appendToGeneratedBuilder(final Appendable builder, final String indent) - // { - // builder.append(indent).append("builder.append('").append(symbol).append("');").append('\n'); - // } - /** * {@inheritDoc} */ From f1f9088e4e26cc07b3d997a1b2512ef90e4973e2 Mon Sep 17 00:00:00 2001 From: "marcio.andrade" Date: Tue, 18 Feb 2025 13:31:32 -0300 Subject: [PATCH 09/25] Use separator. --- .../uk/co/real_logic/sbe/generation/rust/RustGenerator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index d5d996df42..a819a27e83 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1824,7 +1824,7 @@ static void generateDecoderDisplay( indent(writer, level + 2, "str.push_str(\"[%s]\");\n\n", msgName); - indent(writer, level + 2, "str.push('(');\n\n"); + indent(writer, level + 2, "str.push('%s');\n\n", Separator.BEGIN_COMPOSITE); indent(writer, level + 2, "str.push_str(\"sbeTemplateId=\");\n"); indent(writer, level + 2, "str.push_str(&SBE_TEMPLATE_ID.to_string());\n\n"); @@ -1846,7 +1846,7 @@ static void generateDecoderDisplay( indent(writer, level + 2, "}\n"); indent(writer, level + 2, "str.push_str(&SBE_BLOCK_LENGTH.to_string());\n\n"); - indent(writer, level + 2, "str.push_str(\"):\");\n\n"); + indent(writer, level + 2, "str.push_str(\"%s:\");\n\n", Separator.END_COMPOSITE); } indent(writer, level + 2, "// START FIELDS\n"); From 6db3d6424f94c1c42a4355f057d48c60be30b2f5 Mon Sep 17 00:00:00 2001 From: "marcio.andrade" Date: Tue, 18 Feb 2025 13:31:55 -0300 Subject: [PATCH 10/25] Remove TODO. --- .../java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java | 1 - 1 file changed, 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index a819a27e83..72e5b12075 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1977,7 +1977,6 @@ private static void writeTokenDisplay( } else { indent(writer, level, "let display = match self.%s() {\n", formattedFieldName); indent(writer, level + 1, "Some(value) => format!(\"{}\", value),\n"); - // TODO: how to represent None? indent(writer, level + 1, "None => \"null\".to_string(),\n"); indent(writer, level, "};\n"); indent(writer, level, "str.push_str(&display);\n"); From ace17b6ce7d9f995f4f280f0dac7073218a2f6e1 Mon Sep 17 00:00:00 2001 From: "marcio.andrade" Date: Tue, 18 Feb 2025 13:47:03 -0300 Subject: [PATCH 11/25] Improve generated code. --- .../sbe/generation/rust/RustGenerator.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 72e5b12075..e353c11eb5 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1882,10 +1882,10 @@ static void generateDecoderDisplay( indent(writer, level + 2, "let mut %s = self.%s_decoder();\n", groupName, groupName); indent(writer, level + 2, "str.push('%s');\n", Separator.BEGIN_GROUP); - indent(writer, level + 2, "let mut result = %s.human_readable()?;\n", groupName); - indent(writer, level + 2, "str.push_str(&result.1);\n"); + indent(writer, level + 2, "let (mut %s, string) = %s.human_readable()?;\n", groupName, groupName); + indent(writer, level + 2, "str.push_str(&string);\n"); indent(writer, level + 2, "str.push('%s');\n", Separator.END_GROUP); - indent(writer, level + 2, "self = result.0.parent()?;\n"); + indent(writer, level + 2, "self = %s.parent()?;\n\n", groupName); i = findEndSignal(groups, i, Signal.END_GROUP, groupToken.name()); } @@ -1973,10 +1973,10 @@ private static void writeTokenDisplay( indent(writer, level, "str.push('%s');\n", Separator.END_ARRAY); } } else if (typeToken.encoding().presence() == Presence.REQUIRED) { - indent(writer, level, "str.push_str(&format!(\"{}\", self.%s()));\n", formattedFieldName); + indent(writer, level, "str.push_str(&self.%s().to_string());\n", formattedFieldName); } else { indent(writer, level, "let display = match self.%s() {\n", formattedFieldName); - indent(writer, level + 1, "Some(value) => format!(\"{}\", value),\n"); + indent(writer, level + 1, "Some(value) => value.to_string(),\n"); indent(writer, level + 1, "None => \"null\".to_string(),\n"); indent(writer, level, "};\n"); indent(writer, level, "str.push_str(&display);\n"); @@ -1984,7 +1984,7 @@ private static void writeTokenDisplay( break; case BEGIN_ENUM: - indent(writer, level, "str.push_str(&format!(\"{}\", self.%s()));\n", fieldName); + indent(writer, level, "str.push_str(&self.%s().to_string());\n", fieldName); break; case BEGIN_COMPOSITE: @@ -2004,9 +2004,8 @@ private static void writeTokenDisplay( indent(writer, level, "}\n"); } else { indent(writer, level, "let mut %s = self.%s_decoder();\n", formattedFieldName, formattedFieldName); - indent(writer, level, "let result = %s.human_readable()?;\n", formattedFieldName); - indent(writer, level, "%s = result.0;\n", formattedFieldName); - indent(writer, level, "str.push_str(&result.1);\n"); + indent(writer, level, "let (mut %s, string) = %s.human_readable()?;\n", formattedFieldName, formattedFieldName); + indent(writer, level, "str.push_str(&string);\n"); indent(writer, level, "self = %s.parent()?;\n", formattedFieldName); } indent(writer, level, "str.push('%s');\n", Separator.END_COMPOSITE); From e7f49e30c67b5b2ff986b968018d8cef1e484b8e Mon Sep 17 00:00:00 2001 From: "marcio.andrade" Date: Tue, 18 Feb 2025 14:35:11 -0300 Subject: [PATCH 12/25] Improve generated code. --- .../uk/co/real_logic/sbe/generation/rust/RustGenerator.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index e353c11eb5..8e07bcd90d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1997,9 +1997,9 @@ private static void writeTokenDisplay( indent(writer, level + 2, "self = self_;\n"); indent(writer, level + 1, "},\n"); indent(writer, level + 1, "Either::Right(mut %s) => {\n", formattedFieldName); - indent(writer, level + 2, "let mut result = %s.human_readable()?;\n", formattedFieldName); - indent(writer, level + 2, "str.push_str(&result.1);\n"); - indent(writer, level + 2, "self = result.0.parent()?;\n"); + indent(writer, level + 2, "let (mut %s, string) = %s.human_readable()?;\n", formattedFieldName, formattedFieldName); + indent(writer, level + 2, "str.push_str(&string);\n"); + indent(writer, level + 2, "self = %s.parent()?;\n", formattedFieldName); indent(writer, level + 1, "}\n"); indent(writer, level, "}\n"); } else { From 3cfb4a516293a1c47f4db53635b658c9f3964fb2 Mon Sep 17 00:00:00 2001 From: "marcio.andrade" Date: Tue, 18 Feb 2025 14:49:39 -0300 Subject: [PATCH 13/25] Decrease changes in this MR. --- .../sbe/generation/rust/MessageCoderDef.java | 7 +++++-- .../sbe/generation/rust/RustGenerator.java | 16 ++++++++-------- .../real_logic/sbe/generation/rust/RustUtil.java | 6 +++--- .../real_logic/sbe/generation/rust/SubGroup.java | 2 +- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java index e1a0c9c3a1..48d4ec9d67 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java @@ -108,8 +108,11 @@ void generate( if (codecType == Encoder) { - } else { - RustGenerator.generateDecoderDisplay(sb, msgTypeName,msgToken.name(),fields, groups, varData, 1); + } + else + { + RustGenerator.appendImplHumanReadableForDecoder(sb, msgTypeName, msgToken.name(), fields, groups, varData, + 1); } // append all subGroup generated code diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 8e07bcd90d..d4b0c81596 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1241,10 +1241,10 @@ private static void generateSingleBitSet( indent(writer, 1, "}\n"); indent(writer, 0, "}\n"); - generateBitSetDisplay(bitSetType, tokens, writer, 0); + appendImplHumanReadableForBitSet(bitSetType, tokens, writer, 0); } - static void generateBitSetDisplay( + static void appendImplHumanReadableForBitSet( final String bitSetType, final List tokens, final Appendable writer, @@ -1757,12 +1757,12 @@ private static void generateCompositeDecoder( indent(out, 1, "}\n"); // end impl - generateCompositeDecoderDisplay(out, decoderName, tokens, 1); + appendImplHumanReadableForComposite(out, decoderName, tokens, 1); indent(out, 0, "} // end decoder mod \n"); } - private static void generateCompositeDecoderDisplay( + private static void appendImplHumanReadableForComposite( final Appendable writer, final String decoderName, final List tokens, @@ -1776,7 +1776,7 @@ private static void generateCompositeDecoderDisplay( for (int i = 1, size = tokens.size() - 1; i < size; ) { final Token token = tokens.get(i); final String fieldName = RustUtil.formatPropertyName(token.name()); - writeTokenDisplay(fieldName, token, writer, level + 2); + writeHumanReadableKeyValue(fieldName, token, writer, level + 2); i += token.componentTokenCount(); } @@ -1800,7 +1800,7 @@ private static void appendConstAccessor( indent(writer, level, "}\n\n"); } - static void generateDecoderDisplay( + static void appendImplHumanReadableForDecoder( final Appendable writer, final String decoderName, final String msgName, @@ -1857,7 +1857,7 @@ static void generateDecoderDisplay( { final Token encodingToken = fields.get(i + 1); final String fieldName = RustUtil.formatPropertyName(fieldToken.name()); - writeTokenDisplay(fieldName, encodingToken, writer, level + 2); + writeHumanReadableKeyValue(fieldName, encodingToken, writer, level + 2); i += fieldToken.componentTokenCount(); } @@ -1942,7 +1942,7 @@ static void generateDecoderDisplay( indent(writer, level, "}\n"); } - private static void writeTokenDisplay( + private static void writeHumanReadableKeyValue( final String fieldName, final Token typeToken, final Appendable writer, final int level) throws IOException{ if (typeToken.encodedLength() <= 0 || typeToken.isConstantEncoding()) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java index 4c78966a69..c7ec00f735 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java @@ -338,8 +338,8 @@ static boolean anyMatch(final String v) } } - /** - * Separator symbols for `std::fmt::Display` implementations on codecs. + /** + * Separator symbols for `HumanReadable` implementations on codecs. */ enum Separator { @@ -413,7 +413,7 @@ public String toString() } } - /** + /** * Checks if the given encoding represents an ASCII charset. * * @param encoding as a string name (e.g. ASCII). diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java index e2b00226ed..bc005ab740 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java @@ -234,7 +234,7 @@ void generateDecoder( indent(sb, level - 1, "}\n\n"); // close impl - RustGenerator.generateDecoderDisplay(sb, name, null, fields, groups, varData, level - 1); + RustGenerator.appendImplHumanReadableForDecoder(sb, name, null, fields, groups, varData, level - 1); } void appendTo(final Appendable dest) throws IOException From bdcf68913a8f7044b89703d9860599871b9d0682 Mon Sep 17 00:00:00 2001 From: "marcio.andrade" Date: Tue, 18 Feb 2025 14:55:59 -0300 Subject: [PATCH 14/25] Enclose set. --- .../uk/co/real_logic/sbe/generation/rust/RustGenerator.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index d4b0c81596..34ae7b9e67 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -2013,7 +2013,9 @@ private static void writeHumanReadableKeyValue( } case BEGIN_SET: + indent(writer, level, "str.push('%s');\n", Separator.BEGIN_SET); indent(writer, level, "str.push_str(&self.%s().human_readable()?.1);\n", formattedFieldName); + indent(writer, level, "str.push('%s');\n", Separator.END_SET); break; default: From 4b296bd41418281ea837066f898be2a64534ef4b Mon Sep 17 00:00:00 2001 From: "marcio.andrade" Date: Tue, 18 Feb 2025 15:00:20 -0300 Subject: [PATCH 15/25] Improve comment. --- .../sbe/generation/rust/RustGenerator.java | 74 +++++++++---------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 34ae7b9e67..0f56eff7e3 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1772,7 +1772,7 @@ private static void appendImplHumanReadableForComposite( indent(writer, level + 2, "let mut str = String::new();\n"); - // Start from 1 to the token of this own composite field. + // Skip the first and last tokens as they are this composite start and end tokens. for (int i = 1, size = tokens.size() - 1; i < size; ) { final Token token = tokens.get(i); final String fieldName = RustUtil.formatPropertyName(token.name()); @@ -1891,45 +1891,45 @@ static void appendImplHumanReadableForDecoder( } indent(writer, level + 2, "// END GROUPS\n\n"); - // indent(writer, level + 2, "// START VAR_DATA \n"); - // for (int i = 0, size = varData.size(); i < size;) - // { - // final Token varDataToken = varData.get(i); - // if (varDataToken.signal() != Signal.BEGIN_VAR_DATA) - // { - // throw new IllegalStateException("tokens must begin with BEGIN_VAR_DATA: token=" + varDataToken); - // } + indent(writer, level + 2, "// START VAR_DATA \n"); + for (int i = 0, size = varData.size(); i < size;) + { + final Token varDataToken = varData.get(i); + if (varDataToken.signal() != Signal.BEGIN_VAR_DATA) + { + throw new IllegalStateException("tokens must begin with BEGIN_VAR_DATA: token=" + varDataToken); + } - // final String characterEncoding = varData.get(i + 3).encoding().characterEncoding(); - // final String varDataName = formatPropertyName(varDataToken.name()); - - // indent(writer, level + 2, "str.push_str(\"%s%s\");\n", varDataName, Separator.KEY_VALUE); - - // indent(writer, level+2, "let coordinates = self.%s_decoder();\n", varDataName); - // indent(writer, level+2, "let %s = self.%s_slice(coordinates);\n", varDataName, varDataName); - - // indent(writer, level + 2, "// Character encoding: '%s'\n", characterEncoding); - // if (isAsciiEncoding(characterEncoding)) - // { - // indent(writer, level + 2, "for byte in %s {\n", varDataName); - // indent(writer, level + 3, "str.push(char::from(*byte));\n"); - // indent(writer, level + 2, "}\n"); - - // } - // else if (isUtf8Encoding(characterEncoding)) - // { - // indent(writer, level + 2, "str.push_str(&String::from_utf8_lossy(%s));\n", varDataName); - // } else { - // indent(writer, level + 2, "str.push_str(&format!(\"{:?}\", %s));\n", varDataName); - // } - - // indent(writer, level+2, "drop(%s);\n", varDataName); + final String characterEncoding = varData.get(i + 3).encoding().characterEncoding(); + final String varDataName = formatPropertyName(varDataToken.name()); + + indent(writer, level + 2, "str.push_str(\"%s%s\");\n", varDataName, Separator.KEY_VALUE); + + indent(writer, level+2, "let coordinates = self.%s_decoder();\n", varDataName); + indent(writer, level+2, "let %s = self.%s_slice(coordinates);\n", varDataName, varDataName); + + indent(writer, level + 2, "// Character encoding: '%s'\n", characterEncoding); + if (isAsciiEncoding(characterEncoding)) + { + indent(writer, level + 2, "for byte in %s {\n", varDataName); + indent(writer, level + 3, "str.push(char::from(*byte));\n"); + indent(writer, level + 2, "}\n"); + + } + else if (isUtf8Encoding(characterEncoding)) + { + indent(writer, level + 2, "str.push_str(&String::from_utf8_lossy(%s));\n", varDataName); + } else { + indent(writer, level + 2, "str.push_str(&format!(\"{:?}\", %s));\n", varDataName); + } + + indent(writer, level+2, "drop(%s);\n", varDataName); - // indent(writer, level+2, "str.push('%s');\n\n", Separator.FIELD); + indent(writer, level+2, "str.push('%s');\n\n", Separator.FIELD); - // i += varDataToken.componentTokenCount(); - // } - // indent(writer, level + 2, "// END VAR_DATA\n"); + i += varDataToken.componentTokenCount(); + } + indent(writer, level + 2, "// END VAR_DATA\n"); indent(writer, level + 2, "str = str.trim_end_matches('%s').to_string();\n\n", Separator.FIELD); From 1972497616f15aa13080a9c796fdc152675a03d4 Mon Sep 17 00:00:00 2001 From: "marcio.andrade" Date: Wed, 19 Feb 2025 16:11:57 -0300 Subject: [PATCH 16/25] Fix lifetimes. --- .../uk/co/real_logic/sbe/generation/rust/RustGenerator.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 0f56eff7e3..c237fb5bc6 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1906,7 +1906,9 @@ static void appendImplHumanReadableForDecoder( indent(writer, level + 2, "str.push_str(\"%s%s\");\n", varDataName, Separator.KEY_VALUE); indent(writer, level+2, "let coordinates = self.%s_decoder();\n", varDataName); - indent(writer, level+2, "let %s = self.%s_slice(coordinates);\n", varDataName, varDataName); + // Using get_buf instead of the specific get_slice_at method to avoid + // the problems due to the lifetime of the method. + indent(writer, level+2, "let %s = self.get_buf().get_slice_at(coordinates.0, coordinates.1);\n", varDataName); indent(writer, level + 2, "// Character encoding: '%s'\n", characterEncoding); if (isAsciiEncoding(characterEncoding)) From dc280f966b92f8a353ecb7a685cbd19bf01a72ee Mon Sep 17 00:00:00 2001 From: "marcio.andrade" Date: Wed, 19 Feb 2025 17:34:45 -0300 Subject: [PATCH 17/25] Use block instead of dropping reference. --- .../sbe/generation/rust/LibRsDef.java | 1 - .../sbe/generation/rust/RustGenerator.java | 24 +++++++++---------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index 75245018fa..351ecf88b1 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -70,7 +70,6 @@ void generate(final Ir ir) throws IOException indent(libRs, 0, "#![allow(non_camel_case_types)]\n\n"); indent(libRs, 0, "#![allow(ambiguous_glob_reexports)]\n\n"); indent(libRs, 0, "#![allow(unused_mut)]\n\n"); - indent(libRs, 0, "#![allow(dropping_references)]\n\n"); indent(libRs, 0, "use ::core::{convert::TryInto};\n\n"); final ArrayList modules = new ArrayList<>(); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index c237fb5bc6..eb08feca02 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1904,30 +1904,30 @@ static void appendImplHumanReadableForDecoder( final String varDataName = formatPropertyName(varDataToken.name()); indent(writer, level + 2, "str.push_str(\"%s%s\");\n", varDataName, Separator.KEY_VALUE); - - indent(writer, level+2, "let coordinates = self.%s_decoder();\n", varDataName); + + indent(writer, level + 2, "{\n"); + indent(writer, level + 3, "let coordinates = self.%s_decoder();\n", varDataName); // Using get_buf instead of the specific get_slice_at method to avoid // the problems due to the lifetime of the method. - indent(writer, level+2, "let %s = self.get_buf().get_slice_at(coordinates.0, coordinates.1);\n", varDataName); + indent(writer, level + 3, "let %s = self.get_buf().get_slice_at(coordinates.0, coordinates.1);\n", varDataName); - indent(writer, level + 2, "// Character encoding: '%s'\n", characterEncoding); + indent(writer, level + 3, "// Character encoding: '%s'\n", characterEncoding); if (isAsciiEncoding(characterEncoding)) { - indent(writer, level + 2, "for byte in %s {\n", varDataName); - indent(writer, level + 3, "str.push(char::from(*byte));\n"); - indent(writer, level + 2, "}\n"); + indent(writer, level + 3, "for byte in %s {\n", varDataName); + indent(writer, level + 4, "str.push(char::from(*byte));\n"); + indent(writer, level + 3, "}\n"); } else if (isUtf8Encoding(characterEncoding)) { - indent(writer, level + 2, "str.push_str(&String::from_utf8_lossy(%s));\n", varDataName); + indent(writer, level + 3, "str.push_str(&String::from_utf8_lossy(%s));\n", varDataName); } else { - indent(writer, level + 2, "str.push_str(&format!(\"{:?}\", %s));\n", varDataName); + indent(writer, level + 3, "str.push_str(&format!(\"{:?}\", %s));\n", varDataName); } - - indent(writer, level+2, "drop(%s);\n", varDataName); + indent(writer, level + 2, "}\n"); - indent(writer, level+2, "str.push('%s');\n\n", Separator.FIELD); + indent(writer, level + 2, "str.push('%s');\n\n", Separator.FIELD); i += varDataToken.componentTokenCount(); } From bc1886e3a9ca6c9a4199a0a21f2aa5702e0a28e7 Mon Sep 17 00:00:00 2001 From: "marcio.andrade" Date: Wed, 19 Feb 2025 17:56:41 -0300 Subject: [PATCH 18/25] Avoid trailing commas. --- .../sbe/generation/rust/RustGenerator.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index eb08feca02..832208cc45 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1266,9 +1266,12 @@ static void appendImplHumanReadableForBitSet( indent(writer, level + 2, "str.push_str(\"%s=\");\n", choiceName); indent(writer, level + 2, "str.push_str(&self.get_%s().to_string());\n", choiceName); indent(writer, level + 2, "str.push('%s');\n\n", Separator.ENTRY); - } + indent(writer, level + 2, "if str.ends_with('%s') {\n", Separator.ENTRY); + indent(writer, level + 3, "str.pop();\n"); + indent(writer, level + 2, "}\n"); + indent(writer, level + 2, "Ok((self, str))\n"); indent(writer, level + 1, "}\n"); indent(writer, level, "}\n"); @@ -1933,7 +1936,9 @@ else if (isUtf8Encoding(characterEncoding)) } indent(writer, level + 2, "// END VAR_DATA\n"); - indent(writer, level + 2, "str = str.trim_end_matches('%s').to_string();\n\n", Separator.FIELD); + indent(writer, level + 2, "if str.ends_with('%s') {\n", Separator.FIELD); + indent(writer, level + 3, "str.pop();\n"); + indent(writer, level + 2, "}\n"); if (msgName != null){ indent(writer, level + 2, "self.set_limit(original_limit);\n\n"); @@ -1972,6 +1977,9 @@ private static void writeHumanReadableKeyValue( indent(writer, level + 1, "str.push_str(&v.to_string());\n"); indent(writer, level + 1, "str.push('%s');\n", Separator.ENTRY); indent(writer, level, "}\n"); + indent(writer, level, "if str.ends_with('%s') {\n", Separator.ENTRY); + indent(writer, level + 1, "str.pop();\n"); + indent(writer, level, "}\n"); indent(writer, level, "str.push('%s');\n", Separator.END_ARRAY); } } else if (typeToken.encoding().presence() == Presence.REQUIRED) { From 2ee90d733489956574a07280a40f25817f15f63a Mon Sep 17 00:00:00 2001 From: "marcio.andrade" Date: Thu, 20 Feb 2025 13:52:54 -0300 Subject: [PATCH 19/25] Fix display of groups. --- .../sbe/generation/rust/RustGenerator.java | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 832208cc45..98e6b53753 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1884,11 +1884,25 @@ static void appendImplHumanReadableForDecoder( final String groupName = formatPropertyName(groupToken.name()); indent(writer, level + 2, "let mut %s = self.%s_decoder();\n", groupName, groupName); + indent(writer, level + 2, "let %s_original_offset = %s.offset;\n", groupName, groupName); + indent(writer, level + 2, "let %s_original_index = %s.index;\n", groupName, groupName); indent(writer, level + 2, "str.push('%s');\n", Separator.BEGIN_GROUP); - indent(writer, level + 2, "let (mut %s, string) = %s.human_readable()?;\n", groupName, groupName); - indent(writer, level + 2, "str.push_str(&string);\n"); + + indent(writer, level + 2, "while %s.advance()?.is_some() {\n", groupName); + indent(writer, level + 3, "let result = %s.human_readable()?;\n", groupName); + indent(writer, level + 3, "%s = result.0;\n", groupName); + indent(writer, level + 3, "str.push_str(&result.1);\n"); + indent(writer, level + 3, "str.push('%s');\n", Separator.ENTRY); + indent(writer, level + 2, "}\n"); + + indent(writer, level + 2, "if str.ends_with('%s') {\n", Separator.ENTRY); + indent(writer, level + 3, "str.pop();\n"); + indent(writer, level + 2, "}\n"); + indent(writer, level + 2, "str.push('%s');\n", Separator.END_GROUP); - indent(writer, level + 2, "self = %s.parent()?;\n\n", groupName); + indent(writer, level + 2, "%s.offset = %s_original_offset;\n", groupName, groupName); + indent(writer, level + 2, "%s.index = %s_original_index;\n", groupName, groupName); + indent(writer, level + 2, "self = %s.parent()?;\n", groupName); i = findEndSignal(groups, i, Signal.END_GROUP, groupToken.name()); } From 3d52ab9873cdedd61e3e8673e019d0eb20f6981b Mon Sep 17 00:00:00 2001 From: "marcio.andrade" Date: Tue, 11 Mar 2025 14:50:33 -0300 Subject: [PATCH 20/25] Rename trait to SbeToString. --- .../sbe/generation/rust/LibRsDef.java | 12 ++++-- .../sbe/generation/rust/MessageCoderDef.java | 7 +--- .../sbe/generation/rust/RustGenerator.java | 38 +++++++++---------- .../sbe/generation/rust/RustUtil.java | 2 +- .../sbe/generation/rust/SubGroup.java | 2 +- 5 files changed, 31 insertions(+), 30 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index 351ecf88b1..9b2a3a79e3 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -99,7 +99,7 @@ void generate(final Ir ir) throws IOException generateEncoderTraits(libRs); generateDecoderTraits(schemaVersionType, libRs); - generateHumanReadableTrait(libRs); + generateSbeToString(libRs); generateReadBuf(libRs, byteOrder); generateWriteBuf(libRs, byteOrder); } @@ -133,10 +133,14 @@ static void generateDecoderTraits(final String schemaVersionType, final Writer w indent(writer, 0, "}\n\n"); } - static void generateHumanReadableTrait(final Writer writer) throws IOException + static void generateSbeToString(final Writer writer) throws IOException { - indent(writer, 0, "pub trait HumanReadable: Sized {\n"); - indent(writer, 1, "fn human_readable(self) -> SbeResult<(Self, String)>;\n"); + indent(writer, 0, "/// Returns a human-readable string representation of the SBE message.\n\n"); + indent(writer, 0, "/// This trait works like `ToString`, but it takes `self` as value\n"); + indent(writer, 0, "/// to be compatible with the generated decoders.\n"); + indent(writer, 0, "pub trait SbeToString: Sized {\n"); + indent(writer, 1, "/// Returns a human-readable string along with the consumed `self`.\n"); + indent(writer, 1, "fn sbe_to_string(self) -> SbeResult<(Self, String)>;\n"); indent(writer, 0, "}\n\n"); } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java index 48d4ec9d67..c7857bdfec 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java @@ -106,12 +106,9 @@ void generate( indent(sb, 1, "}\n\n"); // impl end - if (codecType == Encoder) - { - } - else + if (codecType == Decoder) { - RustGenerator.appendImplHumanReadableForDecoder(sb, msgTypeName, msgToken.name(), fields, groups, varData, + RustGenerator.appendImplSbeToStringForDecoder(sb, msgTypeName, msgToken.name(), fields, groups, varData, 1); } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 98e6b53753..17253c54a1 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1241,17 +1241,17 @@ private static void generateSingleBitSet( indent(writer, 1, "}\n"); indent(writer, 0, "}\n"); - appendImplHumanReadableForBitSet(bitSetType, tokens, writer, 0); + appendImplSbeToStringForBitSet(bitSetType, tokens, writer, 0); } - static void appendImplHumanReadableForBitSet( + static void appendImplSbeToStringForBitSet( final String bitSetType, final List tokens, final Appendable writer, final int level) throws IOException { - indent(writer, level, "impl HumanReadable for %s {\n", bitSetType); - indent(writer, level + 1, "fn human_readable(mut self) -> SbeResult<(Self, String)> {\n"); + indent(writer, level, "impl SbeToString for %s {\n", bitSetType); + indent(writer, level + 1, "fn sbe_to_string(mut self) -> SbeResult<(Self, String)> {\n"); indent(writer, level + 2, "let mut str = String::new();\n"); for (final Token token : tokens) @@ -1760,18 +1760,18 @@ private static void generateCompositeDecoder( indent(out, 1, "}\n"); // end impl - appendImplHumanReadableForComposite(out, decoderName, tokens, 1); + appendImplSbeToStringForComposite(out, decoderName, tokens, 1); indent(out, 0, "} // end decoder mod \n"); } - private static void appendImplHumanReadableForComposite( + private static void appendImplSbeToStringForComposite( final Appendable writer, final String decoderName, final List tokens, final int level) throws IOException { - indent(writer, level, "impl<'a, P> HumanReadable for %s

where P: Reader<'a> + ActingVersion + Default +'a {\n", decoderName); - indent(writer, level + 1, "fn human_readable(mut self) -> SbeResult<(Self, String)> {\n"); + indent(writer, level, "impl<'a, P> SbeToString for %s

where P: Reader<'a> + ActingVersion + Default +'a {\n", decoderName); + indent(writer, level + 1, "fn sbe_to_string(mut self) -> SbeResult<(Self, String)> {\n"); indent(writer, level + 2, "let mut str = String::new();\n"); @@ -1779,7 +1779,7 @@ private static void appendImplHumanReadableForComposite( for (int i = 1, size = tokens.size() - 1; i < size; ) { final Token token = tokens.get(i); final String fieldName = RustUtil.formatPropertyName(token.name()); - writeHumanReadableKeyValue(fieldName, token, writer, level + 2); + writeSbeToStringKeyValue(fieldName, token, writer, level + 2); i += token.componentTokenCount(); } @@ -1803,7 +1803,7 @@ private static void appendConstAccessor( indent(writer, level, "}\n\n"); } - static void appendImplHumanReadableForDecoder( + static void appendImplSbeToStringForDecoder( final Appendable writer, final String decoderName, final String msgName, @@ -1812,11 +1812,11 @@ static void appendImplHumanReadableForDecoder( final List varData, final int level) throws IOException{ if (msgName != null){ - indent(writer, level, "impl<'a> HumanReadable for %s<'a> {\n", decoderName); + indent(writer, level, "impl<'a> SbeToString for %s<'a> {\n", decoderName); } else { - indent(writer, level, "impl<'a, P> HumanReadable for %s

where P: Decoder<'a> + ActingVersion + Default +'a {\n", decoderName); + indent(writer, level, "impl<'a, P> SbeToString for %s

where P: Decoder<'a> + ActingVersion + Default +'a {\n", decoderName); } - indent(writer, level + 1, "fn human_readable(mut self) -> SbeResult<(Self, String)> {\n"); + indent(writer, level + 1, "fn sbe_to_string(mut self) -> SbeResult<(Self, String)> {\n"); indent(writer, level + 2, "let mut str = String::new();\n"); @@ -1860,7 +1860,7 @@ static void appendImplHumanReadableForDecoder( { final Token encodingToken = fields.get(i + 1); final String fieldName = RustUtil.formatPropertyName(fieldToken.name()); - writeHumanReadableKeyValue(fieldName, encodingToken, writer, level + 2); + writeSbeToStringKeyValue(fieldName, encodingToken, writer, level + 2); i += fieldToken.componentTokenCount(); } @@ -1889,7 +1889,7 @@ static void appendImplHumanReadableForDecoder( indent(writer, level + 2, "str.push('%s');\n", Separator.BEGIN_GROUP); indent(writer, level + 2, "while %s.advance()?.is_some() {\n", groupName); - indent(writer, level + 3, "let result = %s.human_readable()?;\n", groupName); + indent(writer, level + 3, "let result = %s.sbe_to_string()?;\n", groupName); indent(writer, level + 3, "%s = result.0;\n", groupName); indent(writer, level + 3, "str.push_str(&result.1);\n"); indent(writer, level + 3, "str.push('%s');\n", Separator.ENTRY); @@ -1963,7 +1963,7 @@ else if (isUtf8Encoding(characterEncoding)) indent(writer, level, "}\n"); } - private static void writeHumanReadableKeyValue( + private static void writeSbeToStringKeyValue( final String fieldName, final Token typeToken, final Appendable writer, final int level) throws IOException{ if (typeToken.encodedLength() <= 0 || typeToken.isConstantEncoding()) @@ -2021,14 +2021,14 @@ private static void writeHumanReadableKeyValue( indent(writer, level + 2, "self = self_;\n"); indent(writer, level + 1, "},\n"); indent(writer, level + 1, "Either::Right(mut %s) => {\n", formattedFieldName); - indent(writer, level + 2, "let (mut %s, string) = %s.human_readable()?;\n", formattedFieldName, formattedFieldName); + indent(writer, level + 2, "let (mut %s, string) = %s.sbe_to_string()?;\n", formattedFieldName, formattedFieldName); indent(writer, level + 2, "str.push_str(&string);\n"); indent(writer, level + 2, "self = %s.parent()?;\n", formattedFieldName); indent(writer, level + 1, "}\n"); indent(writer, level, "}\n"); } else { indent(writer, level, "let mut %s = self.%s_decoder();\n", formattedFieldName, formattedFieldName); - indent(writer, level, "let (mut %s, string) = %s.human_readable()?;\n", formattedFieldName, formattedFieldName); + indent(writer, level, "let (mut %s, string) = %s.sbe_to_string()?;\n", formattedFieldName, formattedFieldName); indent(writer, level, "str.push_str(&string);\n"); indent(writer, level, "self = %s.parent()?;\n", formattedFieldName); } @@ -2038,7 +2038,7 @@ private static void writeHumanReadableKeyValue( case BEGIN_SET: indent(writer, level, "str.push('%s');\n", Separator.BEGIN_SET); - indent(writer, level, "str.push_str(&self.%s().human_readable()?.1);\n", formattedFieldName); + indent(writer, level, "str.push_str(&self.%s().sbe_to_string()?.1);\n", formattedFieldName); indent(writer, level, "str.push('%s');\n", Separator.END_SET); break; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java index c7ec00f735..03997fe65e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java @@ -339,7 +339,7 @@ static boolean anyMatch(final String v) } /** - * Separator symbols for `HumanReadable` implementations on codecs. + * Separator symbols for `SbeToString` implementations on codecs. */ enum Separator { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java index bc005ab740..a83edd9fe5 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java @@ -234,7 +234,7 @@ void generateDecoder( indent(sb, level - 1, "}\n\n"); // close impl - RustGenerator.appendImplHumanReadableForDecoder(sb, name, null, fields, groups, varData, level - 1); + RustGenerator.appendImplSbeToStringForDecoder(sb, name, null, fields, groups, varData, level - 1); } void appendTo(final Appendable dest) throws IOException From 48b0955545cd51970208c76bd239fc0afe85d301 Mon Sep 17 00:00:00 2001 From: "marcio.andrade" Date: Tue, 11 Mar 2025 14:52:08 -0300 Subject: [PATCH 21/25] Improve comment. --- .../uk/co/real_logic/sbe/generation/rust/RustGenerator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 17253c54a1..f696e5a023 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1924,8 +1924,8 @@ static void appendImplSbeToStringForDecoder( indent(writer, level + 2, "{\n"); indent(writer, level + 3, "let coordinates = self.%s_decoder();\n", varDataName); - // Using get_buf instead of the specific get_slice_at method to avoid - // the problems due to the lifetime of the method. + // We're using get_buf instead of the specific get_slice_at method, because when using the latter, + // the compiler complained about the lifetimes of the values. indent(writer, level + 3, "let %s = self.get_buf().get_slice_at(coordinates.0, coordinates.1);\n", varDataName); indent(writer, level + 3, "// Character encoding: '%s'\n", characterEncoding); From f67d26826386e66c4a65110f3b46ee0775d9e072 Mon Sep 17 00:00:00 2001 From: "marcio.andrade" Date: Wed, 12 Mar 2025 14:05:45 -0300 Subject: [PATCH 22/25] Reduce duplication. --- .../sbe/generation/rust/RustGenerator.java | 274 ++++++++++-------- .../sbe/generation/rust/SubGroup.java | 2 +- 2 files changed, 147 insertions(+), 129 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index f696e5a023..cd5b0b6bef 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1811,158 +1811,176 @@ static void appendImplSbeToStringForDecoder( final List groups, final List varData, final int level) throws IOException{ - if (msgName != null){ - indent(writer, level, "impl<'a> SbeToString for %s<'a> {\n", decoderName); - } else { - indent(writer, level, "impl<'a, P> SbeToString for %s

where P: Decoder<'a> + ActingVersion + Default +'a {\n", decoderName); - } + indent(writer, level, "impl<'a> SbeToString for %s<'a> {\n", decoderName); indent(writer, level + 1, "fn sbe_to_string(mut self) -> SbeResult<(Self, String)> {\n"); + indent(writer, level + 2, "let original_limit = self.get_limit();\n"); + indent(writer, level + 2, "self.set_limit(self.offset + self.acting_block_length as usize);\n\n"); indent(writer, level + 2, "let mut str = String::new();\n"); - - if (msgName != null){ - indent(writer, level + 2, "let original_limit = self.get_limit();\n"); - indent(writer, level + 2, "self.set_limit(self.offset + self.acting_block_length as usize);\n\n"); + indent(writer, level + 2, "str.push_str(\"[%s]\");\n\n", msgName); - indent(writer, level + 2, "str.push_str(\"[%s]\");\n\n", msgName); + indent(writer, level + 2, "str.push('%s');\n\n", Separator.BEGIN_COMPOSITE); + indent(writer, level + 2, "str.push_str(\"sbeTemplateId=\");\n"); + indent(writer, level + 2, "str.push_str(&SBE_TEMPLATE_ID.to_string());\n\n"); - indent(writer, level + 2, "str.push('%s');\n\n", Separator.BEGIN_COMPOSITE); + indent(writer, level + 2, "str.push_str(\"|sbeSchemaId=\");\n"); + indent(writer, level + 2, "str.push_str(&SBE_SCHEMA_ID.to_string());\n\n"); - indent(writer, level + 2, "str.push_str(\"sbeTemplateId=\");\n"); - indent(writer, level + 2, "str.push_str(&SBE_TEMPLATE_ID.to_string());\n\n"); - - indent(writer, level + 2, "str.push_str(\"|sbeSchemaId=\");\n"); - indent(writer, level + 2, "str.push_str(&SBE_SCHEMA_ID.to_string());\n\n"); + indent(writer, level + 2, "str.push_str(\"|sbeSchemaVersion=\");\n"); + indent(writer, level + 2, "if self.acting_version != SBE_SCHEMA_VERSION {\n"); + indent(writer, level + 3, "str.push_str(&self.acting_version.to_string());\n"); + indent(writer, level + 3, "str.push('/');\n"); + indent(writer, level + 2, "}\n"); + indent(writer, level + 2, "str.push_str(&SBE_SCHEMA_VERSION.to_string());\n\n"); + + indent(writer, level + 2, "str.push_str(\"|sbeBlockLength=\");\n"); + indent(writer, level + 2, "if self.acting_block_length != SBE_BLOCK_LENGTH {\n"); + indent(writer, level + 3, "str.push_str(&self.acting_block_length.to_string());\n"); + indent(writer, level + 3, "str.push('/');\n"); + indent(writer, level + 2, "}\n"); + indent(writer, level + 2, "str.push_str(&SBE_BLOCK_LENGTH.to_string());\n\n"); + indent(writer, level + 2, "str.push_str(\"%s:\");\n\n", Separator.END_COMPOSITE); - indent(writer, level + 2, "str.push_str(\"|sbeSchemaVersion=\");\n"); - indent(writer, level + 2, "if self.acting_version != SBE_SCHEMA_VERSION {\n"); - indent(writer, level + 3, "str.push_str(&self.acting_version.to_string());\n"); - indent(writer, level + 3, "str.push('/');\n"); - indent(writer, level + 2, "}\n"); - indent(writer, level + 2, "str.push_str(&SBE_SCHEMA_VERSION.to_string());\n\n"); - - indent(writer, level + 2, "str.push_str(\"|sbeBlockLength=\");\n"); - indent(writer, level + 2, "if self.acting_block_length != SBE_BLOCK_LENGTH {\n"); - indent(writer, level + 3, "str.push_str(&self.acting_block_length.to_string());\n"); - indent(writer, level + 3, "str.push('/');\n"); - indent(writer, level + 2, "}\n"); - indent(writer, level + 2, "str.push_str(&SBE_BLOCK_LENGTH.to_string());\n\n"); + appendCommonImplSbeToStringForDecoders(writer, decoderName, fields, groups, varData, level + 2); + + indent(writer, level + 2, "self.set_limit(original_limit);\n\n"); + indent(writer, level + 2, "Ok((self, str))\n"); + indent(writer, level + 1, "}\n"); + indent(writer, level, "}\n"); + } - indent(writer, level + 2, "str.push_str(\"%s:\");\n\n", Separator.END_COMPOSITE); - } + static void appendImplSbeToStringForSubgroupDecoder( + final Appendable writer, + final String decoderName, + final List fields, + final List groups, + final List varData, + final int level) throws IOException{ + indent(writer, level, "impl<'a, P> SbeToString for %s

where P: Decoder<'a> + ActingVersion + Default +'a {\n", decoderName); + indent(writer, level + 1, "fn sbe_to_string(mut self) -> SbeResult<(Self, String)> {\n"); - indent(writer, level + 2, "// START FIELDS\n"); - for (int i = 0, size = fields.size(); i < size;) - { - final Token fieldToken = fields.get(i); - if (fieldToken.signal() == Signal.BEGIN_FIELD) - { - final Token encodingToken = fields.get(i + 1); - final String fieldName = RustUtil.formatPropertyName(fieldToken.name()); - writeSbeToStringKeyValue(fieldName, encodingToken, writer, level + 2); + indent(writer, level + 2, "let mut str = String::new();\n"); - i += fieldToken.componentTokenCount(); - } - else - { - ++i; - } + appendCommonImplSbeToStringForDecoders(writer, decoderName, fields, groups, varData, level + 2); + + indent(writer, level + 2, "Ok((self, str))\n"); + indent(writer, level + 1, "}\n"); + indent(writer, level, "}\n"); } - indent(writer, level + 2, "// END FIELDS\n\n"); - indent(writer, level + 2, "// START GROUPS\n"); - for (int i = 0, size = groups.size(); i < size; i++) - { - final Token groupToken = groups.get(i); - if (groupToken.signal() != Signal.BEGIN_GROUP) + /** Common code for both messages and subgroups decoders */ + private static void appendCommonImplSbeToStringForDecoders( + final Appendable writer, + final String decoderName, + final List fields, + final List groups, + final List varData, + final int level) throws IOException{ + indent(writer, level + 2, "// START FIELDS\n"); + for (int i = 0, size = fields.size(); i < size;) { - throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken); - } - - final String groupName = formatPropertyName(groupToken.name()); - - indent(writer, level + 2, "let mut %s = self.%s_decoder();\n", groupName, groupName); - indent(writer, level + 2, "let %s_original_offset = %s.offset;\n", groupName, groupName); - indent(writer, level + 2, "let %s_original_index = %s.index;\n", groupName, groupName); - indent(writer, level + 2, "str.push('%s');\n", Separator.BEGIN_GROUP); - - indent(writer, level + 2, "while %s.advance()?.is_some() {\n", groupName); - indent(writer, level + 3, "let result = %s.sbe_to_string()?;\n", groupName); - indent(writer, level + 3, "%s = result.0;\n", groupName); - indent(writer, level + 3, "str.push_str(&result.1);\n"); - indent(writer, level + 3, "str.push('%s');\n", Separator.ENTRY); - indent(writer, level + 2, "}\n"); - - indent(writer, level + 2, "if str.ends_with('%s') {\n", Separator.ENTRY); - indent(writer, level + 3, "str.pop();\n"); - indent(writer, level + 2, "}\n"); - - indent(writer, level + 2, "str.push('%s');\n", Separator.END_GROUP); - indent(writer, level + 2, "%s.offset = %s_original_offset;\n", groupName, groupName); - indent(writer, level + 2, "%s.index = %s_original_index;\n", groupName, groupName); - indent(writer, level + 2, "self = %s.parent()?;\n", groupName); - - i = findEndSignal(groups, i, Signal.END_GROUP, groupToken.name()); - } - indent(writer, level + 2, "// END GROUPS\n\n"); - - indent(writer, level + 2, "// START VAR_DATA \n"); - for (int i = 0, size = varData.size(); i < size;) - { - final Token varDataToken = varData.get(i); - if (varDataToken.signal() != Signal.BEGIN_VAR_DATA) - { - throw new IllegalStateException("tokens must begin with BEGIN_VAR_DATA: token=" + varDataToken); + final Token fieldToken = fields.get(i); + if (fieldToken.signal() == Signal.BEGIN_FIELD) + { + final Token encodingToken = fields.get(i + 1); + final String fieldName = RustUtil.formatPropertyName(fieldToken.name()); + writeSbeToStringKeyValue(fieldName, encodingToken, writer, level + 2); + + i += fieldToken.componentTokenCount(); + } + else + { + ++i; + } } + indent(writer, level + 2, "// END FIELDS\n\n"); - final String characterEncoding = varData.get(i + 3).encoding().characterEncoding(); - final String varDataName = formatPropertyName(varDataToken.name()); - - indent(writer, level + 2, "str.push_str(\"%s%s\");\n", varDataName, Separator.KEY_VALUE); - - indent(writer, level + 2, "{\n"); - indent(writer, level + 3, "let coordinates = self.%s_decoder();\n", varDataName); - // We're using get_buf instead of the specific get_slice_at method, because when using the latter, - // the compiler complained about the lifetimes of the values. - indent(writer, level + 3, "let %s = self.get_buf().get_slice_at(coordinates.0, coordinates.1);\n", varDataName); - - indent(writer, level + 3, "// Character encoding: '%s'\n", characterEncoding); - if (isAsciiEncoding(characterEncoding)) + indent(writer, level + 2, "// START GROUPS\n"); + for (int i = 0, size = groups.size(); i < size; i++) { - indent(writer, level + 3, "for byte in %s {\n", varDataName); - indent(writer, level + 4, "str.push(char::from(*byte));\n"); - indent(writer, level + 3, "}\n"); - + final Token groupToken = groups.get(i); + + if (groupToken.signal() != Signal.BEGIN_GROUP) + { + throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken); + } + + final String groupName = formatPropertyName(groupToken.name()); + + indent(writer, level + 2, "let mut %s = self.%s_decoder();\n", groupName, groupName); + indent(writer, level + 2, "let %s_original_offset = %s.offset;\n", groupName, groupName); + indent(writer, level + 2, "let %s_original_index = %s.index;\n", groupName, groupName); + indent(writer, level + 2, "str.push('%s');\n", Separator.BEGIN_GROUP); + + indent(writer, level + 2, "while %s.advance()?.is_some() {\n", groupName); + indent(writer, level + 3, "let result = %s.sbe_to_string()?;\n", groupName); + indent(writer, level + 3, "%s = result.0;\n", groupName); + indent(writer, level + 3, "str.push_str(&result.1);\n"); + indent(writer, level + 3, "str.push('%s');\n", Separator.ENTRY); + indent(writer, level + 2, "}\n"); + + indent(writer, level + 2, "if str.ends_with('%s') {\n", Separator.ENTRY); + indent(writer, level + 3, "str.pop();\n"); + indent(writer, level + 2, "}\n"); + + indent(writer, level + 2, "str.push('%s');\n", Separator.END_GROUP); + indent(writer, level + 2, "%s.offset = %s_original_offset;\n", groupName, groupName); + indent(writer, level + 2, "%s.index = %s_original_index;\n", groupName, groupName); + indent(writer, level + 2, "self = %s.parent()?;\n", groupName); + + i = findEndSignal(groups, i, Signal.END_GROUP, groupToken.name()); } - else if (isUtf8Encoding(characterEncoding)) + indent(writer, level + 2, "// END GROUPS\n\n"); + + indent(writer, level + 2, "// START VAR_DATA \n"); + for (int i = 0, size = varData.size(); i < size;) { - indent(writer, level + 3, "str.push_str(&String::from_utf8_lossy(%s));\n", varDataName); - } else { - indent(writer, level + 3, "str.push_str(&format!(\"{:?}\", %s));\n", varDataName); - } - indent(writer, level + 2, "}\n"); + final Token varDataToken = varData.get(i); + if (varDataToken.signal() != Signal.BEGIN_VAR_DATA) + { + throw new IllegalStateException("tokens must begin with BEGIN_VAR_DATA: token=" + varDataToken); + } + + final String characterEncoding = varData.get(i + 3).encoding().characterEncoding(); + final String varDataName = formatPropertyName(varDataToken.name()); - indent(writer, level + 2, "str.push('%s');\n\n", Separator.FIELD); + indent(writer, level + 2, "str.push_str(\"%s%s\");\n", varDataName, Separator.KEY_VALUE); + + indent(writer, level + 2, "{\n"); + indent(writer, level + 3, "let coordinates = self.%s_decoder();\n", varDataName); + // We're using get_buf instead of the specific get_slice_at method, because when using the latter, + // the compiler complained about the lifetimes of the values. + indent(writer, level + 3, "let %s = self.get_buf().get_slice_at(coordinates.0, coordinates.1);\n", varDataName); - i += varDataToken.componentTokenCount(); - } - indent(writer, level + 2, "// END VAR_DATA\n"); - - indent(writer, level + 2, "if str.ends_with('%s') {\n", Separator.FIELD); - indent(writer, level + 3, "str.pop();\n"); - indent(writer, level + 2, "}\n"); - - if (msgName != null){ - indent(writer, level + 2, "self.set_limit(original_limit);\n\n"); + indent(writer, level + 3, "// Character encoding: '%s'\n", characterEncoding); + if (isAsciiEncoding(characterEncoding)) + { + indent(writer, level + 3, "for byte in %s {\n", varDataName); + indent(writer, level + 4, "str.push(char::from(*byte));\n"); + indent(writer, level + 3, "}\n"); + + } + else if (isUtf8Encoding(characterEncoding)) + { + indent(writer, level + 3, "str.push_str(&String::from_utf8_lossy(%s));\n", varDataName); + } else { + indent(writer, level + 3, "str.push_str(&format!(\"{:?}\", %s));\n", varDataName); + } + indent(writer, level + 2, "}\n"); + + indent(writer, level + 2, "str.push('%s');\n\n", Separator.FIELD); + + i += varDataToken.componentTokenCount(); + } + indent(writer, level + 2, "// END VAR_DATA\n"); + + indent(writer, level + 2, "if str.ends_with('%s') {\n", Separator.FIELD); + indent(writer, level + 3, "str.pop();\n"); + indent(writer, level + 2, "}\n"); } - indent(writer, level + 2, "Ok((self, str))\n"); - indent(writer, level + 1, "}\n"); - indent(writer, level, "}\n"); - } - private static void writeSbeToStringKeyValue( final String fieldName, final Token typeToken, final Appendable writer, final int level) throws IOException{ diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java index a83edd9fe5..04471f505e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java @@ -234,7 +234,7 @@ void generateDecoder( indent(sb, level - 1, "}\n\n"); // close impl - RustGenerator.appendImplSbeToStringForDecoder(sb, name, null, fields, groups, varData, level - 1); + RustGenerator.appendImplSbeToStringForSubgroupDecoder(sb, name, fields, groups, varData, level - 1); } void appendTo(final Appendable dest) throws IOException From 83b842690b555bbfbca24d94c1feffde96f1e287 Mon Sep 17 00:00:00 2001 From: "marcio.andrade" Date: Wed, 12 Mar 2025 14:35:39 -0300 Subject: [PATCH 23/25] Format code. --- build.gradle | 4 +- .../sbe/generation/rust/RustGenerator.java | 513 +++++++++--------- .../sbe/generation/rust/RustUtil.java | 2 +- 3 files changed, 271 insertions(+), 248 deletions(-) diff --git a/build.gradle b/build.gradle index b34005c0aa..b0ac62184a 100644 --- a/build.gradle +++ b/build.gradle @@ -167,7 +167,7 @@ jar.enabled = false subprojects { apply plugin: 'java-library' apply plugin: 'jvm-test-suite' - // apply plugin: 'checkstyle' + apply plugin: 'checkstyle' group = sbeGroup version = sbeVersion @@ -179,7 +179,7 @@ subprojects { sourceCompatibility = JavaVersion.VERSION_17 } - // checkstyle.toolVersion = libs.versions.checkstyle.get() + checkstyle.toolVersion = libs.versions.checkstyle.get() tasks.withType(Sign).configureEach { onlyIf { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index cd5b0b6bef..3fc8c88f74 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1120,7 +1120,7 @@ static void generateDecoderVarData( // function to return slice form given coord indent(sb, level, "#[inline]\n"); - indent(sb, level, "pub fn %s_slice(&'a self, coordinates: (usize, usize)) -> &'a [u8] {\n", propertyName); + indent(sb, level, "pub fn %s_slice(&'a self, coord: (usize, usize)) -> &'a [u8] {\n", propertyName); if (varDataToken.version() > 0) { @@ -1130,8 +1130,8 @@ static void generateDecoderVarData( indent(sb, level + 1, "}\n\n"); } - indent(sb, level + 1, "debug_assert!(self.get_limit() >= coordinates.0 + coordinates.1);\n"); - indent(sb, level + 1, "self.get_buf().get_slice_at(coordinates.0, coordinates.1)\n"); + indent(sb, level + 1, "debug_assert!(self.get_limit() >= coord.0 + coord.1);\n"); + indent(sb, level + 1, "self.get_buf().get_slice_at(coord.0, coord.1)\n"); indent(sb, level, "}\n\n"); i += varDataToken.componentTokenCount(); @@ -1769,25 +1769,27 @@ private static void appendImplSbeToStringForComposite( final Appendable writer, final String decoderName, final List tokens, - final int level) throws IOException { - indent(writer, level, "impl<'a, P> SbeToString for %s

where P: Reader<'a> + ActingVersion + Default +'a {\n", decoderName); - indent(writer, level + 1, "fn sbe_to_string(mut self) -> SbeResult<(Self, String)> {\n"); - - indent(writer, level + 2, "let mut str = String::new();\n"); - - // Skip the first and last tokens as they are this composite start and end tokens. - for (int i = 1, size = tokens.size() - 1; i < size; ) { - final Token token = tokens.get(i); - final String fieldName = RustUtil.formatPropertyName(token.name()); - writeSbeToStringKeyValue(fieldName, token, writer, level + 2); - i += token.componentTokenCount(); - } + final int level) throws IOException + { + indent(writer, level, + "impl<'a, P> SbeToString for %s

where P: Reader<'a> + ActingVersion + Default +'a {\n", + decoderName); + indent(writer, level + 1, "fn sbe_to_string(mut self) -> SbeResult<(Self, String)> {\n"); + indent(writer, level + 2, "let mut str = String::new();\n"); - indent(writer, level + 2, "str = str.trim_end_matches('%s').to_string();\n\n", Separator.FIELD); + // Skip the first and last tokens as they are this composite start and end tokens. + for (int i = 1, size = tokens.size() - 1; i < size;) + { + final Token token = tokens.get(i); + final String fieldName = RustUtil.formatPropertyName(token.name()); + writeSbeToStringKeyValue(fieldName, token, writer, level + 2); + i += token.componentTokenCount(); + } - indent(writer, level + 2, "Ok((self, str))\n"); - indent(writer, level + 1, "}\n"); - indent(writer, level, "}\n"); + indent(writer, level + 2, "str = str.trim_end_matches('%s').to_string();\n\n", Separator.FIELD); + indent(writer, level + 2, "Ok((self, str))\n"); + indent(writer, level + 1, "}\n"); + indent(writer, level, "}\n"); } private static void appendConstAccessor( @@ -1810,259 +1812,280 @@ static void appendImplSbeToStringForDecoder( final List fields, final List groups, final List varData, - final int level) throws IOException{ - indent(writer, level, "impl<'a> SbeToString for %s<'a> {\n", decoderName); - indent(writer, level + 1, "fn sbe_to_string(mut self) -> SbeResult<(Self, String)> {\n"); + final int level) throws IOException + { + indent(writer, level, "impl<'a> SbeToString for %s<'a> {\n", decoderName); + indent(writer, level + 1, "fn sbe_to_string(mut self) -> SbeResult<(Self, String)> {\n"); + + indent(writer, level + 2, "let original_limit = self.get_limit();\n"); + indent(writer, level + 2, "self.set_limit(self.offset + self.acting_block_length as usize);\n\n"); + + indent(writer, level + 2, "let mut str = String::new();\n"); + indent(writer, level + 2, "str.push_str(\"[%s]\");\n\n", msgName); + + indent(writer, level + 2, "str.push('%s');\n\n", Separator.BEGIN_COMPOSITE); + indent(writer, level + 2, "str.push_str(\"sbeTemplateId=\");\n"); + indent(writer, level + 2, "str.push_str(&SBE_TEMPLATE_ID.to_string());\n\n"); - indent(writer, level + 2, "let original_limit = self.get_limit();\n"); - indent(writer, level + 2, "self.set_limit(self.offset + self.acting_block_length as usize);\n\n"); + indent(writer, level + 2, "str.push_str(\"|sbeSchemaId=\");\n"); + indent(writer, level + 2, "str.push_str(&SBE_SCHEMA_ID.to_string());\n\n"); - indent(writer, level + 2, "let mut str = String::new();\n"); - indent(writer, level + 2, "str.push_str(\"[%s]\");\n\n", msgName); + indent(writer, level + 2, "str.push_str(\"|sbeSchemaVersion=\");\n"); + indent(writer, level + 2, "if self.acting_version != SBE_SCHEMA_VERSION {\n"); + indent(writer, level + 3, "str.push_str(&self.acting_version.to_string());\n"); + indent(writer, level + 3, "str.push('/');\n"); + indent(writer, level + 2, "}\n"); + indent(writer, level + 2, "str.push_str(&SBE_SCHEMA_VERSION.to_string());\n\n"); - indent(writer, level + 2, "str.push('%s');\n\n", Separator.BEGIN_COMPOSITE); - indent(writer, level + 2, "str.push_str(\"sbeTemplateId=\");\n"); - indent(writer, level + 2, "str.push_str(&SBE_TEMPLATE_ID.to_string());\n\n"); + indent(writer, level + 2, "str.push_str(\"|sbeBlockLength=\");\n"); + indent(writer, level + 2, "if self.acting_block_length != SBE_BLOCK_LENGTH {\n"); + indent(writer, level + 3, "str.push_str(&self.acting_block_length.to_string());\n"); + indent(writer, level + 3, "str.push('/');\n"); + indent(writer, level + 2, "}\n"); + indent(writer, level + 2, "str.push_str(&SBE_BLOCK_LENGTH.to_string());\n\n"); + indent(writer, level + 2, "str.push_str(\"%s:\");\n\n", Separator.END_COMPOSITE); - indent(writer, level + 2, "str.push_str(\"|sbeSchemaId=\");\n"); - indent(writer, level + 2, "str.push_str(&SBE_SCHEMA_ID.to_string());\n\n"); + appendCommonImplSbeToStringForDecoders(writer, decoderName, fields, groups, varData, level + 2); - indent(writer, level + 2, "str.push_str(\"|sbeSchemaVersion=\");\n"); - indent(writer, level + 2, "if self.acting_version != SBE_SCHEMA_VERSION {\n"); - indent(writer, level + 3, "str.push_str(&self.acting_version.to_string());\n"); - indent(writer, level + 3, "str.push('/');\n"); + indent(writer, level + 2, "self.set_limit(original_limit);\n\n"); + indent(writer, level + 2, "Ok((self, str))\n"); + indent(writer, level + 1, "}\n"); + indent(writer, level, "}\n"); + } + + static void appendImplSbeToStringForSubgroupDecoder( + final Appendable writer, + final String decoderName, + final List fields, + final List groups, + final List varData, + final int level) throws IOException + { + indent(writer, level, + "impl<'a, P> SbeToString for %s

where P: Decoder<'a> + ActingVersion + Default +'a {\n", + decoderName); + indent(writer, level + 1, "fn sbe_to_string(mut self) -> SbeResult<(Self, String)> {\n"); + + indent(writer, level + 2, "let mut str = String::new();\n"); + + appendCommonImplSbeToStringForDecoders(writer, decoderName, fields, groups, varData, level + 2); + + indent(writer, level + 2, "Ok((self, str))\n"); + indent(writer, level + 1, "}\n"); + indent(writer, level, "}\n"); + } + + + /** Common code for both messages and subgroups decoders. + * + * @param writer the Appendable writer to write the code to. + * @param decoderName the name of the decoder. + * @param fields the list of field tokens. + * @param groups the list of group tokens. + * @param varData the list of varData tokens. + * @param level the base indentation level. + * @throws IOException if an error occurs while writing to the writer. + */ + private static void appendCommonImplSbeToStringForDecoders( + final Appendable writer, + final String decoderName, + final List fields, + final List groups, + final List varData, + final int level) throws IOException + { + indent(writer, level + 2, "// START FIELDS\n"); + for (int i = 0, size = fields.size(); i < size;) + { + final Token fieldToken = fields.get(i); + if (fieldToken.signal() == Signal.BEGIN_FIELD) + { + final String propName = RustUtil.formatPropertyName(fieldToken.name()); + writeSbeToStringKeyValue(propName, fields.get(i + 1), writer, level + 2); + i += fieldToken.componentTokenCount(); + } + else + { + ++i; + } + } + indent(writer, level + 2, "// END FIELDS\n\n"); + + indent(writer, level + 2, "// START GROUPS\n"); + for (int i = 0, size = groups.size(); i < size; i++) + { + final Token groupToken = groups.get(i); + if (groupToken.signal() != Signal.BEGIN_GROUP) + { + throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken); + } + final String groupName = RustUtil.formatPropertyName(groupToken.name()); + + indent(writer, level + 2, "let mut %s = self.%s_decoder();\n", groupName, groupName); + indent(writer, level + 2, "let %s_original_offset = %s.offset;\n", groupName, groupName); + indent(writer, level + 2, "let %s_original_index = %s.index;\n", groupName, groupName); + indent(writer, level + 2, "str.push('%s');\n", Separator.BEGIN_GROUP); + + indent(writer, level + 2, "while %s.advance()?.is_some() {\n", groupName); + indent(writer, level + 3, "let result = %s.sbe_to_string()?;\n", groupName); + indent(writer, level + 3, "%s = result.0;\n", groupName); + indent(writer, level + 3, "str.push_str(&result.1);\n"); + indent(writer, level + 3, "str.push('%s');\n", Separator.ENTRY); indent(writer, level + 2, "}\n"); - indent(writer, level + 2, "str.push_str(&SBE_SCHEMA_VERSION.to_string());\n\n"); - - indent(writer, level + 2, "str.push_str(\"|sbeBlockLength=\");\n"); - indent(writer, level + 2, "if self.acting_block_length != SBE_BLOCK_LENGTH {\n"); - indent(writer, level + 3, "str.push_str(&self.acting_block_length.to_string());\n"); - indent(writer, level + 3, "str.push('/');\n"); + + indent(writer, level + 2, "if str.ends_with('%s') {\n", Separator.ENTRY); + indent(writer, level + 3, "str.pop();\n"); indent(writer, level + 2, "}\n"); - indent(writer, level + 2, "str.push_str(&SBE_BLOCK_LENGTH.to_string());\n\n"); - indent(writer, level + 2, "str.push_str(\"%s:\");\n\n", Separator.END_COMPOSITE); - - appendCommonImplSbeToStringForDecoders(writer, decoderName, fields, groups, varData, level + 2); - - indent(writer, level + 2, "self.set_limit(original_limit);\n\n"); - indent(writer, level + 2, "Ok((self, str))\n"); - indent(writer, level + 1, "}\n"); - indent(writer, level, "}\n"); + + indent(writer, level + 2, "str.push('%s');\n", Separator.END_GROUP); + indent(writer, level + 2, "%s.offset = %s_original_offset;\n", groupName, groupName); + indent(writer, level + 2, "%s.index = %s_original_index;\n", groupName, groupName); + indent(writer, level + 2, "self = %s.parent()?;\n", groupName); + + i = findEndSignal(groups, i, Signal.END_GROUP, groupToken.name()); } + indent(writer, level + 2, "// END GROUPS\n\n"); - static void appendImplSbeToStringForSubgroupDecoder( - final Appendable writer, - final String decoderName, - final List fields, - final List groups, - final List varData, - final int level) throws IOException{ - indent(writer, level, "impl<'a, P> SbeToString for %s

where P: Decoder<'a> + ActingVersion + Default +'a {\n", decoderName); - indent(writer, level + 1, "fn sbe_to_string(mut self) -> SbeResult<(Self, String)> {\n"); - - indent(writer, level + 2, "let mut str = String::new();\n"); - - appendCommonImplSbeToStringForDecoders(writer, decoderName, fields, groups, varData, level + 2); - - indent(writer, level + 2, "Ok((self, str))\n"); - indent(writer, level + 1, "}\n"); - indent(writer, level, "}\n"); + indent(writer, level + 2, "// START VAR_DATA \n"); + for (int i = 0, size = varData.size(); i < size;) + { + final Token varDataToken = varData.get(i); + if (varDataToken.signal() != Signal.BEGIN_VAR_DATA) + { + throw new IllegalStateException("tokens must begin with BEGIN_VAR_DATA: token=" + varDataToken); } + final String charEncoding = varData.get(i + 3).encoding().characterEncoding(); + final String propName = RustUtil.formatPropertyName(varDataToken.name()); + + indent(writer, level + 2, "str.push_str(\"%s%s\");\n", propName, Separator.KEY_VALUE); + + indent(writer, level + 2, "{\n"); + indent(writer, level + 3, "let coord = self.%s_decoder();\n", propName); + // Using get_buf instead of get_slice_at due to lifetime issues with the latter. + indent(writer, level + 3, "let %s = self.get_buf().get_slice_at(coord.0, coord.1);\n", propName); - /** Common code for both messages and subgroups decoders */ - private static void appendCommonImplSbeToStringForDecoders( - final Appendable writer, - final String decoderName, - final List fields, - final List groups, - final List varData, - final int level) throws IOException{ - indent(writer, level + 2, "// START FIELDS\n"); - for (int i = 0, size = fields.size(); i < size;) + indent(writer, level + 3, "// Character encoding: '%s'\n", charEncoding); + if (isAsciiEncoding(charEncoding)) + { + indent(writer, level + 3, "for byte in %s {\n", propName); + indent(writer, level + 4, "str.push(char::from(*byte));\n"); + indent(writer, level + 3, "}\n"); + + } + else if (isUtf8Encoding(charEncoding)) + { + indent(writer, level + 3, "str.push_str(&String::from_utf8_lossy(%s));\n", propName); + } + else + { + indent(writer, level + 3, "str.push_str(&format!(\"{:?}\", %s));\n", propName); + } + indent(writer, level + 2, "}\n"); + indent(writer, level + 2, "str.push('%s');\n\n", Separator.FIELD); + + i += varDataToken.componentTokenCount(); + } + indent(writer, level + 2, "// END VAR_DATA\n"); + + indent(writer, level + 2, "if str.ends_with('%s') {\n", Separator.FIELD); + indent(writer, level + 3, "str.pop();\n"); + indent(writer, level + 2, "}\n"); + } + + private static void writeSbeToStringKeyValue( + final String fieldName, final Token typeToken, final Appendable writer, final int level) + throws IOException + { + if (typeToken.encodedLength() <= 0 || typeToken.isConstantEncoding()) + { + return; + } + + indent(writer, level, "// SIGNAL: %s\n", typeToken.signal()); + indent(writer, level, "str.push_str(\"%s%s\");\n", fieldName, Separator.KEY_VALUE); + + final String propName = RustUtil.formatPropertyName(fieldName); + + switch (typeToken.signal()) + { + case ENCODING: + if (typeToken.arrayLength() > 1) { - final Token fieldToken = fields.get(i); - if (fieldToken.signal() == Signal.BEGIN_FIELD) + indent(writer, level, "let %s = self.%s();\n", propName, propName); + if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) { - final Token encodingToken = fields.get(i + 1); - final String fieldName = RustUtil.formatPropertyName(fieldToken.name()); - writeSbeToStringKeyValue(fieldName, encodingToken, writer, level + 2); - - i += fieldToken.componentTokenCount(); + indent(writer, level, "for byte in %s {\n", propName); + indent(writer, level + 1, "str.push(char::from(byte));\n"); + indent(writer, level, "}\n"); } else { - ++i; + indent(writer, level, "str.push('%s');\n", Separator.BEGIN_ARRAY); + indent(writer, level, "for v in %s {\n", propName); + indent(writer, level + 1, "str.push_str(&v.to_string());\n"); + indent(writer, level + 1, "str.push('%s');\n", Separator.ENTRY); + indent(writer, level, "}\n"); + indent(writer, level, "if str.ends_with('%s') {\n", Separator.ENTRY); + indent(writer, level + 1, "str.pop();\n"); + indent(writer, level, "}\n"); + indent(writer, level, "str.push('%s');\n", Separator.END_ARRAY); } } - indent(writer, level + 2, "// END FIELDS\n\n"); - - indent(writer, level + 2, "// START GROUPS\n"); - for (int i = 0, size = groups.size(); i < size; i++) + else if (typeToken.encoding().presence() == Presence.REQUIRED) { - final Token groupToken = groups.get(i); - - if (groupToken.signal() != Signal.BEGIN_GROUP) - { - throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken); - } - - final String groupName = formatPropertyName(groupToken.name()); - - indent(writer, level + 2, "let mut %s = self.%s_decoder();\n", groupName, groupName); - indent(writer, level + 2, "let %s_original_offset = %s.offset;\n", groupName, groupName); - indent(writer, level + 2, "let %s_original_index = %s.index;\n", groupName, groupName); - indent(writer, level + 2, "str.push('%s');\n", Separator.BEGIN_GROUP); - - indent(writer, level + 2, "while %s.advance()?.is_some() {\n", groupName); - indent(writer, level + 3, "let result = %s.sbe_to_string()?;\n", groupName); - indent(writer, level + 3, "%s = result.0;\n", groupName); - indent(writer, level + 3, "str.push_str(&result.1);\n"); - indent(writer, level + 3, "str.push('%s');\n", Separator.ENTRY); - indent(writer, level + 2, "}\n"); - - indent(writer, level + 2, "if str.ends_with('%s') {\n", Separator.ENTRY); - indent(writer, level + 3, "str.pop();\n"); - indent(writer, level + 2, "}\n"); - - indent(writer, level + 2, "str.push('%s');\n", Separator.END_GROUP); - indent(writer, level + 2, "%s.offset = %s_original_offset;\n", groupName, groupName); - indent(writer, level + 2, "%s.index = %s_original_index;\n", groupName, groupName); - indent(writer, level + 2, "self = %s.parent()?;\n", groupName); - - i = findEndSignal(groups, i, Signal.END_GROUP, groupToken.name()); + indent(writer, level, "str.push_str(&self.%s().to_string());\n", propName); } - indent(writer, level + 2, "// END GROUPS\n\n"); - - indent(writer, level + 2, "// START VAR_DATA \n"); - for (int i = 0, size = varData.size(); i < size;) + else { - final Token varDataToken = varData.get(i); - if (varDataToken.signal() != Signal.BEGIN_VAR_DATA) - { - throw new IllegalStateException("tokens must begin with BEGIN_VAR_DATA: token=" + varDataToken); - } - - final String characterEncoding = varData.get(i + 3).encoding().characterEncoding(); - final String varDataName = formatPropertyName(varDataToken.name()); - - indent(writer, level + 2, "str.push_str(\"%s%s\");\n", varDataName, Separator.KEY_VALUE); - - indent(writer, level + 2, "{\n"); - indent(writer, level + 3, "let coordinates = self.%s_decoder();\n", varDataName); - // We're using get_buf instead of the specific get_slice_at method, because when using the latter, - // the compiler complained about the lifetimes of the values. - indent(writer, level + 3, "let %s = self.get_buf().get_slice_at(coordinates.0, coordinates.1);\n", varDataName); - - indent(writer, level + 3, "// Character encoding: '%s'\n", characterEncoding); - if (isAsciiEncoding(characterEncoding)) - { - indent(writer, level + 3, "for byte in %s {\n", varDataName); - indent(writer, level + 4, "str.push(char::from(*byte));\n"); - indent(writer, level + 3, "}\n"); - - } - else if (isUtf8Encoding(characterEncoding)) - { - indent(writer, level + 3, "str.push_str(&String::from_utf8_lossy(%s));\n", varDataName); - } else { - indent(writer, level + 3, "str.push_str(&format!(\"{:?}\", %s));\n", varDataName); - } - indent(writer, level + 2, "}\n"); - - indent(writer, level + 2, "str.push('%s');\n\n", Separator.FIELD); - - i += varDataToken.componentTokenCount(); + indent(writer, level, "let display = match self.%s() {\n", propName); + indent(writer, level + 1, "Some(value) => value.to_string(),\n"); + indent(writer, level + 1, "None => \"null\".to_string(),\n"); + indent(writer, level, "};\n"); + indent(writer, level, "str.push_str(&display);\n"); } - indent(writer, level + 2, "// END VAR_DATA\n"); - - indent(writer, level + 2, "if str.ends_with('%s') {\n", Separator.FIELD); - indent(writer, level + 3, "str.pop();\n"); - indent(writer, level + 2, "}\n"); - } + break; - private static void writeSbeToStringKeyValue( - final String fieldName, final Token typeToken, final Appendable writer, final int level) - throws IOException{ - if (typeToken.encodedLength() <= 0 || typeToken.isConstantEncoding()) - { - return; - } - - indent(writer, level, "// SIGNAL: %s\n", typeToken.signal()); - indent(writer, level, "str.push_str(\"%s%s\");\n", fieldName, Separator.KEY_VALUE); - - final String formattedFieldName = formatPropertyName(fieldName); + case BEGIN_ENUM: + indent(writer, level, "str.push_str(&self.%s().to_string());\n", fieldName); + break; - switch (typeToken.signal()) + case BEGIN_COMPOSITE: { - case ENCODING: - if (typeToken.arrayLength() > 1) { - indent(writer, level, "let %s = self.%s();\n", formattedFieldName, formattedFieldName); - if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) { - indent(writer, level, "for byte in %s {\n", formattedFieldName); - indent(writer, level + 1, "str.push(char::from(byte));\n"); - indent(writer, level, "}\n"); - } else { - indent(writer, level, "str.push('%s');\n", Separator.BEGIN_ARRAY); - indent(writer, level, "for v in %s {\n", formattedFieldName); - indent(writer, level + 1, "str.push_str(&v.to_string());\n"); - indent(writer, level + 1, "str.push('%s');\n", Separator.ENTRY); - indent(writer, level, "}\n"); - indent(writer, level, "if str.ends_with('%s') {\n", Separator.ENTRY); - indent(writer, level + 1, "str.pop();\n"); - indent(writer, level, "}\n"); - indent(writer, level, "str.push('%s');\n", Separator.END_ARRAY); - } - } else if (typeToken.encoding().presence() == Presence.REQUIRED) { - indent(writer, level, "str.push_str(&self.%s().to_string());\n", formattedFieldName); - } else { - indent(writer, level, "let display = match self.%s() {\n", formattedFieldName); - indent(writer, level + 1, "Some(value) => value.to_string(),\n"); - indent(writer, level + 1, "None => \"null\".to_string(),\n"); - indent(writer, level, "};\n"); - indent(writer, level, "str.push_str(&display);\n"); - } - break; - - case BEGIN_ENUM: - indent(writer, level, "str.push_str(&self.%s().to_string());\n", fieldName); - break; - - case BEGIN_COMPOSITE: + indent(writer, level, "str.push('%s');\n", Separator.BEGIN_COMPOSITE); + if (typeToken.version() > 0) { - indent(writer, level, "str.push('%s');\n", Separator.BEGIN_COMPOSITE); - if (typeToken.version() > 0) - { - indent(writer, level, "match self.%s_decoder() {\n", formattedFieldName); - indent(writer, level + 1, "Either::Left(self_) => {\n"); - indent(writer, level + 2, "self = self_;\n"); - indent(writer, level + 1, "},\n"); - indent(writer, level + 1, "Either::Right(mut %s) => {\n", formattedFieldName); - indent(writer, level + 2, "let (mut %s, string) = %s.sbe_to_string()?;\n", formattedFieldName, formattedFieldName); - indent(writer, level + 2, "str.push_str(&string);\n"); - indent(writer, level + 2, "self = %s.parent()?;\n", formattedFieldName); - indent(writer, level + 1, "}\n"); - indent(writer, level, "}\n"); - } else { - indent(writer, level, "let mut %s = self.%s_decoder();\n", formattedFieldName, formattedFieldName); - indent(writer, level, "let (mut %s, string) = %s.sbe_to_string()?;\n", formattedFieldName, formattedFieldName); - indent(writer, level, "str.push_str(&string);\n"); - indent(writer, level, "self = %s.parent()?;\n", formattedFieldName); - } - indent(writer, level, "str.push('%s');\n", Separator.END_COMPOSITE); - break; + indent(writer, level, "match self.%s_decoder() {\n", propName); + indent(writer, level + 1, "Either::Left(self_) => {\n"); + indent(writer, level + 2, "self = self_;\n"); + indent(writer, level + 1, "},\n"); + indent(writer, level + 1, "Either::Right(mut %s) => {\n", propName); + indent(writer, level + 2, "let (mut %s, string) = %s.sbe_to_string()?;\n", propName, propName); + indent(writer, level + 2, "str.push_str(&string);\n"); + indent(writer, level + 2, "self = %s.parent()?;\n", propName); + indent(writer, level + 1, "}\n"); + indent(writer, level, "}\n"); } - - case BEGIN_SET: - indent(writer, level, "str.push('%s');\n", Separator.BEGIN_SET); - indent(writer, level, "str.push_str(&self.%s().sbe_to_string()?.1);\n", formattedFieldName); - indent(writer, level, "str.push('%s');\n", Separator.END_SET); - break; - - default: - break; + else + { + indent(writer, level, "let mut %s = self.%s_decoder();\n", propName, propName); + indent(writer, level, "let (mut %s, string) = %s.sbe_to_string()?;\n", propName, propName); + indent(writer, level, "str.push_str(&string);\n"); + indent(writer, level, "self = %s.parent()?;\n", propName); + } + indent(writer, level, "str.push('%s');\n", Separator.END_COMPOSITE); + break; } - indent(writer, level, "str.push('%s');\n\n", Separator.FIELD); + + case BEGIN_SET: + indent(writer, level, "str.push('%s');\n", Separator.BEGIN_SET); + indent(writer, level, "str.push_str(&self.%s().sbe_to_string()?.1);\n", propName); + indent(writer, level, "str.push('%s');\n", Separator.END_SET); + break; + + default: + break; } + indent(writer, level, "str.push('%s');\n\n", Separator.FIELD); + } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java index 03997fe65e..9e56bc259e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java @@ -152,7 +152,7 @@ static String formatFunctionName(final String value) } return sanitizeMethodOrProperty(toLowerSnakeCase(value)); } - + static String formatPropertyName(final String value) { if (value.isEmpty()) From 5d2c03d377fba4f786608fc7eb1fe4b59fea0a26 Mon Sep 17 00:00:00 2001 From: "marcio.andrade" Date: Wed, 12 Mar 2025 14:47:15 -0300 Subject: [PATCH 24/25] Revert undesired changes --- .../uk/co/real_logic/sbe/generation/rust/RustGenerator.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 3fc8c88f74..05fe6caa57 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1120,7 +1120,7 @@ static void generateDecoderVarData( // function to return slice form given coord indent(sb, level, "#[inline]\n"); - indent(sb, level, "pub fn %s_slice(&'a self, coord: (usize, usize)) -> &'a [u8] {\n", propertyName); + indent(sb, level, "pub fn %s_slice(&'a self, coordinates: (usize, usize)) -> &'a [u8] {\n", propertyName); if (varDataToken.version() > 0) { @@ -1130,8 +1130,8 @@ static void generateDecoderVarData( indent(sb, level + 1, "}\n\n"); } - indent(sb, level + 1, "debug_assert!(self.get_limit() >= coord.0 + coord.1);\n"); - indent(sb, level + 1, "self.get_buf().get_slice_at(coord.0, coord.1)\n"); + indent(sb, level + 1, "debug_assert!(self.get_limit() >= coordinates.0 + coordinates.1);\n"); + indent(sb, level + 1, "self.get_buf().get_slice_at(coordinates.0, coordinates.1)\n"); indent(sb, level, "}\n\n"); i += varDataToken.componentTokenCount(); From 070e007cc5ec31b7323e18a80b029c4dcfef1b91 Mon Sep 17 00:00:00 2001 From: "marcio.andrade" Date: Tue, 18 Mar 2025 12:11:21 -0300 Subject: [PATCH 25/25] Fix SbeToString docstring. --- .../java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index 9b2a3a79e3..88050b048b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -135,7 +135,8 @@ static void generateDecoderTraits(final String schemaVersionType, final Writer w static void generateSbeToString(final Writer writer) throws IOException { - indent(writer, 0, "/// Returns a human-readable string representation of the SBE message.\n\n"); + indent(writer, 0, "/// Returns a human-readable string representation of the SBE message.\n"); + indent(writer, 0, "///\n"); indent(writer, 0, "/// This trait works like `ToString`, but it takes `self` as value\n"); indent(writer, 0, "/// to be compatible with the generated decoders.\n"); indent(writer, 0, "pub trait SbeToString: Sized {\n");