public static CodeGenerator defaultRustGenerator(final Ir ir, final String outputDir) { return new RustGenerator(ir, new RustFlatFileOutputManager(outputDir, ir.applicableNamespace())); } }
public void generate() throws IOException { generateSharedImports(ir, outputManager); generateResultEnums(outputManager); generateDecoderScratchStruct(outputManager); generateEncoderScratchStruct(ir, outputManager); generateEitherEnum(outputManager); generateEnums(ir, outputManager); generateComposites(ir, outputManager); generateBitSets(ir, outputManager); final int headerSize = totalByteSize(ir.headerStructure()); for (final List<Token> tokens : ir.messages()) { final MessageComponents components = MessageComponents.collectMessageComponents(tokens); final String messageTypeName = formatTypeName(components.messageToken.name()); final Optional<FieldsRepresentationSummary> fieldsRepresentation = generateFieldsRepresentation(messageTypeName, components, outputManager); generateMessageHeaderDefault(ir, outputManager, components.messageToken); // Avoid the work of recomputing the group tree twice per message final List<GroupTreeNode> groupTree = buildGroupTrees(messageTypeName, components.groups); generateGroupFieldRepresentations(outputManager, groupTree); generateMessageDecoder(outputManager, components, groupTree, fieldsRepresentation, headerSize); generateMessageEncoder(outputManager, components, groupTree, fieldsRepresentation, headerSize); } }
constantRustTypeName = getRustTypeForPrimitivePossiblyArray( signalToken, constantRustPrimitiveType); constantRustExpression = generateRustLiteral( appendConstAccessor(writer, name, constantRustTypeName, constantRustExpression); i += componentTokenCount;
private void generateGroupFieldRepresentations( final Appendable appendable, final List<GroupTreeNode> groupTree) throws IOException { for (final GroupTreeNode node : groupTree) { appendStructHeader(appendable, node.contextualName + "Member", true); appendStructFields(appendable, node.simpleNamedFields); appendable.append("}\n"); generateConstantAccessorImpl(appendable, node.contextualName + "Member", node.rawFields); generateGroupFieldRepresentations(appendable, node.groups); } }
private static void generateSingleComposite(final List<Token> tokens, final OutputManager outputManager) throws IOException { final Token beginToken = tokens.get(0); final String originalTypeName = beginToken.applicableTypeName(); final String formattedTypeName = formatTypeName(originalTypeName); final SplitCompositeTokens splitTokens = SplitCompositeTokens.splitInnerTokens(tokens); try (Writer writer = outputManager.createOutput(formattedTypeName)) { appendStructHeader(writer, formattedTypeName, true); appendStructFields(writer, splitTokens.nonConstantEncodingTokens()); writer.append("}\n"); generateConstantAccessorImpl(writer, formattedTypeName, getMessageBody(tokens)); } }
appendStructHeader(out, withLifetime(memberCoderType), false); final String rustCountType = rustTypeName(node.numInGroupType); final String contentProperty; contentBearingType = withLifetime(node.parent.get().contextualName + "MemberEncoder"); contentBearingType = withLifetime(SCRATCH_ENCODER_TYPE); appendImplWithLifetimeHeader(out, memberCoderType); indent(out, 1, "pub fn next_%s_member(mut self, fields: &%s)", formatMethodName(node.originalName), fieldsType); out.append(format(" -> CodecResult<%s> {\n", withLifetime(nextCoderType))); final String scratchChain = toScratchChain(node); indent(out, 2, "%s.write_type::<%s>(fields, %s)?; // block length\n", scratchChain, fieldsType, node.blockLength); formatMethodName(node.originalName), withLifetime(afterGroupCoderType)); indent(out, 2, "%s.write_at_position::<%s>(self.count_write_pos, &self.count, %s)?;\n", scratchChain, rustCountType, node.numInGroupType.size()); appendStructHeader(out, withLifetime(headerCoderType), false); indent(out, 1, "%s: %s,\n", contentProperty, contentBearingType); out.append("}\n"); appendImplWithLifetimeHeader(out, headerCoderType); indent(out).append("#[inline]\n"); indent(out, 1, "fn wrap(%s: %s) -> Self {\n", contentProperty, contentBearingType);
appendStructHeader(out, withLifetime(memberDecoderType), false); final String rustCountType = rustTypeName(node.numInGroupType); final String contentProperty; contentBearingType = withLifetime(node.parent.get().contextualName + "MemberDecoder"); contentBearingType = withLifetime(SCRATCH_DECODER_TYPE); appendImplWithLifetimeHeader(out, memberDecoderType); nextDecoderType.startsWith("Either") ? nextDecoderType : withLifetime(nextDecoderType))); toScratchChain(node), node.contextualName + "Member", node.blockLength); indent(out, 2).append("self.index += 1;\n"); appendStructHeader(out, withLifetime(headerDecoderType), false); indent(out, 1, "%s: %s,\n", contentProperty, contentBearingType).append("}\n"); appendImplWithLifetimeHeader(out, headerDecoderType); indent(out, 1, "fn wrap(%s: %s) -> Self {\n", contentProperty, contentBearingType); indent(out, 2, "%s { %s: %s }\n", headerDecoderType, contentProperty, contentProperty) formatMethodName(node.originalName), groupLevelNextDecoderType); indent(out, 2, "%s.skip_bytes(%s)?; // Skip reading block length for now\n", toScratchChain(node), node.blockLengthType.size()); indent(out, 2, "let count = *%s.read_type::<%s>(%s)?;\n", toScratchChain(node), rustTypeName(node.numInGroupType), node.numInGroupType.size()); indent(out, 2).append("if count > 0 {\n"); indent(out, 3, "Ok(Either::Left(%s::new(self.%s, count)))\n",
final int groupHeaderTokenCount = dimensionsToken.componentTokenCount(); final List<Token> dimensionsTokens = groupsTokens.subList(i, i + groupHeaderTokenCount); final PrimitiveType numInGroupType = findPrimitiveByTokenName(dimensionsTokens, "numInGroup"); final Token blockLengthToken = findPrimitiveTokenByTokenName(dimensionsTokens, "blockLength"); final int blockLength = groupToken.encodedLength(); final PrimitiveType blockLengthType = blockLengthToken.encoding().primitiveType(); buildGroupTrees(contextualName, childGroups, Optional.of(node));
try (Writer writer = outputManager.createOutput(name + " variable-length data")) appendStructHeader(writer, withLifetime(decoderType), false); final String contentPropertyName = groupDepth > 0 ? "parent" : SCRATCH_DECODER_PROPERTY; indent(writer, 1, "%s: %s,\n", contentPropertyName, withLifetime(contentType)); writer.append("}\n"); appendImplWithLifetimeHeader(writer, decoderType); indent(writer, 1, "fn wrap(%s: %s) -> Self {\n", contentPropertyName, withLifetime(contentType)); indent(writer, 2, "%s { %s: %s }\n", decoderType, contentPropertyName, contentPropertyName).append(INDENT).append("}\n"); atEndOfGroup ? nextDecoderType : withLifetime(nextDecoderType)); indent(writer, 2, "let count = *%s.read_type::<%s>(%s)?;\n", toScratchChain(groupDepth), rustTypeName(this.lengthType), this.lengthType.size());
String generateMessageHeaderCoder( final String messageTypeName, final OutputManager outputManager, final String topType, final int headerSize) throws IOException { final String messageHeaderRepresentation = "MessageHeader"; final String headerCoderType = messageTypeName + messageHeaderRepresentation + name(); try (Writer writer = outputManager.createOutput(headerCoderType)) { appendScratchWrappingStruct(writer, headerCoderType); RustGenerator.appendImplWithLifetimeHeader(writer, headerCoderType); appendWrapMethod(writer, headerCoderType); appendDirectCodeMethods(writer, "header", messageHeaderRepresentation, topType, headerSize); writer.append("}\n"); } return headerCoderType; } }
private static String fullGenerateForResource( final SingleStringOutputManager outputManager, final String localResourceName) { outputManager.clear(); final RustGenerator rustGenerator = new RustGenerator(generateIrForResource(localResourceName), outputManager); try { rustGenerator.generate(); } catch (final IOException e) { throw new AssertionFailedError("Unexpected IOException during generation. " + e.getMessage()); } return outputManager.toString(); }
@Test public void generateSharedImports() throws IOException { RustGenerator.generateSharedImports(generateIrForResource(BROAD_USE_CASES_SCHEMA), outputManager); assertContainsSharedImports(outputManager.toString()); }
appendStructHeader(writer, wrapperName, true); indent(writer, 1, "pub message_header: MessageHeader\n"); writer.append("}\n");
appendStructHeader(out, withLifetime(memberCoderType), false); final String rustCountType = rustTypeName(node.numInGroupType); final String contentProperty; contentBearingType = withLifetime(node.parent.get().contextualName + "MemberEncoder"); contentBearingType = withLifetime(SCRATCH_ENCODER_TYPE); appendImplWithLifetimeHeader(out, memberCoderType); indent(out, 1, "pub fn next_%s_member(mut self, fields: &%s)", formatMethodName(node.originalName), fieldsType); out.append(format(" -> CodecResult<%s> {\n", withLifetime(nextCoderType))); final String scratchChain = toScratchChain(node); indent(out, 2, "%s.write_type::<%s>(fields, %s)?; // block length\n", scratchChain, fieldsType, node.blockLength); formatMethodName(node.originalName), withLifetime(afterGroupCoderType)); indent(out, 2, "%s.write_at_position::<%s>(self.count_write_pos, &self.count, %s)?;\n", scratchChain, rustCountType, node.numInGroupType.size()); appendStructHeader(out, withLifetime(headerCoderType), false); indent(out, 1, "%s: %s,\n", contentProperty, contentBearingType); out.append("}\n"); appendImplWithLifetimeHeader(out, headerCoderType); indent(out).append("#[inline]\n"); indent(out, 1, "fn wrap(%s: %s) -> Self {\n", contentProperty, contentBearingType);
appendStructHeader(out, withLifetime(memberDecoderType), false); final String rustCountType = rustTypeName(node.numInGroupType); final String contentProperty; contentBearingType = withLifetime(node.parent.get().contextualName + "MemberDecoder"); contentBearingType = withLifetime(SCRATCH_DECODER_TYPE); appendImplWithLifetimeHeader(out, memberDecoderType); nextDecoderType.startsWith("Either") ? nextDecoderType : withLifetime(nextDecoderType))); toScratchChain(node), node.contextualName + "Member", node.blockLength); indent(out, 2).append("self.index += 1;\n"); appendStructHeader(out, withLifetime(headerDecoderType), false); indent(out, 1, "%s: %s,\n", contentProperty, contentBearingType).append("}\n"); appendImplWithLifetimeHeader(out, headerDecoderType); indent(out, 1, "fn wrap(%s: %s) -> Self {\n", contentProperty, contentBearingType); indent(out, 2, "%s { %s: %s }\n", headerDecoderType, contentProperty, contentProperty) formatMethodName(node.originalName), groupLevelNextDecoderType); indent(out, 2, "%s.skip_bytes(%s)?; // Skip reading block length for now\n", toScratchChain(node), node.blockLengthType.size()); indent(out, 2, "let count = *%s.read_type::<%s>(%s)?;\n", toScratchChain(node), rustTypeName(node.numInGroupType), node.numInGroupType.size()); indent(out, 2).append("if count > 0 {\n"); indent(out, 3, "Ok(Either::Left(%s::new(self.%s, count)))\n",
try (Writer writer = outputManager.createOutput(messageTypeName + " Fixed-size Fields")) appendStructHeader(writer, representationStruct, true); appendStructFields(writer, namedFieldTokens); writer.append("}\n"); generateConstantAccessorImpl(writer, representationStruct, components.fields);
private void generateGroupFieldRepresentations( final Appendable appendable, final List<GroupTreeNode> groupTree) throws IOException { for (final GroupTreeNode node : groupTree) { appendStructHeader(appendable, node.contextualName + "Member", true); appendStructFields(appendable, node.simpleNamedFields); appendable.append("}\n"); generateConstantAccessorImpl(appendable, node.contextualName + "Member", node.rawFields); generateGroupFieldRepresentations(appendable, node.groups); } }
final int groupHeaderTokenCount = dimensionsToken.componentTokenCount(); final List<Token> dimensionsTokens = groupsTokens.subList(i, i + groupHeaderTokenCount); final PrimitiveType numInGroupType = findPrimitiveByTokenName(dimensionsTokens, "numInGroup"); final Token blockLengthToken = findPrimitiveTokenByTokenName(dimensionsTokens, "blockLength"); final int blockLength = groupToken.encodedLength(); final PrimitiveType blockLengthType = blockLengthToken.encoding().primitiveType(); buildGroupTrees(contextualName, childGroups, Optional.of(node));
try (Writer writer = outputManager.createOutput(name + " variable-length data")) appendStructHeader(writer, withLifetime(decoderType), false); final String contentPropertyName = groupDepth > 0 ? "parent" : codecType.scratchProperty(); indent(writer, 1, "%s: %s,\n", contentPropertyName, withLifetime(contentType)); writer.append("}\n"); appendImplWithLifetimeHeader(writer, decoderType); indent(writer, 1, "fn wrap(%s: %s) -> Self {\n", contentPropertyName, withLifetime(contentType)); indent(writer, 2, "%s { %s: %s }\n", decoderType, contentPropertyName, contentPropertyName).append(INDENT).append("}\n"); atEndOfGroup ? nextCoderType : withLifetime(nextCoderType));
private static String generateFixedFieldCoder( final String messageTypeName, final OutputManager outputManager, final String topType, final Optional<FieldsRepresentationSummary> fieldsRepresentationOptional, final RustCodecType codecType) throws IOException { if (!fieldsRepresentationOptional.isPresent()) { return topType; } final FieldsRepresentationSummary fieldsRepresentation = fieldsRepresentationOptional.get(); try (Writer writer = outputManager.createOutput(messageTypeName + " Fixed fields " + codecType.name())) { final String representationStruct = fieldsRepresentation.typeName; final String decoderName = representationStruct + codecType.name(); codecType.appendScratchWrappingStruct(writer, decoderName); appendImplWithLifetimeHeader(writer, decoderName); codecType.appendWrapMethod(writer, decoderName); codecType.appendDirectCodeMethods(writer, formatMethodName(messageTypeName) + "_fields", representationStruct, topType, fieldsRepresentation.numBytes); writer.append("}\n"); // TODO - Move read position further if in-message blockLength exceeds fixed fields representation size // will require piping some data from the previously-read message header return decoderName; } }