diff --git a/protocol/src/main/java/com/zfoo/protocol/generate/GenerateProtocolNote.java b/protocol/src/main/java/com/zfoo/protocol/generate/GenerateProtocolNote.java index bd62a333..94c620b0 100644 --- a/protocol/src/main/java/com/zfoo/protocol/generate/GenerateProtocolNote.java +++ b/protocol/src/main/java/com/zfoo/protocol/generate/GenerateProtocolNote.java @@ -82,6 +82,7 @@ public abstract class GenerateProtocolNote { private static String formatNote(CodeLanguage language, String note) { switch (language) { case Cpp: + case Rust: case Java: case Kotlin: case Scala: diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/CodeLanguage.java b/protocol/src/main/java/com/zfoo/protocol/serializer/CodeLanguage.java index a8948695..c56ad65f 100644 --- a/protocol/src/main/java/com/zfoo/protocol/serializer/CodeLanguage.java +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/CodeLanguage.java @@ -23,6 +23,7 @@ import com.zfoo.protocol.serializer.kotlin.CodeGenerateKotlin; import com.zfoo.protocol.serializer.lua.CodeGenerateLua; import com.zfoo.protocol.serializer.php.CodeGeneratePhp; import com.zfoo.protocol.serializer.python.CodeGeneratePython; +import com.zfoo.protocol.serializer.rust.CodeGenerateRust; import com.zfoo.protocol.serializer.scala.CodeGenerateScala; import com.zfoo.protocol.serializer.typescript.CodeGenerateTypeScript; @@ -44,6 +45,8 @@ public enum CodeLanguage { Cpp(1 << 7, CodeGenerateCpp.class), + Rust(1 << 8, CodeGenerateRust.class), + Golang(1 << 9, CodeGenerateGolang.class), JavaScript(1 << 10, CodeGenerateJavaScript.class), diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/rust/CodeGenerateRust.java b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/CodeGenerateRust.java new file mode 100644 index 00000000..cd0d25a8 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/CodeGenerateRust.java @@ -0,0 +1,463 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.rust; + +import com.zfoo.protocol.anno.Compatible; +import com.zfoo.protocol.generate.GenerateOperation; +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.generate.GenerateProtocolNote; +import com.zfoo.protocol.generate.GenerateProtocolPath; +import com.zfoo.protocol.registration.ProtocolAnalysis; +import com.zfoo.protocol.registration.ProtocolRegistration; +import com.zfoo.protocol.serializer.CodeLanguage; +import com.zfoo.protocol.serializer.CodeTemplatePlaceholder; +import com.zfoo.protocol.serializer.ICodeGenerate; +import com.zfoo.protocol.serializer.enhance.EnhanceObjectProtocolSerializer; +import com.zfoo.protocol.serializer.reflect.*; +import com.zfoo.protocol.util.ClassUtils; +import com.zfoo.protocol.util.FileUtils; +import com.zfoo.protocol.util.ReflectionUtils; +import com.zfoo.protocol.util.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.zfoo.protocol.util.FileUtils.LS; +import static com.zfoo.protocol.util.StringUtils.TAB; + +/** + * @author godotg + */ +public class CodeGenerateRust implements ICodeGenerate { + private static final Logger logger = LoggerFactory.getLogger(CodeGenerateRust.class); + + // custom configuration + public static String protocolOutputRootPath = "zfoorust"; + private static String protocolOutputPath = StringUtils.EMPTY; + + private static final Map rustSerializerMap = new HashMap<>(); + + public static IRustSerializer rustSerializer(ISerializer serializer) { + return rustSerializerMap.get(serializer); + } + + @Override + public void init(GenerateOperation generateOperation) { + protocolOutputPath = FileUtils.joinPath(generateOperation.getProtocolPath(), protocolOutputRootPath); + FileUtils.deleteFile(new File(protocolOutputPath)); + + rustSerializerMap.put(BoolSerializer.INSTANCE, new RustBoolSerializer()); + rustSerializerMap.put(ByteSerializer.INSTANCE, new RustByteSerializer()); + rustSerializerMap.put(ShortSerializer.INSTANCE, new RustShortSerializer()); + rustSerializerMap.put(IntSerializer.INSTANCE, new RustIntSerializer()); + rustSerializerMap.put(LongSerializer.INSTANCE, new RustLongSerializer()); + rustSerializerMap.put(FloatSerializer.INSTANCE, new RustFloatSerializer()); + rustSerializerMap.put(DoubleSerializer.INSTANCE, new RustDoubleSerializer()); + rustSerializerMap.put(StringSerializer.INSTANCE, new RustStringSerializer()); + rustSerializerMap.put(ArraySerializer.INSTANCE, new RustArraySerializer()); + rustSerializerMap.put(ListSerializer.INSTANCE, new RustListSerializer()); + rustSerializerMap.put(SetSerializer.INSTANCE, new RustSetSerializer()); + rustSerializerMap.put(MapSerializer.INSTANCE, new RustMapSerializer()); + rustSerializerMap.put(ObjectProtocolSerializer.INSTANCE, new RustObjectProtocolSerializer()); + } + + @Override + public void mergerProtocol(List registrations) throws IOException { + createTemplateFile(); + + + // 生成ProtocolManager.ts文件 + var protocolManagerTemplate = ClassUtils.getFileFromClassPathToString("typescript/ProtocolManagerTemplate.ts"); + var protocol_imports_manager = new StringBuilder(); + var protocol_manager_registrations = new StringBuilder(); + protocol_imports_manager.append("import * as Protocols from './Protocols';").append(LS); + for (var registration : registrations) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + protocol_manager_registrations.append(StringUtils.format("protocols.set({}, new Protocols.{}Registration());", protocol_id, protocol_name)).append(LS); + protocol_manager_registrations.append(StringUtils.format("protocolIdMap.set(Protocols.{}, {});", protocol_name, protocol_id)).append(LS); + } + var placeholderMap = Map.of(CodeTemplatePlaceholder.protocol_imports, protocol_imports_manager.toString() + , CodeTemplatePlaceholder.protocol_manager_registrations, protocol_manager_registrations.toString()); + var formatProtocolManagerTemplate = CodeTemplatePlaceholder.formatTemplate(protocolManagerTemplate, placeholderMap); + var protocolManagerFile = new File(StringUtils.format("{}/{}", protocolOutputPath, "ProtocolManager.ts")); + FileUtils.writeStringToFile(protocolManagerFile, formatProtocolManagerTemplate, true); + logger.info("Generated TypeScript protocol manager file:[{}] is in path:[{}]", protocolManagerFile.getName(), protocolManagerFile.getAbsolutePath()); + + + var protocol_imports_protocols = new StringBuilder(); + protocol_imports_protocols.append("import IByteBuffer from './IByteBuffer';").append(LS); + var protocol_class = new StringBuilder(); + var protocol_registration = new StringBuilder(); + for (var registration : registrations) { + protocol_class.append(protocol_class(registration).replace("class ", "export class ")).append(LS); + protocol_registration.append(protocol_registration(registration)).append(LS); + } + var protocolTemplate = ClassUtils.getFileFromClassPathToString("typescript/ProtocolsTemplate.ts"); + var formatProtocolTemplate = CodeTemplatePlaceholder.formatTemplate(protocolTemplate, Map.of( + CodeTemplatePlaceholder.protocol_imports, protocol_imports_protocols.toString() + , CodeTemplatePlaceholder.protocol_class, protocol_class.toString() + , CodeTemplatePlaceholder.protocol_registration, protocol_registration.toString() + )); + var outputPath = StringUtils.format("{}/Protocols.ts", protocolOutputPath); + var file = new File(outputPath); + FileUtils.writeStringToFile(file, formatProtocolTemplate, true); + logger.info("Generated TypeScript protocol file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath()); + } + + @Override + public void foldProtocol(List registrations) throws IOException { + createTemplateFile(); + + + // 生成ProtocolManager.ts文件 + var protocolManagerTemplate = ClassUtils.getFileFromClassPathToString("typescript/ProtocolManagerTemplate.ts"); + var protocol_imports = new StringBuilder(); + var protocol_manager_registrations = new StringBuilder(); + for (var registration : registrations) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + protocol_imports.append(StringUtils.format("import {} from './{}/{}';", protocol_name, GenerateProtocolPath.protocolPathSlash(protocol_id), protocol_name)).append(LS); + protocol_imports.append(StringUtils.format("import { {}Registration } from './{}/{}';", protocol_name, GenerateProtocolPath.protocolPathSlash(protocol_id), protocol_name)).append(LS); + protocol_manager_registrations.append(StringUtils.format("protocols.set({}, new {}Registration());", protocol_id, protocol_name)).append(LS); + protocol_manager_registrations.append(StringUtils.format("protocolIdMap.set({}, {});", protocol_name, protocol_id)).append(LS); + } + var placeholderMap = Map.of(CodeTemplatePlaceholder.protocol_imports, protocol_imports.toString() + , CodeTemplatePlaceholder.protocol_manager_registrations, protocol_manager_registrations.toString()); + var formatProtocolManagerTemplate = CodeTemplatePlaceholder.formatTemplate(protocolManagerTemplate, placeholderMap); + var protocolManagerFile = new File(StringUtils.format("{}/{}", protocolOutputPath, "ProtocolManager.ts")); + FileUtils.writeStringToFile(protocolManagerFile, formatProtocolManagerTemplate, true); + logger.info("Generated TypeScript protocol manager file:[{}] is in path:[{}]", protocolManagerFile.getName(), protocolManagerFile.getAbsolutePath()); + +// +// for (var registration : registrations) { +// var protocol_id = registration.protocolId(); +// var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); +// var protocolTemplate = ClassUtils.getFileFromClassPathToString("typescript/ProtocolTemplate.ts"); +// var formatProtocolTemplate = CodeTemplatePlaceholder.formatTemplate(protocolTemplate, Map.of( +// CodeTemplatePlaceholder.protocol_id, String.valueOf(protocol_id) +// , CodeTemplatePlaceholder.protocol_name, protocol_name +// , CodeTemplatePlaceholder.protocol_imports, protocol_imports_fold(registration) +// , CodeTemplatePlaceholder.protocol_class, protocol_class(registration) +// , CodeTemplatePlaceholder.protocol_registration, protocol_registration(registration) +// )); +// var outputPath = StringUtils.format("{}/{}/{}.ts", protocolOutputPath, GenerateProtocolPath.protocolPathSlash(protocol_id), protocol_name); +// var file = new File(outputPath); +// FileUtils.writeStringToFile(file, formatProtocolTemplate, true); +// logger.info("Generated TypeScript protocol file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath()); +// } + } + + @Override + public void defaultProtocol(List registrations) throws IOException { + createTemplateFile(); + + + // 生成mod文件 + var modBuilder = new StringBuilder(); + modBuilder.append("pub mod i_byte_buffer;").append(LS); + modBuilder.append("pub mod byte_buffer;").append(LS); + modBuilder.append("pub mod protocol_manager;").append(LS); + for (var registration : registrations) { + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + modBuilder.append(StringUtils.format("pub mod {};", StringUtils.uncapitalize(protocol_name))).append(LS); + } + var modFile = new File(StringUtils.format("{}/{}", protocolOutputPath, "mod.rs")); + FileUtils.writeStringToFile(modFile, modBuilder.toString(), true); + logger.info("Generated Rust mod file:[{}] is in path:[{}]", modFile.getName(), modFile.getAbsolutePath()); + + + // 生成ProtocolManager.ts文件 + var protocolManagerTemplate = ClassUtils.getFileFromClassPathToString("rust/protocol_manager_template.rs"); + var protocol_imports = new StringBuilder(); + var protocol_manager_write_registrations = new StringBuilder(); + var protocol_manager_read_registrations = new StringBuilder(); + for (var registration : registrations) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + protocol_imports.append(StringUtils.format("use crate::{}::{}::{{}, write{}, read{}};", protocolOutputRootPath, StringUtils.uncapitalize(protocol_name), protocol_name, protocol_name, protocol_name)).append(LS); + protocol_manager_write_registrations.append(StringUtils.format("{} => write{}(buffer, packet),", protocol_id, protocol_name)).append(LS); + protocol_manager_read_registrations.append(StringUtils.format("{} => read{}(buffer),", protocol_id, protocol_name)).append(LS); + } + var placeholderMap = Map.of(CodeTemplatePlaceholder.protocol_root_path, protocolOutputRootPath + , CodeTemplatePlaceholder.protocol_imports, protocol_imports.toString() + , CodeTemplatePlaceholder.protocol_write_serialization, protocol_manager_write_registrations.toString() + , CodeTemplatePlaceholder.protocol_read_deserialization, protocol_manager_read_registrations.toString() + ); + var formatProtocolManagerTemplate = CodeTemplatePlaceholder.formatTemplate(protocolManagerTemplate, placeholderMap); + var protocolManagerFile = new File(StringUtils.format("{}/{}", protocolOutputPath, "protocol_manager.rs")); + FileUtils.writeStringToFile(protocolManagerFile, formatProtocolManagerTemplate, true); + logger.info("Generated Rust protocol manager file:[{}] is in path:[{}]", protocolManagerFile.getName(), protocolManagerFile.getAbsolutePath()); + + + for (var registration : registrations) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + var protocolTemplate = ClassUtils.getFileFromClassPathToString("rust/protocol_template.rs"); + var formatProtocolTemplate = CodeTemplatePlaceholder.formatTemplate(protocolTemplate, Map.of( + CodeTemplatePlaceholder.protocol_root_path, protocolOutputRootPath + , CodeTemplatePlaceholder.protocol_name, protocol_name + , CodeTemplatePlaceholder.protocol_imports, protocol_imports_default(registration) + , CodeTemplatePlaceholder.protocol_class, protocol_class(registration) + , CodeTemplatePlaceholder.protocol_registration, protocol_registration(registration) + )); + var outputPath = StringUtils.format("{}/{}.rs", protocolOutputPath, StringUtils.uncapitalize(protocol_name)); + var file = new File(outputPath); + FileUtils.writeStringToFile(file, formatProtocolTemplate, true); + logger.info("Generated Rust protocol file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath()); + } + } + + private void createTemplateFile() throws IOException { + var list = List.of("rust/byte_buffer.rs", "rust/i_byte_buffer.rs"); + for (var fileName : list) { + var template = ClassUtils.getFileFromClassPathToString(fileName); + var formatTemplate = CodeTemplatePlaceholder.formatTemplate(template, Map.of( + CodeTemplatePlaceholder.protocol_root_path, protocolOutputRootPath + )); + var createFile = new File(StringUtils.format("{}/{}", protocolOutputPath, StringUtils.substringAfterFirst(fileName, "rust/"))); + FileUtils.writeStringToFile(createFile, formatTemplate, false); + } + } + + private String protocol_class(ProtocolRegistration registration) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + var protocolTemplate = ClassUtils.getFileFromClassPathToString("rust/protocol_class_template.rs"); + var formatProtocolTemplate = CodeTemplatePlaceholder.formatTemplate(protocolTemplate, Map.of( + CodeTemplatePlaceholder.protocol_note, GenerateProtocolNote.protocol_note(protocol_id, CodeLanguage.Rust) + , CodeTemplatePlaceholder.protocol_name, protocol_name + , CodeTemplatePlaceholder.protocol_id, String.valueOf(protocol_id) + , CodeTemplatePlaceholder.protocol_field_definition, protocol_field_definition(registration) + )); + return formatProtocolTemplate; + } + + private String protocol_registration(ProtocolRegistration registration) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + var protocolTemplate = ClassUtils.getFileFromClassPathToString("rust/protocol_registration_template.rs"); + var formatProtocolTemplate = CodeTemplatePlaceholder.formatTemplate(protocolTemplate, Map.of( + CodeTemplatePlaceholder.protocol_name, protocol_name + , CodeTemplatePlaceholder.protocol_id, String.valueOf(protocol_id) + , CodeTemplatePlaceholder.protocol_field_definition, protocol_field_definition_new(registration) + , CodeTemplatePlaceholder.protocol_write_serialization, protocol_write_serialization(registration) + , CodeTemplatePlaceholder.protocol_read_deserialization, protocol_read_deserialization(registration) + )); + return formatProtocolTemplate; + } + + private String protocol_imports_default(ProtocolRegistration registration) { + // import IByteBuffer first + var protocolId = registration.getId(); + var importBuilder = new StringBuilder(); + // import other sub protocols + var subProtocols = ProtocolAnalysis.getFirstSubProtocolIds(protocolId); + for (var subProtocolId : subProtocols) { + var protocolName = EnhanceObjectProtocolSerializer.getProtocolClassSimpleName(subProtocolId); + importBuilder.append(StringUtils.format("use crate::{}::{}::{};", protocolOutputRootPath, StringUtils.uncapitalize(protocolName), protocolName)).append(LS); + } + return importBuilder.toString(); + } + + private String protocol_field_definition(ProtocolRegistration registration) { + var protocolId = registration.protocolId(); + var fields = registration.getFields(); + var fieldRegistrations = registration.getFieldRegistrations(); + // when generate source code fields, use origin fields sort + var sequencedFields = ReflectionUtils.notStaticAndTransientFields(registration.getConstructor().getDeclaringClass()); + var rustBuilder = new StringBuilder(); + for (var field : sequencedFields) { + var fieldRegistration = fieldRegistrations[GenerateProtocolFile.indexOf(fields, field)]; + var fieldName = field.getName(); + // 生成注释 + var fieldNotes = GenerateProtocolNote.fieldNotes(protocolId, fieldName, CodeLanguage.Rust); + for (var fieldNote : fieldNotes) { + rustBuilder.append(fieldNote).append(LS); + } + var fieldTypeDefaultValue = rustSerializer(fieldRegistration.serializer()).fieldTypeDefaultValue(field, fieldRegistration); + var fieldType = fieldTypeDefaultValue.getKey(); + var fieldDefaultValue = fieldTypeDefaultValue.getValue(); + rustBuilder.append(StringUtils.format("pub {}: {},", fieldName, fieldType)).append(LS); + } + return rustBuilder.toString(); + } + + private String protocol_field_definition_new(ProtocolRegistration registration) { + var protocolId = registration.protocolId(); + var fields = registration.getFields(); + var fieldRegistrations = registration.getFieldRegistrations(); + // when generate source code fields, use origin fields sort + var sequencedFields = ReflectionUtils.notStaticAndTransientFields(registration.getConstructor().getDeclaringClass()); + var rustBuilder = new StringBuilder(); + for (var field : sequencedFields) { + var fieldRegistration = fieldRegistrations[GenerateProtocolFile.indexOf(fields, field)]; + var fieldName = field.getName(); + // 生成注释 + var fieldNotes = GenerateProtocolNote.fieldNotes(protocolId, fieldName, CodeLanguage.Rust); + for (var fieldNote : fieldNotes) { + rustBuilder.append(fieldNote).append(LS); + } + var fieldTypeDefaultValue = rustSerializer(fieldRegistration.serializer()).fieldTypeDefaultValue(field, fieldRegistration); + var fieldType = fieldTypeDefaultValue.getKey(); + var fieldDefaultValue = fieldTypeDefaultValue.getValue(); + rustBuilder.append(StringUtils.format("{}: {},", fieldName, fieldDefaultValue)).append(LS); + } + return rustBuilder.toString(); + } + + private String protocol_write_serialization(ProtocolRegistration registration) { + GenerateProtocolFile.localVariableId = 0; + var fields = registration.getFields(); + var fieldRegistrations = registration.getFieldRegistrations(); + var rustBuilder = new StringBuilder(); + if (registration.isCompatible()) { + rustBuilder.append("let beforeWriteIndex = buffer.getWriteOffset();").append(LS); + rustBuilder.append(StringUtils.format("buffer.writeInt({});", registration.getPredictionLength())).append(LS); + } else { + rustBuilder.append("buffer.writeInt(-1);").append(LS); + } + for (var i = 0; i < fields.length; i++) { + var field = fields[i]; + var fieldRegistration = fieldRegistrations[i]; + var serializer = rustSerializer(fieldRegistration.serializer()); + if (serializer instanceof RustStringSerializer || serializer instanceof RustObjectProtocolSerializer) { + serializer.writeObject(rustBuilder, "&message." + field.getName(), 0, field, fieldRegistration); + } else { + serializer.writeObject(rustBuilder, "message." + field.getName(), 0, field, fieldRegistration); + } + } + if (registration.isCompatible()) { + rustBuilder.append(StringUtils.format("buffer.adjustPadding({}, beforeWriteIndex);", registration.getPredictionLength())).append(LS); + } + return rustBuilder.toString(); + } + + private String protocol_read_deserialization(ProtocolRegistration registration) { + GenerateProtocolFile.localVariableId = 0; + var fields = registration.getFields(); + var fieldRegistrations = registration.getFieldRegistrations(); + var rustBuilder = new StringBuilder(); + for (var i = 0; i < fields.length; i++) { + var field = fields[i]; + var fieldRegistration = fieldRegistrations[i]; + if (field.isAnnotationPresent(Compatible.class)) { + rustBuilder.append("if (buffer.compatibleRead(beforeReadIndex, length)) {").append(LS); + var compatibleReadObject = rustSerializer(fieldRegistration.serializer()).readObject(rustBuilder, 1, field, fieldRegistration); + rustBuilder.append(TAB).append(StringUtils.format("packet.{} = {};", field.getName(), compatibleReadObject)).append(LS); + rustBuilder.append("}").append(LS); + continue; + } + var readObject = rustSerializer(fieldRegistration.serializer()).readObject(rustBuilder, 0, field, fieldRegistration); + rustBuilder.append(StringUtils.format("packet.{} = {};", field.getName(), readObject)).append(LS); + } + return rustBuilder.toString(); + } + + public static String toRustClassName(String typeName) { + typeName = typeName.replaceAll("java.util.|java.lang.", StringUtils.EMPTY); + typeName = typeName.replaceAll("[a-zA-Z0-9_.]*\\.", StringUtils.EMPTY); + + // CSharp不适用基础类型的泛型,会影响性能 + switch (typeName) { + case "boolean": + case "Boolean": + typeName = "bool"; + return typeName; + case "byte": + case "Byte": + typeName = "i8"; + return typeName; + case "short": + case "Short": + typeName = "i16"; + return typeName; + case "int": + case "Integer": + typeName = "i32"; + return typeName; + case "long": + case "Long": + typeName = "i64"; + return typeName; + case "Float": + typeName = "f32"; + return typeName; + case "Double": + typeName = "f64"; + return typeName; + case "String": + typeName = "String"; + return typeName; + default: + } + + // 将boolean转为bool + typeName = typeName.replaceAll("[B|b]oolean\\[", "bool"); + typeName = typeName.replace("", "bool>"); + + // 将Byte转为byte + typeName = typeName.replace("Byte[", "i8"); + typeName = typeName.replace("Byte>", "i8>"); + typeName = typeName.replace("", "i16>"); + typeName = typeName.replace("", "i32>"); + typeName = typeName.replace("", "i64>"); + typeName = typeName.replace("", "f32>"); + typeName = typeName.replace("", "f64>"); + typeName = typeName.replace("", "String>"); + typeName = typeName.replace(" fieldTypeDefaultValue(Field field, IFieldRegistration fieldRegistration); + + void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration); + + String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration); + +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustArraySerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustArraySerializer.java new file mode 100644 index 00000000..e3bf15a8 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustArraySerializer.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.rust; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.model.Pair; +import com.zfoo.protocol.registration.field.ArrayField; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.serializer.CodeLanguage; +import com.zfoo.protocol.serializer.CutDownArraySerializer; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + +/** + * @author godotg + */ +public class RustArraySerializer implements IRustSerializer { + + @Override + public Pair fieldTypeDefaultValue(Field field, IFieldRegistration fieldRegistration) { + var type = StringUtils.format("Vec<{}>", CodeGenerateRust.toRustClassName(field.getType().getComponentType().getSimpleName())); + return new Pair<>(type, "Vec::new()"); + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + if (CutDownArraySerializer.getInstance().writeObject(builder, objectStr, field, fieldRegistration, CodeLanguage.Rust)) { + return; + } + + ArrayField arrayField = (ArrayField) fieldRegistration; + + builder.append(StringUtils.format("if ({}.is_empty()) {", objectStr)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("buffer.writeInt(0);").append(LS); + GenerateProtocolFile.addTab(builder, deep); + + builder.append("} else {").append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("buffer.writeInt({}.len() as i32);", objectStr)).append(LS); + + String element = "element" + GenerateProtocolFile.localVariableId++; + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("for {} in {} {", element, objectStr)).append(LS); + CodeGenerateRust.rustSerializer(arrayField.getArrayElementRegistration().serializer()) + .writeObject(builder, element, deep + 2, field, arrayField.getArrayElementRegistration()); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("}").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("}").append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + var cutDown = CutDownArraySerializer.getInstance().readObject(builder, field, fieldRegistration, CodeLanguage.Rust); + if (cutDown != null) { + return cutDown; + } + + ArrayField arrayField = (ArrayField) fieldRegistration; + String result = "result" + GenerateProtocolFile.localVariableId++; + var typeName = StringUtils.format("Vec<{}>", CodeGenerateRust.toRustClassName(arrayField.getType().getSimpleName())); + builder.append(StringUtils.format("let mut {}: {} = Vec::new();", result, typeName)).append(LS); + + String i = "index" + GenerateProtocolFile.localVariableId++; + String size = "size" + GenerateProtocolFile.localVariableId++; + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("let {} = buffer.readInt();", size)).append(LS); + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("if ({} > 0) {", size)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("for {} in 0 .. {} {", i, size)).append(LS); + String readObject = CodeGenerateRust.rustSerializer(arrayField.getArrayElementRegistration().serializer()) + .readObject(builder, deep + 2, field, arrayField.getArrayElementRegistration()); + GenerateProtocolFile.addTab(builder, deep + 2); + builder.append(StringUtils.format("{}.push({});", result, readObject)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("}").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("}").append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustBoolSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustBoolSerializer.java new file mode 100644 index 00000000..894faf8f --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustBoolSerializer.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.rust; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.model.Pair; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + +/** + * @author godotg + */ +public class RustBoolSerializer implements IRustSerializer { + + @Override + public Pair fieldTypeDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return new Pair<>("bool", "false"); + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("buffer.writeBool({});", objectStr)).append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + String result = "result" + GenerateProtocolFile.localVariableId++; + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("let {} = buffer.readBool(); ", result)).append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustByteSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustByteSerializer.java new file mode 100644 index 00000000..a00b8f2d --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustByteSerializer.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.rust; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.model.Pair; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + +/** + * @author godotg + */ +public class RustByteSerializer implements IRustSerializer { + + @Override + public Pair fieldTypeDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return new Pair<>("i8", "0"); + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("buffer.writeByte({});", objectStr)).append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + String result = "result" + GenerateProtocolFile.localVariableId++; + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("let {} = buffer.readByte();", result)).append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustDoubleSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustDoubleSerializer.java new file mode 100644 index 00000000..decf5786 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustDoubleSerializer.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.rust; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.model.Pair; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + +/** + * @author godotg + */ +public class RustDoubleSerializer implements IRustSerializer { + + @Override + public Pair fieldTypeDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return new Pair<>("f64", "0f64"); + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("buffer.writeDouble({});", objectStr)).append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + String result = "result" + GenerateProtocolFile.localVariableId++; + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("let {} = buffer.readDouble();", result)).append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustFloatSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustFloatSerializer.java new file mode 100644 index 00000000..ae5e9442 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustFloatSerializer.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.rust; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.model.Pair; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + +/** + * @author godotg + */ +public class RustFloatSerializer implements IRustSerializer { + + @Override + public Pair fieldTypeDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return new Pair<>("f32", "0f32"); + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("buffer.writeFloat({});", objectStr)).append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + String result = "result" + GenerateProtocolFile.localVariableId++; + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("let {} = buffer.readFloat();", result)).append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustIntSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustIntSerializer.java new file mode 100644 index 00000000..e363b467 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustIntSerializer.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.rust; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.model.Pair; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + +/** + * @author godotg + */ +public class RustIntSerializer implements IRustSerializer { + + @Override + public Pair fieldTypeDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return new Pair<>("i32", "0"); + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("buffer.writeInt({});", objectStr)).append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + String result = "result" + GenerateProtocolFile.localVariableId++; + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("let {} = buffer.readInt();", result)).append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustListSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustListSerializer.java new file mode 100644 index 00000000..d4808d44 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustListSerializer.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.rust; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.model.Pair; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.registration.field.ListField; +import com.zfoo.protocol.serializer.CodeLanguage; +import com.zfoo.protocol.serializer.CutDownListSerializer; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + +/** + * @author godotg + */ +public class RustListSerializer implements IRustSerializer { + + @Override + public Pair fieldTypeDefaultValue(Field field, IFieldRegistration fieldRegistration) { + var type = StringUtils.format("{}", CodeGenerateRust.toRustClassName(field.getGenericType().toString())); + return new Pair<>(type, "Vec::new()"); + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + if (CutDownListSerializer.getInstance().writeObject(builder, objectStr, field, fieldRegistration, CodeLanguage.Rust)) { + return; + } + + ListField listField = (ListField) fieldRegistration; + + builder.append(StringUtils.format("if ({}.is_empty()) {", objectStr)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("buffer.writeInt(0);").append(LS); + GenerateProtocolFile.addTab(builder, deep); + + builder.append("} else {").append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("buffer.writeInt({}.len() as i32);", objectStr)).append(LS); + + String element = "element" + GenerateProtocolFile.localVariableId++; + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("for {} in {} {", element, objectStr)).append(LS); + CodeGenerateRust.rustSerializer(listField.getListElementRegistration().serializer()) + .writeObject(builder, element, deep + 2, field, listField.getListElementRegistration()); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("}").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("}").append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + var cutDown = CutDownListSerializer.getInstance().readObject(builder, field, fieldRegistration, CodeLanguage.Rust); + if (cutDown != null) { + return cutDown; + } + + ListField listField = (ListField) fieldRegistration; + String result = "result" + GenerateProtocolFile.localVariableId++; + var typeName = CodeGenerateRust.toRustClassName(listField.getType().toString()); + builder.append(StringUtils.format("let mut {}: {} = Vec::new();", result, typeName)).append(LS); + + GenerateProtocolFile.addTab(builder, deep); + String size = "size" + GenerateProtocolFile.localVariableId++; + builder.append(StringUtils.format("let {} = buffer.readInt();", size)).append(LS); + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("if ({} > 0) {", size)).append(LS); + + GenerateProtocolFile.addTab(builder, deep + 1); + String i = "index" + GenerateProtocolFile.localVariableId++; + builder.append(StringUtils.format("for {} in 0 .. {} {", i, size)).append(LS); + String readObject = CodeGenerateRust.rustSerializer(listField.getListElementRegistration().serializer()) + .readObject(builder, deep + 2, field, listField.getListElementRegistration()); + GenerateProtocolFile.addTab(builder, deep + 2); + builder.append(StringUtils.format("{}.push({});", result, readObject)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("}").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("}").append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustLongSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustLongSerializer.java new file mode 100644 index 00000000..a4a1d721 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustLongSerializer.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.rust; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.model.Pair; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + +/** + * @author godotg + */ +public class RustLongSerializer implements IRustSerializer { + + @Override + public Pair fieldTypeDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return new Pair<>("i64", "0"); + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("buffer.writeLong({});", objectStr)).append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + String result = "result" + GenerateProtocolFile.localVariableId++; + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("let {} = buffer.readLong();", result)).append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustMapSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustMapSerializer.java new file mode 100644 index 00000000..f4aaed50 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustMapSerializer.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.rust; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.model.Pair; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.registration.field.MapField; +import com.zfoo.protocol.serializer.CodeLanguage; +import com.zfoo.protocol.serializer.CutDownMapSerializer; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + +/** + * @author godotg + */ +public class RustMapSerializer implements IRustSerializer { + + @Override + public Pair fieldTypeDefaultValue(Field field, IFieldRegistration fieldRegistration) { + var type = StringUtils.format("{}", CodeGenerateRust.toRustClassName(field.getGenericType().toString())); + return new Pair<>(type, "HashMap::new()"); + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + if (CutDownMapSerializer.getInstance().writeObject(builder, objectStr, field, fieldRegistration, CodeLanguage.Rust)) { + return; + } + + MapField mapField = (MapField) fieldRegistration; + builder.append(StringUtils.format("if ({}.is_empty()) {", objectStr)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("buffer.writeInt(0);").append(LS); + + GenerateProtocolFile.addTab(builder, deep); + builder.append("} else {").append(LS); + + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("buffer.writeInt({}.len() as i32);", objectStr)).append(LS); + + String key = "key" + GenerateProtocolFile.localVariableId++; + String value = "value" + GenerateProtocolFile.localVariableId++; + + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("for ({}, {}) in {} {", key, value, objectStr)).append(LS); + CodeGenerateRust.rustSerializer(mapField.getMapKeyRegistration().serializer()) + .writeObject(builder, key, deep + 2, field, mapField.getMapKeyRegistration()); + CodeGenerateRust.rustSerializer(mapField.getMapValueRegistration().serializer()) + .writeObject(builder, value, deep + 2, field, mapField.getMapValueRegistration()); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("}").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("}").append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + var cutDown = CutDownMapSerializer.getInstance().readObject(builder, field, fieldRegistration, CodeLanguage.Rust); + if (cutDown != null) { + return cutDown; + } + + MapField mapField = (MapField) fieldRegistration; + String result = "result" + GenerateProtocolFile.localVariableId++; + var typeName = CodeGenerateRust.toRustClassName(mapField.getType().toString()); + builder.append(StringUtils.format("let mut {}: {} = HashMap::new();", result, typeName)).append(LS); + + GenerateProtocolFile.addTab(builder, deep); + String size = "size" + GenerateProtocolFile.localVariableId++; + builder.append(StringUtils.format("let {} = buffer.readInt();", size)).append(LS); + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("if ({} > 0) {", size)).append(LS); + + String i = "index" + GenerateProtocolFile.localVariableId++; + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("for {} in 0 .. {} {", i, size)).append(LS); + String keyObject = CodeGenerateRust.rustSerializer(mapField.getMapKeyRegistration().serializer()) + .readObject(builder, deep + 2, field, mapField.getMapKeyRegistration()); + + + String valueObject = CodeGenerateRust.rustSerializer(mapField.getMapValueRegistration().serializer()) + .readObject(builder, deep + 2, field, mapField.getMapValueRegistration()); + GenerateProtocolFile.addTab(builder, deep + 2); + + builder.append(StringUtils.format("{}.insert({}, {});", result, keyObject, valueObject)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("}").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("}").append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustObjectProtocolSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustObjectProtocolSerializer.java new file mode 100644 index 00000000..edffd5f6 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustObjectProtocolSerializer.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.rust; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.model.Pair; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.registration.field.ObjectProtocolField; +import com.zfoo.protocol.serializer.enhance.EnhanceObjectProtocolSerializer; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + +/** + * @author godotg + */ +public class RustObjectProtocolSerializer implements IRustSerializer { + + @Override + public Pair fieldTypeDefaultValue(Field field, IFieldRegistration fieldRegistration) { + ObjectProtocolField objectProtocolField = (ObjectProtocolField) fieldRegistration; + var protocolSimpleName = EnhanceObjectProtocolSerializer.getProtocolClassSimpleName(objectProtocolField.getProtocolId()); + var defaultValue = StringUtils.format("{}::new()", protocolSimpleName); + return new Pair<>(protocolSimpleName, defaultValue); + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + ObjectProtocolField objectProtocolField = (ObjectProtocolField) fieldRegistration; + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("buffer.writePacket(&{}, {});", objectStr, objectProtocolField.getProtocolId())).append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + ObjectProtocolField objectProtocolField = (ObjectProtocolField) fieldRegistration; + var result = "result" + GenerateProtocolFile.localVariableId++; + String ptr = "result" + GenerateProtocolFile.localVariableId++; + var protocolSimpleName = EnhanceObjectProtocolSerializer.getProtocolClassSimpleName(objectProtocolField.getProtocolId()); + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("let {} = buffer.readPacket({});", result, objectProtocolField.getProtocolId())).append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("let {} = {}.downcast_ref::<{}>().unwrap();", ptr, result, protocolSimpleName)).append(LS); + return ptr; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustSetSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustSetSerializer.java new file mode 100644 index 00000000..896e3960 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustSetSerializer.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.rust; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.model.Pair; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.registration.field.SetField; +import com.zfoo.protocol.serializer.CodeLanguage; +import com.zfoo.protocol.serializer.CutDownSetSerializer; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + +/** + * @author godotg + */ +public class RustSetSerializer implements IRustSerializer { + + @Override + public Pair fieldTypeDefaultValue(Field field, IFieldRegistration fieldRegistration) { + var type = StringUtils.format("{}", CodeGenerateRust.toRustClassName(field.getGenericType().toString())); + return new Pair<>(type, "HashSet::new()"); + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + if (CutDownSetSerializer.getInstance().writeObject(builder, objectStr, field, fieldRegistration, CodeLanguage.Rust)) { + return; + } + + SetField setField = (SetField) fieldRegistration; + + builder.append(StringUtils.format("if ({}.is_empty()) {", objectStr)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("buffer.writeInt(0);").append(LS); + GenerateProtocolFile.addTab(builder, deep); + + builder.append("} else {").append(LS); + + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("buffer.writeInt({}.len() as i32);", objectStr)).append(LS); + + String element = "element" + GenerateProtocolFile.localVariableId++; + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("for {} in {} {", element, objectStr)).append(LS); + CodeGenerateRust.rustSerializer(setField.getSetElementRegistration().serializer()) + .writeObject(builder, element, deep + 2, field, setField.getSetElementRegistration()); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("}").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("}").append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + var cutDown = CutDownSetSerializer.getInstance().readObject(builder, field, fieldRegistration, CodeLanguage.Rust); + if (cutDown != null) { + return cutDown; + } + + SetField setField = (SetField) fieldRegistration; + String result = "result" + GenerateProtocolFile.localVariableId++; + var typeName = CodeGenerateRust.toRustClassName(setField.getType().toString()); + builder.append(StringUtils.format("let mut {}: {} = HashSet::new();", result, typeName)).append(LS); + + GenerateProtocolFile.addTab(builder, deep); + String size = "size" + GenerateProtocolFile.localVariableId++; + builder.append(StringUtils.format("let {} = buffer.readInt();", size)).append(LS); + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("if ({} > 0) {", size)).append(LS); + + GenerateProtocolFile.addTab(builder, deep + 1); + String i = "index" + GenerateProtocolFile.localVariableId++; + builder.append(StringUtils.format("for {} in 0 .. {} {", i, size)).append(LS); + String readObject = CodeGenerateRust.rustSerializer(setField.getSetElementRegistration().serializer()) + .readObject(builder, deep + 2, field, setField.getSetElementRegistration()); + GenerateProtocolFile.addTab(builder, deep + 2); + builder.append(StringUtils.format("{}.insert({});", result, readObject)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("}").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("}").append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustShortSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustShortSerializer.java new file mode 100644 index 00000000..28769124 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustShortSerializer.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.rust; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.model.Pair; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + +/** + * @author godotg + */ +public class RustShortSerializer implements IRustSerializer { + + @Override + public Pair fieldTypeDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return new Pair<>("i16", "0"); + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("buffer.writeShort({});", objectStr)).append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + String result = "result" + GenerateProtocolFile.localVariableId++; + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("let {} = buffer.readShort();", result)).append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustStringSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustStringSerializer.java new file mode 100644 index 00000000..dd314471 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/rust/RustStringSerializer.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.rust; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.model.Pair; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + +/** + * @author godotg + */ +public class RustStringSerializer implements IRustSerializer { + + @Override + public Pair fieldTypeDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return new Pair<>("String", "String::from(\"\")"); + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("buffer.writeString(&{});", objectStr)).append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + String result = "result" + GenerateProtocolFile.localVariableId++; + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("let {} = buffer.readString();", result)).append(LS); + return result; + } +} diff --git a/protocol/src/main/resources/rust/byte_buffer.rs b/protocol/src/main/resources/rust/byte_buffer.rs new file mode 100644 index 00000000..f29d0554 --- /dev/null +++ b/protocol/src/main/resources/rust/byte_buffer.rs @@ -0,0 +1,426 @@ +use std::any::Any; +use crate::${protocol_root_path}::i_byte_buffer::IByteBuffer; +use crate::${protocol_root_path}::i_byte_buffer::IPacket; +use crate::${protocol_root_path}::protocol_manager::write; +use crate::${protocol_root_path}::protocol_manager::readByProtocolId; + +#[allow(non_snake_case)] +pub struct ByteBuffer { + buffer: Vec, + writeOffset: i32, + readOffset: i32, +} + +#[allow(non_snake_case)] +#[allow(dead_code)] +#[allow(unused_parens)] +impl ByteBuffer { + pub fn new() -> ByteBuffer { + let mut buffer = ByteBuffer { + buffer: Vec::new(), + writeOffset: 0, + readOffset: 0, + }; + buffer.buffer.resize(128, 0); + return buffer; + } +} +#[allow(non_snake_case)] +#[allow(dead_code)] +#[allow(unused_parens)] +impl IByteBuffer for ByteBuffer { + fn getBuffer(&self) -> &Vec { + return &self.buffer; + } + + fn getWriteOffset(&self) -> i32 { + return self.writeOffset; + } + + fn setWriteOffset(&mut self, writeIndex: i32) { + self.writeOffset = writeIndex; + } + + fn getReadOffset(&self) -> i32 { + return self.readOffset; + } + + fn setReadOffset(&mut self, readIndex: i32) { + self.readOffset = readIndex; + } + + fn getCapacity(&self) -> i32 { + return self.buffer.capacity() as i32 - self.writeOffset; + } + + fn ensureCapacity(&mut self, capacity: i32) { + while capacity > self.getCapacity() { + self.buffer.resize(self.buffer.capacity() * 2, 0); + } + } + + fn isReadable(&self) -> bool { + return self.writeOffset > self.readOffset; + } + + fn writeBytes(&mut self, bytes: &[i8]) { + let length = bytes.len() as i32; + self.ensureCapacity(length); + for byte in bytes { + self.writeByte(*byte); + } + } + + fn readBytes(&mut self, count: i32) -> &[i8] { + let value = &self.buffer[self.readOffset as usize..(self.readOffset + count) as usize]; + self.readOffset += count; + return value; + } + + fn writeUBytes(&mut self, bytes: &[u8]) { + let length = bytes.len() as i32; + self.ensureCapacity(length); + for byte in bytes { + self.writeUByte(*byte); + } + } + + fn readUBytes(&mut self, count: i32) -> Vec { + let mut bytes: Vec = Vec::new(); + bytes.resize(count as usize, 0); + for i in 0..count { + bytes[i as usize] = self.readUByte(); + } + return bytes; + } + + fn toBytes(&self) -> &[i8] { + return &self.buffer[0..self.writeOffset as usize]; + } + + fn writeBool(&mut self, value: bool) { + self.ensureCapacity(1); + self.buffer[self.writeOffset as usize] = if value { 1 } else { 0 }; + self.writeOffset += 1; + } + + fn readBool(&mut self) -> bool { + let value = self.buffer[self.readOffset as usize]; + self.readOffset += 1; + return value != 0; + } + + fn writeByte(&mut self, value: i8) { + self.ensureCapacity(1); + self.buffer[self.writeOffset as usize] = value; + self.writeOffset += 1; + } + + fn readByte(&mut self) -> i8 { + let value = self.buffer[self.readOffset as usize]; + self.readOffset += 1; + return value; + } + + fn writeUByte(&mut self, value: u8) { + self.ensureCapacity(1); + self.buffer[self.writeOffset as usize] = value as i8; + self.writeOffset += 1; + } + + fn readUByte(&mut self) -> u8 { + let value = self.buffer[self.readOffset as usize]; + self.readOffset += 1; + return value as u8; + } + + fn writeShort(&mut self, value: i16) { + self.ensureCapacity(2); + self.buffer[self.writeOffset as usize] = (value >> 8) as i8; + self.buffer[self.writeOffset as usize + 1] = value as i8; + self.writeOffset += 2; + } + + fn readShort(&mut self) -> i16 { + let value = (self.buffer[self.readOffset as usize] as i16) << 8 + | (self.buffer[self.readOffset as usize + 1] as u8) as i16; + self.readOffset += 2; + return value; + } + + fn writeRawInt(&mut self, value: i32) { + self.writeByte((value >> 24) as i8); + self.writeByte((value >> 16) as i8); + self.writeByte((value >> 8) as i8); + self.writeByte(value as i8); + } + + fn readRawInt(&mut self) -> i32 { + let value = (self.readUByte() as i32) << 24 + | (self.readUByte() as i32) << 16 + | (self.readUByte() as i32) << 8 + | (self.readUByte() as i32); + return value; + } + + fn writeInt(&mut self, intValue: i32) { + let value = ((intValue << 1) ^ (intValue >> 31)) as u32; + + if (value >> 7 == 0) { + self.writeByte(value as i8); + return; + } + + if (value >> 14 == 0) { + self.writeByte((value | 0x80) as i8); + self.writeByte((value >> 7) as i8); + return; + } + + if (value >> 21 == 0) { + self.writeByte((value | 0x80) as i8); + self.writeByte(((value >> 7) | 0x80) as i8); + self.writeByte((value >> 14) as i8); + return; + } + + if (value >> 28 == 0) { + self.writeByte((value | 0x80) as i8); + self.writeByte(((value >> 7) | 0x80) as i8); + self.writeByte(((value >> 14) | 0x80) as i8); + self.writeByte((value >> 21) as i8); + return; + } + + self.writeByte((value | 0x80) as i8); + self.writeByte(((value >> 7) | 0x80) as i8); + self.writeByte(((value >> 14) | 0x80) as i8); + self.writeByte(((value >> 21) | 0x80) as i8); + self.writeByte((value >> 28) as i8); + } + + fn writeIntCount(&mut self, intValue: i32) -> i32 { + let value = ((intValue << 1) ^ (intValue >> 31)) as u32; + if (value >> 7 == 0) { + return 1; + } + if (value >> 14 == 0) { + return 2; + } + if (value >> 21 == 0) { + return 3; + } + if (value >> 28 == 0) { + return 4; + } + return 5; + } + + fn readInt(&mut self) -> i32 { + let mut b = self.readUByte() as u32; + let mut value = b & 0x7F; + if ((b & 0x80) != 0) { + b = self.readUByte() as u32; + value |= (b & 0x7F) << 7; + if ((b & 0x80) != 0) { + b = self.readUByte() as u32; + value |= (b & 0x7F) << 14; + if ((b & 0x80) != 0) { + b = self.readUByte() as u32; + value |= (b & 0x7F) << 21; + if ((b & 0x80) != 0) { + b = self.readUByte() as u32; + value |= (b & 0x7F) << 28; + } + } + } + } + return (value >> 1) as i32 ^ -((value as i32) & 1); + } + + fn writeRawLong(&mut self, value: i64) { + self.writeByte((value >> 56) as i8); + self.writeByte((value >> 48) as i8); + self.writeByte((value >> 40) as i8); + self.writeByte((value >> 32) as i8); + self.writeByte((value >> 24) as i8); + self.writeByte((value >> 16) as i8); + self.writeByte((value >> 8) as i8); + self.writeByte(value as i8); + } + + fn readRawLong(&mut self) -> i64 { + let value = (self.readUByte() as i64) << 56 + | (self.readUByte() as i64) << 48 + | (self.readUByte() as i64) << 40 + | (self.readUByte() as i64) << 32 + | (self.readUByte() as i64) << 24 + | (self.readUByte() as i64) << 16 + | (self.readUByte() as i64) << 8 + | (self.readUByte() as i64); + return value; + } + + fn writeLong(&mut self, longValue: i64) { + let value = ((longValue << 1) ^ (longValue >> 63)) as u64; + + if (value >> 7 == 0) { + self.writeByte(value as i8); + return; + } + + if (value >> 14 == 0) { + self.writeByte(((value & 0x7F) | 0x80) as i8); + self.writeByte((value >> 7) as i8); + return; + } + + if (value >> 21 == 0) { + self.writeByte((value | 0x80) as i8); + self.writeByte(((value >> 7) | 0x80) as i8); + self.writeByte((value >> 14) as i8); + return; + } + + if ((value >> 28) == 0) { + self.writeByte((value | 0x80) as i8); + self.writeByte(((value >> 7) | 0x80) as i8); + self.writeByte(((value >> 14) | 0x80) as i8); + self.writeByte((value >> 21) as i8); + return; + } + + if (value >> 35 == 0) { + self.writeByte((value | 0x80) as i8); + self.writeByte(((value >> 7) | 0x80) as i8); + self.writeByte(((value >> 14) | 0x80) as i8); + self.writeByte(((value >> 21) | 0x80) as i8); + self.writeByte((value >> 28) as i8); + return; + } + + if (value >> 42 == 0) { + self.writeByte((value | 0x80) as i8); + self.writeByte(((value >> 7) | 0x80) as i8); + self.writeByte(((value >> 14) | 0x80) as i8); + self.writeByte(((value >> 21) | 0x80) as i8); + self.writeByte(((value >> 28) | 0x80) as i8); + self.writeByte((value >> 35) as i8); + return; + } + + if (value >> 49 == 0) { + self.writeByte((value | 0x80) as i8); + self.writeByte(((value >> 7) | 0x80) as i8); + self.writeByte(((value >> 14) | 0x80) as i8); + self.writeByte(((value >> 21) | 0x80) as i8); + self.writeByte(((value >> 28) | 0x80) as i8); + self.writeByte(((value >> 35) | 0x80) as i8); + self.writeByte((value >> 42) as i8); + return; + } + + if ((value >> 56) == 0) { + self.writeByte((value | 0x80) as i8); + self.writeByte(((value >> 7) | 0x80) as i8); + self.writeByte(((value >> 14) | 0x80) as i8); + self.writeByte(((value >> 21) | 0x80) as i8); + self.writeByte(((value >> 28) | 0x80) as i8); + self.writeByte(((value >> 35) | 0x80) as i8); + self.writeByte(((value >> 42) | 0x80) as i8); + self.writeByte((value >> 49) as i8); + return; + } + + self.writeByte((value | 0x80) as i8); + self.writeByte(((value >> 7) | 0x80) as i8); + self.writeByte(((value >> 14) | 0x80) as i8); + self.writeByte(((value >> 21) | 0x80) as i8); + self.writeByte(((value >> 28) | 0x80) as i8); + self.writeByte(((value >> 35) | 0x80) as i8); + self.writeByte(((value >> 42) | 0x80) as i8); + self.writeByte(((value >> 49) | 0x80) as i8); + self.writeByte((value >> 56) as i8); + } + + fn readLong(&mut self) -> i64 { + let mut b = self.readUByte() as u64; + let mut value = b & 0x7F; + if ((b & 0x80) != 0) { + b = self.readUByte() as u64; + value |= (b & 0x7F) << 7; + if ((b & 0x80) != 0) { + b = self.readUByte() as u64; + value |= (b & 0x7F) << 14; + if ((b & 0x80) != 0) { + b = self.readUByte() as u64; + value |= (b & 0x7F) << 21; + if ((b & 0x80) != 0) { + b = self.readUByte() as u64; + value |= (b & 0x7F) << 28; + if ((b & 0x80) != 0) { + b = self.readUByte() as u64; + value |= (b & 0x7F) << 35; + if ((b & 0x80) != 0) { + b = self.readUByte() as u64; + value |= (b & 0x7F) << 42; + if ((b & 0x80) != 0) { + b = self.readUByte() as u64; + value |= (b & 0x7F) << 49; + if ((b & 0x80) != 0) { + b = self.readUByte() as u64; + value |= b << 56; + } + } + } + } + } + } + } + } + + return (value >> 1) as i64 ^ -(value as i64 & 1); + } + + fn writeFloat(&mut self, value: f32) { + self.writeRawInt(value.to_bits() as i32); + } + + fn readFloat(&mut self) -> f32 { + return f32::from_bits(self.readRawInt() as u32); + } + + fn writeDouble(&mut self, value: f64) { + self.writeRawLong(value.to_bits() as i64); + } + + fn readDouble(&mut self) -> f64 { + return f64::from_bits(self.readRawLong() as u64); + } + + fn writeString(&mut self, value: &String) { + if (value == "" || value.is_empty()) { + self.writeInt(0); + } + let bytes = value.as_bytes(); + self.writeInt(bytes.len() as i32); + self.writeUBytes(bytes); + } + + fn readString(&mut self) -> String { + let length = self.readInt(); + if (length <= 0) { + return String::from(""); + } + let bytes = self.readUBytes(length); + return String::from_utf8(bytes).unwrap(); + } + + fn writePacket(&mut self, packet: &dyn Any, protocolId: i16) { + write(self, packet, protocolId); + } + + fn readPacket(&mut self, protocolId: i16) -> Box { + return readByProtocolId(self, protocolId); + } +} diff --git a/protocol/src/main/resources/rust/i_byte_buffer.rs b/protocol/src/main/resources/rust/i_byte_buffer.rs new file mode 100644 index 00000000..44f6176b --- /dev/null +++ b/protocol/src/main/resources/rust/i_byte_buffer.rs @@ -0,0 +1,50 @@ +use std::any::Any; + +#[allow(non_snake_case)] +pub trait IPacket { + fn protocolId(&self) -> i16; +} + +#[allow(non_snake_case)] +#[allow(dead_code)] +#[allow(unused_parens)] +pub trait IByteBuffer { + fn getBuffer(&self) -> &Vec; + fn getWriteOffset(&self) -> i32; + fn setWriteOffset(&mut self, writeIndex: i32); + fn getReadOffset(&self) -> i32; + fn setReadOffset(&mut self, readIndex: i32); + fn getCapacity(&self) -> i32; + fn ensureCapacity(&mut self, capacity: i32); + fn isReadable(&self) -> bool; + fn writeBytes(&mut self, bytes: &[i8]); + fn readBytes(&mut self, count: i32) -> &[i8]; + fn writeUBytes(&mut self, bytes: &[u8]); + fn readUBytes(&mut self, count: i32) -> Vec; + fn toBytes(&self) -> &[i8]; + fn writeBool(&mut self, value: bool); + fn readBool(&mut self) -> bool; + fn writeByte(&mut self, value: i8); + fn readByte(&mut self) -> i8; + fn writeUByte(&mut self, value: u8); + fn readUByte(&mut self) -> u8; + fn writeShort(&mut self, value: i16); + fn readShort(&mut self) -> i16; + fn writeRawInt(&mut self, value: i32); + fn readRawInt(&mut self) -> i32; + fn writeInt(&mut self, intValue: i32); + fn writeIntCount(&mut self, intValue: i32) -> i32; + fn readInt(&mut self) -> i32; + fn writeRawLong(&mut self, value: i64); + fn readRawLong(&mut self) -> i64; + fn writeLong(&mut self, longValue: i64); + fn readLong(&mut self) -> i64; + fn writeFloat(&mut self, value: f32); + fn readFloat(&mut self) -> f32; + fn writeDouble(&mut self, value: f64); + fn readDouble(&mut self) -> f64; + fn writeString(&mut self, value: &String); + fn readString(&mut self) -> String; + fn writePacket(&mut self, packet: &dyn Any, protocolId: i16); + fn readPacket(&mut self, protocolId: i16) -> Box; +} diff --git a/protocol/src/main/resources/rust/protocol_class_template.rs b/protocol/src/main/resources/rust/protocol_class_template.rs new file mode 100644 index 00000000..ba459128 --- /dev/null +++ b/protocol/src/main/resources/rust/protocol_class_template.rs @@ -0,0 +1,4 @@ +${protocol_note} +pub struct ${protocol_name} { + ${protocol_field_definition} +} \ No newline at end of file diff --git a/protocol/src/main/resources/rust/protocol_manager_template.rs b/protocol/src/main/resources/rust/protocol_manager_template.rs new file mode 100644 index 00000000..44cfae15 --- /dev/null +++ b/protocol/src/main/resources/rust/protocol_manager_template.rs @@ -0,0 +1,24 @@ +use std::any::Any; +use std::collections::HashMap; +use crate::${protocol_root_path}::i_byte_buffer::{IByteBuffer, IPacket}; +${protocol_imports} + +pub fn write(buffer: &mut dyn IByteBuffer, packet: &dyn Any, protocolId: i16) { + match protocolId { + ${protocol_write_serialization} + _ => println!("protocolId:[{}] not found", protocolId) + } +} + +pub fn read(buffer: &mut dyn IByteBuffer) -> Box { + let protocolId = buffer.readShort(); + return readByProtocolId(buffer, protocolId); +} + +pub fn readByProtocolId(buffer: &mut dyn IByteBuffer, protocolId: i16) -> Box { + let packet = match protocolId { + ${protocol_read_deserialization} + _ => Box::new(String::from("protocolId not found")) + }; + return packet; +} \ No newline at end of file diff --git a/protocol/src/main/resources/rust/protocol_registration_template.rs b/protocol/src/main/resources/rust/protocol_registration_template.rs new file mode 100644 index 00000000..378d54be --- /dev/null +++ b/protocol/src/main/resources/rust/protocol_registration_template.rs @@ -0,0 +1,33 @@ +impl IPacket for ${protocol_name} { + fn protocolId(&self) -> i16 { + return ${protocol_id}; + } +} + +impl ${protocol_name} { + pub fn new() -> ${protocol_name} { + let mut packet = ${protocol_name} { + ${protocol_field_definition} + }; + return packet; + } +} + +pub fn write${protocol_name}(buffer: &mut dyn IByteBuffer, packet: &dyn Any) { + let message = packet.downcast_ref::<${protocol_name}>().unwrap(); + ${protocol_write_serialization} +} + +pub fn read${protocol_name}(buffer: &mut dyn IByteBuffer) -> Box { + let length = buffer.readInt(); + let mut packet = ${protocol_name}::new(); + if (length == 0) { + return Box::new(packet); + } + let beforeReadIndex = buffer.getReadOffset(); + ${protocol_read_deserialization} + if (length > 0) { + buffer.setReadOffset(beforeReadIndex + length); + } + return Box::new(packet); +} diff --git a/protocol/src/main/resources/rust/protocol_template.rs b/protocol/src/main/resources/rust/protocol_template.rs new file mode 100644 index 00000000..5ef6c54b --- /dev/null +++ b/protocol/src/main/resources/rust/protocol_template.rs @@ -0,0 +1,8 @@ +use std::any::Any; +use std::collections::HashMap; +use std::collections::HashSet; +use crate::${protocol_root_path}::i_byte_buffer::{IByteBuffer, IPacket}; +${protocol_imports} +${protocol_class} + +${protocol_registration} \ No newline at end of file