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 4b0dea02..6e4cdce7 100644 --- a/protocol/src/main/java/com/zfoo/protocol/serializer/CodeLanguage.java +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/CodeLanguage.java @@ -22,6 +22,7 @@ import com.zfoo.protocol.serializer.javascript.CodeGenerateJavaScript; import com.zfoo.protocol.serializer.kotlin.CodeGenerateKotlin; import com.zfoo.protocol.serializer.lua.CodeGenerateLua; import com.zfoo.protocol.serializer.python.CodeGeneratePython; +import com.zfoo.protocol.serializer.scala.CodeGenerateScala; import com.zfoo.protocol.serializer.typescript.CodeGenerateTypeScript; /** @@ -34,11 +35,11 @@ public enum CodeLanguage { */ Enhance(1, null), - Java(1<<1, CodeGenerateJava.class), + Java(1 << 1, CodeGenerateJava.class), - Kotlin(1<<2, CodeGenerateKotlin.class), + Kotlin(1 << 2, CodeGenerateKotlin.class), - Scala(1<<3, null), + Scala(1 << 3, CodeGenerateScala.class), Cpp(1 << 7, CodeGenerateCpp.class), diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/scala/CodeGenerateScala.java b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/CodeGenerateScala.java new file mode 100644 index 00000000..210d61b2 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/CodeGenerateScala.java @@ -0,0 +1,428 @@ +/* + * 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.scala; + +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.registration.field.IFieldRegistration; +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 CodeGenerateScala implements ICodeGenerate { + private static final Logger logger = LoggerFactory.getLogger(CodeGenerateScala.class); + + // custom configuration + public static String protocolOutputRootPath = "zfooscala"; + private static String protocolOutputPath = StringUtils.EMPTY; + public static String protocolPackage = "com.zfoo.scala"; + + private static final Map scalaSerializerMap = new HashMap<>(); + + public static IScalaSerializer scalaSerializer(ISerializer serializer) { + return scalaSerializerMap.get(serializer); + } + + @Override + public void init(GenerateOperation generateOperation) { + protocolOutputPath = FileUtils.joinPath(generateOperation.getProtocolPath(), protocolOutputRootPath); + FileUtils.deleteFile(new File(protocolOutputPath)); + + scalaSerializerMap.put(BooleanSerializer.INSTANCE, new ScalaBooleanSerializer()); + scalaSerializerMap.put(ByteSerializer.INSTANCE, new ScalaByteSerializer()); + scalaSerializerMap.put(ShortSerializer.INSTANCE, new ScalaShortSerializer()); + scalaSerializerMap.put(IntSerializer.INSTANCE, new ScalaIntSerializer()); + scalaSerializerMap.put(LongSerializer.INSTANCE, new ScalaLongSerializer()); + scalaSerializerMap.put(FloatSerializer.INSTANCE, new ScalaFloatSerializer()); + scalaSerializerMap.put(DoubleSerializer.INSTANCE, new ScalaDoubleSerializer()); + scalaSerializerMap.put(StringSerializer.INSTANCE, new ScalaStringSerializer()); + scalaSerializerMap.put(ArraySerializer.INSTANCE, new ScalaArraySerializer()); + scalaSerializerMap.put(ListSerializer.INSTANCE, new ScalaListSerializer()); + scalaSerializerMap.put(SetSerializer.INSTANCE, new ScalaSetSerializer()); + scalaSerializerMap.put(MapSerializer.INSTANCE, new ScalaMapSerializer()); + scalaSerializerMap.put(ObjectProtocolSerializer.INSTANCE, new ScalaObjectProtocolSerializer()); + } + + @Override + public void mergerProtocol(List registrations) throws IOException { + createTemplateFile(); + var protocol_root_path = StringUtils.format("package {}", protocolPackage); + + var protocolManagerTemplate = ClassUtils.getFileFromClassPathToString("scala/ProtocolManagerTemplate.scala"); + var protocol_manager_registrations = new StringBuilder(); + for (var registration : registrations) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + protocol_manager_registrations.append(StringUtils.format("protocols({}) = Registration{}", protocol_id, protocol_name)).append(LS); + protocol_manager_registrations.append(StringUtils.format("protocolIdMap.put(classOf[{}], {})", protocol_name, protocol_id)).append(LS); + } + + var placeholderMap = Map.of(CodeTemplatePlaceholder.protocol_root_path, protocol_root_path + , CodeTemplatePlaceholder.protocol_imports, StringUtils.EMPTY + , CodeTemplatePlaceholder.protocol_manager_registrations, protocol_manager_registrations.toString()); + var formatProtocolManagerTemplate = CodeTemplatePlaceholder.formatTemplate(protocolManagerTemplate, placeholderMap); + var protocolManagerFile = new File(StringUtils.format("{}/{}", protocolOutputRootPath, "ProtocolManager.scala")); + FileUtils.writeStringToFile(protocolManagerFile, formatProtocolManagerTemplate, true); + logger.info("Generated Scala protocol manager file:[{}] is in path:[{}]", protocolManagerFile.getName(), protocolManagerFile.getAbsolutePath()); + + var protocol_class = new StringBuilder(); + var protocol_registration = new StringBuilder(); + for (var registration : GenerateProtocolFile.subProtocolFirst(registrations)) { + var protocol_id = registration.protocolId(); + // protocol + protocol_class.append(protocol_class(registration)).append(LS); + // registration + protocol_registration.append(protocol_registration(registration)).append(LS); + } + var protocolTemplate = ClassUtils.getFileFromClassPathToString("scala/ProtocolsTemplate.scala"); + var formatProtocolTemplate = CodeTemplatePlaceholder.formatTemplate(protocolTemplate, Map.of( + CodeTemplatePlaceholder.protocol_root_path, protocol_root_path + , CodeTemplatePlaceholder.protocol_imports, StringUtils.EMPTY + , CodeTemplatePlaceholder.protocol_class, protocol_class.toString() + , CodeTemplatePlaceholder.protocol_registration, protocol_registration.toString() + )); + var outputPath = StringUtils.format("{}/Protocols.scala", protocolOutputPath); + var file = new File(outputPath); + FileUtils.writeStringToFile(file, formatProtocolTemplate, true); + logger.info("Generated Scala protocol file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath()); + } + + @Override + public void foldProtocol(List registrations) throws IOException { + createTemplateFile(); + + var protocolManagerTemplate = ClassUtils.getFileFromClassPathToString("scala/ProtocolManagerTemplate.scala"); + var protocol_manager_registrations = new StringBuilder(); + var protocol_imports = new StringBuilder(); + for (var registration : registrations) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + protocol_imports.append(StringUtils.format("import {}.{}.{}", protocolPackage, GenerateProtocolPath.protocolPathPeriod(protocol_id), protocol_name)).append(LS); + protocol_imports.append(StringUtils.format("import {}.{}.Registration{}", protocolPackage, GenerateProtocolPath.protocolPathPeriod(protocol_id), protocol_name)).append(LS); + protocol_manager_registrations.append(StringUtils.format("protocols({}) = Registration{}", protocol_id, protocol_name)).append(LS); + protocol_manager_registrations.append(StringUtils.format("protocolIdMap.put(classOf[{}], {})", protocol_name, protocol_id)).append(LS); + } + + var placeholderMap = Map.of(CodeTemplatePlaceholder.protocol_root_path, StringUtils.format("package {}", protocolPackage) + , 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("{}/{}", protocolOutputRootPath, "ProtocolManager.scala")); + FileUtils.writeStringToFile(protocolManagerFile, formatProtocolManagerTemplate, true); + logger.info("Generated Scala 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("scala/ProtocolTemplate.scala"); + var protocol_root_path = StringUtils.format("package {}.{}", protocolPackage, GenerateProtocolPath.protocolPathPeriod(protocol_id)); + var formatProtocolTemplate = CodeTemplatePlaceholder.formatTemplate(protocolTemplate, Map.of( + CodeTemplatePlaceholder.protocol_root_path, protocol_root_path + , CodeTemplatePlaceholder.protocol_imports, protocol_imports_fold(registration) + , CodeTemplatePlaceholder.protocol_note, GenerateProtocolNote.protocol_note(protocol_id, CodeLanguage.Scala) + , CodeTemplatePlaceholder.protocol_name, protocol_name + , CodeTemplatePlaceholder.protocol_class, protocol_class(registration) + , CodeTemplatePlaceholder.protocol_registration, protocol_registration(registration) + )); + var outputPath = StringUtils.format("{}/{}/{}.scala", protocolOutputPath, GenerateProtocolPath.protocolPathSlash(protocol_id), protocol_name); + var file = new File(outputPath); + FileUtils.writeStringToFile(file, formatProtocolTemplate, true); + logger.info("Generated Scala protocol file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath()); + } + } + + @Override + public void defaultProtocol(List registrations) throws IOException { + createTemplateFile(); + var protocol_root_path = StringUtils.format("package {}", protocolPackage); + + var protocolManagerTemplate = ClassUtils.getFileFromClassPathToString("scala/ProtocolManagerTemplate.scala"); + var protocol_manager_registrations = new StringBuilder(); + for (var registration : registrations) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + protocol_manager_registrations.append(StringUtils.format("protocols({}) = Registration{}", protocol_id, protocol_name)).append(LS); + protocol_manager_registrations.append(StringUtils.format("protocolIdMap.put(classOf[{}], {})", protocol_name, protocol_id)).append(LS); + } + + var placeholderMap = Map.of(CodeTemplatePlaceholder.protocol_root_path, protocol_root_path + , CodeTemplatePlaceholder.protocol_imports, StringUtils.EMPTY + , CodeTemplatePlaceholder.protocol_manager_registrations, protocol_manager_registrations.toString()); + var formatProtocolManagerTemplate = CodeTemplatePlaceholder.formatTemplate(protocolManagerTemplate, placeholderMap); + var protocolManagerFile = new File(StringUtils.format("{}/{}", protocolOutputRootPath, "ProtocolManager.scala")); + FileUtils.writeStringToFile(protocolManagerFile, formatProtocolManagerTemplate, true); + logger.info("Generated Scala 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("scala/ProtocolTemplate.scala"); + var formatProtocolTemplate = CodeTemplatePlaceholder.formatTemplate(protocolTemplate, Map.of( + CodeTemplatePlaceholder.protocol_root_path, protocol_root_path + , CodeTemplatePlaceholder.protocol_imports, StringUtils.EMPTY + , CodeTemplatePlaceholder.protocol_class, protocol_class(registration) + , CodeTemplatePlaceholder.protocol_registration, protocol_registration(registration) + )); + var outputPath = StringUtils.format("{}/{}.scala", protocolOutputPath, protocol_name); + var file = new File(outputPath); + FileUtils.writeStringToFile(file, formatProtocolTemplate, true); + logger.info("Generated Scala protocol file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath()); + } + } + + private void createTemplateFile() { + var rootPackage = StringUtils.format("package {}", protocolPackage); + var list = List.of("scala/IProtocolRegistration.scala" + , "scala/ByteBuffer.scala"); + for (var fileName : list) { + // IProtocolRegistration + var template = ClassUtils.getFileFromClassPathToString(fileName); + var formatTemplate = CodeTemplatePlaceholder.formatTemplate(template, Map.of( + CodeTemplatePlaceholder.protocol_root_path, rootPackage + , CodeTemplatePlaceholder.protocol_imports, StringUtils.EMPTY + )); + var createFile = new File(StringUtils.format("{}/{}", protocolOutputPath, StringUtils.substringAfterFirst(fileName, "scala/"))); + 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("scala/ProtocolClassTemplate.scala"); + var formatProtocolTemplate = CodeTemplatePlaceholder.formatTemplate(protocolTemplate, Map.of( + CodeTemplatePlaceholder.protocol_note, GenerateProtocolNote.protocol_note(protocol_id, CodeLanguage.Scala) + , 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("scala/ProtocolRegistrationTemplate.scala"); + var formatProtocolTemplate = CodeTemplatePlaceholder.formatTemplate(protocolTemplate, Map.of( + CodeTemplatePlaceholder.protocol_name, protocol_name + , CodeTemplatePlaceholder.protocol_id, String.valueOf(protocol_id) + , CodeTemplatePlaceholder.protocol_write_serialization, protocol_write_serialization(registration) + , CodeTemplatePlaceholder.protocol_read_deserialization, protocol_read_deserialization(registration) + )); + return formatProtocolTemplate; + } + + + private String protocol_imports_fold(ProtocolRegistration registration) { + var protocolId = registration.getId(); + var subProtocols = ProtocolAnalysis.getAllSubProtocolIds(protocolId); + var scalaBuilder = new StringBuilder(); + for (var subProtocolId : subProtocols) { + var protocolName = EnhanceObjectProtocolSerializer.getProtocolClassSimpleName(subProtocolId); + var subProtocolPath = StringUtils.format("import {}.{}.{}", protocolPackage, GenerateProtocolPath.protocolPathPeriod(subProtocolId), protocolName); + scalaBuilder.append(subProtocolPath).append(LS); + } + scalaBuilder.append(StringUtils.format("import {}.IProtocolRegistration", protocolPackage)).append(LS); + scalaBuilder.append(StringUtils.format("import {}.ByteBuffer", protocolPackage)).append(LS); + return scalaBuilder.toString(); + } + + private String protocol_field_definition(ProtocolRegistration registration) { + var protocolId = registration.getId(); + var fields = registration.getFields(); + var fieldRegistrations = registration.getFieldRegistrations(); + var scalaBuilder = new StringBuilder(); + var sequencedFields = ReflectionUtils.notStaticAndTransientFields(registration.getConstructor().getDeclaringClass()); + for (int i = 0; i < sequencedFields.size(); i++) { + var field = sequencedFields.get(i); + IFieldRegistration fieldRegistration = fieldRegistrations[GenerateProtocolFile.indexOf(fields, field)]; + var fieldName = field.getName(); + // 生成注释 + var fieldNotes = GenerateProtocolNote.fieldNotes(protocolId, fieldName, CodeLanguage.Scala); + for (var fieldNote : fieldNotes) { + scalaBuilder.append(fieldNote).append(LS); + } + var pair = scalaSerializer(fieldRegistration.serializer()).field(field, fieldRegistration); + scalaBuilder.append(StringUtils.format("var {}: {} = {}", fieldName, pair.getKey(), pair.getValue())).append(LS); + } + return scalaBuilder.toString(); + } + + + private String protocol_write_serialization(ProtocolRegistration registration) { + GenerateProtocolFile.localVariableId = 0; + var fields = registration.getFields(); + var fieldRegistrations = registration.getFieldRegistrations(); + var scalaBuilder = new StringBuilder(); + if (registration.isCompatible()) { + scalaBuilder.append("val beforeWriteIndex = buffer.getWriteOffset").append(LS); + scalaBuilder.append(StringUtils.format("buffer.writeInt({})", registration.getPredictionLength())).append(LS); + } else { + scalaBuilder.append("buffer.writeInt(-1)").append(LS); + } + for (var i = 0; i < fields.length; i++) { + var field = fields[i]; + var fieldRegistration = fieldRegistrations[i]; + scalaSerializer(fieldRegistration.serializer()).writeObject(scalaBuilder, "message." + field.getName(), 0, field, fieldRegistration); + } + if (registration.isCompatible()) { + scalaBuilder.append(StringUtils.format("buffer.adjustPadding({}, beforeWriteIndex)", registration.getPredictionLength())).append(LS); + } + return scalaBuilder.toString(); + } + + + private String protocol_read_deserialization(ProtocolRegistration registration) { + GenerateProtocolFile.localVariableId = 0; + var fields = registration.getFields(); + var fieldRegistrations = registration.getFieldRegistrations(); + var scalaBuilder = new StringBuilder(); + for (var i = 0; i < fields.length; i++) { + var field = fields[i]; + var fieldRegistration = fieldRegistrations[i]; + + if (field.isAnnotationPresent(Compatible.class)) { + scalaBuilder.append("if (buffer.compatibleRead(beforeReadIndex, length)) {").append(LS); + var compatibleReadObject = scalaSerializer(fieldRegistration.serializer()).readObject(scalaBuilder, 1, field, fieldRegistration); + scalaBuilder.append(TAB).append(StringUtils.format("packet.{} = {}", field.getName(), compatibleReadObject)).append(LS); + scalaBuilder.append("}").append(LS); + continue; + } + var readObject = scalaSerializer(fieldRegistration.serializer()).readObject(scalaBuilder, 0, field, fieldRegistration); + scalaBuilder.append(StringUtils.format("packet.{} = {}", field.getName(), readObject)).append(LS); + } + return scalaBuilder.toString(); + } + + public static String toScalaClassName(String typeName) { + typeName = typeName.replaceAll("java.util.|java.lang.", StringUtils.EMPTY); + typeName = typeName.replaceAll("[a-zA-Z0-9_.]*\\.", StringUtils.EMPTY); + + switch (typeName) { + case "boolean": + case "Boolean": + typeName = "Boolean"; + return typeName; + case "byte": + case "Byte": + typeName = "Byte"; + return typeName; + case "short": + case "Short": + typeName = "Short"; + return typeName; + case "int": + case "Integer": + typeName = "Int"; + return typeName; + case "long": + case "Long": + typeName = "Long"; + return typeName; + case "float": + case "Float": + typeName = "Float"; + return typeName; + case "double": + case "Double": + typeName = "Double"; + return typeName; + case "char": + case "Character": + case "String": + typeName = "String"; + return typeName; + default: + } + + // 将boolean转为bool + typeName = typeName.replaceAll("[B|b]oolean\\[", "Boolean"); + typeName = typeName.replace("", "Boolean]"); + + // 将Byte转为byte + typeName = typeName.replace("Byte[", "Byte"); + typeName = typeName.replace("Byte>", "Byte]"); + typeName = typeName.replace("", "Short]"); + typeName = typeName.replace("", "Int]"); + typeName = typeName.replace("", "Long]"); + typeName = typeName.replace("", "Float]"); + typeName = typeName.replace("", "Double]"); + typeName = typeName.replace("", "String]"); + typeName = typeName.replace("", "String]"); + typeName = typeName.replace("", "]"); + + return typeName; + } + +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/scala/IScalaSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/IScalaSerializer.java new file mode 100644 index 00000000..54ddbc1a --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/IScalaSerializer.java @@ -0,0 +1,34 @@ +/* + * 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.scala; + +import com.zfoo.protocol.model.Pair; +import com.zfoo.protocol.registration.field.IFieldRegistration; + +import java.lang.reflect.Field; + +/** + * @author godotg + */ +public interface IScalaSerializer { + /** + * 获取属性的类型,默认值 + */ + Pair field(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/scala/ScalaArraySerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaArraySerializer.java new file mode 100644 index 00000000..2785d48b --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaArraySerializer.java @@ -0,0 +1,111 @@ +/* + * 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.scala; + +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 ScalaArraySerializer implements IScalaSerializer { + + @Override + public Pair field(Field field, IFieldRegistration fieldRegistration) { + var type = StringUtils.format("Array[{}]", CodeGenerateScala.toScalaClassName(field.getType().getComponentType().getSimpleName())); + return new Pair<>(type, "_"); + } + + @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.Scala)) { + return; + } + + ArrayField arrayField = (ArrayField) fieldRegistration; + + builder.append(StringUtils.format("buffer.writeInt({}.length)", objectStr)).append(LS); + GenerateProtocolFile.addTab(builder, deep); + String length = "length" + GenerateProtocolFile.localVariableId++; + builder.append(StringUtils.format("val {} = {}.length", length, objectStr)).append(LS); + + String i = "i" + GenerateProtocolFile.localVariableId++; + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("for ({} <- 0 until {}) {", i, length)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + String element = "element" + GenerateProtocolFile.localVariableId++; + builder.append(StringUtils.format("val {} = {}({})", element, objectStr, i)).append(LS); + + CodeGenerateScala.scalaSerializer(arrayField.getArrayElementRegistration().serializer()) + .writeObject(builder, element, deep + 1, field, arrayField.getArrayElementRegistration()); + + 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.Scala); + if (cutDown != null) { + return cutDown; + } + + + var arrayField = (ArrayField) fieldRegistration; + var result = "result" + GenerateProtocolFile.localVariableId++; + + var typeName = CodeGenerateScala.toScalaClassName(arrayField.getType().getSimpleName()); + + var i = "index" + GenerateProtocolFile.localVariableId++; + var init = "init" + GenerateProtocolFile.localVariableId++; + var size = "size" + GenerateProtocolFile.localVariableId++; + builder.append(StringUtils.format("val {} = buffer.readInt", size)).append(LS); + + GenerateProtocolFile.addTab(builder, deep); + var pair = CodeGenerateScala.scalaSerializer(arrayField.getArrayElementRegistration().serializer()).field(field, arrayField.getArrayElementRegistration()); + var defaultValue = pair.getValue(); + if (defaultValue.equals("null")) { + defaultValue = StringUtils.format("{}()", typeName); + } + builder.append(StringUtils.format("val {} = new mutable.ArrayBuffer[{}]()", result, typeName)).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 ({} <- 0 until {}) {", i, size)).append(LS); + var readObject = CodeGenerateScala.scalaSerializer(arrayField.getArrayElementRegistration().serializer()) + .readObject(builder, deep + 2, field, arrayField.getArrayElementRegistration()); + GenerateProtocolFile.addTab(builder, deep + 2); + builder.append(StringUtils.format("{}.addOne({})", result, readObject)); + builder.append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("}").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("}").append(LS); + + return result + ".toArray"; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaBooleanSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaBooleanSerializer.java new file mode 100644 index 00000000..84c746c5 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaBooleanSerializer.java @@ -0,0 +1,49 @@ +/* + * 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.scala; + +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 ScalaBooleanSerializer implements IScalaSerializer { + + @Override + public Pair field(Field field, IFieldRegistration fieldRegistration) { + return new Pair<>("Boolean", "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("val {} = buffer.readBool", result)).append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaByteSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaByteSerializer.java new file mode 100644 index 00000000..08fe531f --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaByteSerializer.java @@ -0,0 +1,50 @@ +/* + * 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.scala; + +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 ScalaByteSerializer implements IScalaSerializer { + + @Override + public Pair field(Field field, IFieldRegistration fieldRegistration) { + return new Pair<>("Byte", "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("val {} = buffer.readByte", result)).append(LS); + return result; + } + +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaDoubleSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaDoubleSerializer.java new file mode 100644 index 00000000..f6f701a2 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaDoubleSerializer.java @@ -0,0 +1,50 @@ +/* + * 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.scala; + +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 ScalaDoubleSerializer implements IScalaSerializer { + + @Override + public Pair field(Field field, IFieldRegistration fieldRegistration) { + return new Pair<>("Double", "0D"); + } + + @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("val {} = buffer.readDouble", result)).append(LS); + return result; + } + +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaFloatSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaFloatSerializer.java new file mode 100644 index 00000000..6598e390 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaFloatSerializer.java @@ -0,0 +1,50 @@ +/* + * 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.scala; + +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 ScalaFloatSerializer implements IScalaSerializer { + + @Override + public Pair field(Field field, IFieldRegistration fieldRegistration) { + return new Pair<>("Float", "0f"); + } + + @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("val {} = buffer.readFloat", result)).append(LS); + return result; + } + +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaIntSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaIntSerializer.java new file mode 100644 index 00000000..9942b4f6 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaIntSerializer.java @@ -0,0 +1,49 @@ +/* + * 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.scala; + +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 ScalaIntSerializer implements IScalaSerializer { + + @Override + public Pair field(Field field, IFieldRegistration fieldRegistration) { + return new Pair<>("Int", "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("val {} = buffer.readInt", result)).append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaListSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaListSerializer.java new file mode 100644 index 00000000..e72ff2a0 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaListSerializer.java @@ -0,0 +1,98 @@ +/* + * 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.scala; + +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 ScalaListSerializer implements IScalaSerializer { + + @Override + public Pair field(Field field, IFieldRegistration fieldRegistration) { + var type = StringUtils.format("{}", CodeGenerateScala.toScalaClassName(field.getGenericType().toString())); + return new Pair<>(type, "_"); + } + + @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.Scala)) { + return; + } + + ListField listField = (ListField) fieldRegistration; + + builder.append(StringUtils.format("buffer.writeInt({}.size)", objectStr)).append(LS); + + GenerateProtocolFile.addTab(builder, deep); + String element = "element" + GenerateProtocolFile.localVariableId++; + builder.append(StringUtils.format("for ({} <- {}) {", element, objectStr)).append(LS); + + CodeGenerateScala.scalaSerializer(listField.getListElementRegistration().serializer()) + .writeObject(builder, element, deep + 1, field, listField.getListElementRegistration()); + + 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.Scala); + if (cutDown != null) { + return cutDown; + } + + var listField = (ListField) fieldRegistration; + var result = "result" + GenerateProtocolFile.localVariableId++; + + var typeName = CodeGenerateScala.toScalaClassName(listField.getType().toString()); + + var i = "index" + GenerateProtocolFile.localVariableId++; + var size = "size" + GenerateProtocolFile.localVariableId++; + + builder.append(StringUtils.format("val {} = buffer.readInt", size)).append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("val {} = new mutable.ListBuffer{}()", result, StringUtils.substringAfterFirst(typeName, "List"))).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 ({} <- 0 until {}) {", i, size)).append(LS); + var readObject = CodeGenerateScala.scalaSerializer(listField.getListElementRegistration().serializer()) + .readObject(builder, deep + 2, field, listField.getListElementRegistration()); + GenerateProtocolFile.addTab(builder, deep + 2); + builder.append(StringUtils.format("{}.addOne({})", result, readObject)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("}").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("}").append(LS); + + return result + ".toList"; + } + +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaLongSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaLongSerializer.java new file mode 100644 index 00000000..0b1edce5 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaLongSerializer.java @@ -0,0 +1,50 @@ +/* + * 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.scala; + +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 ScalaLongSerializer implements IScalaSerializer { + + @Override + public Pair field(Field field, IFieldRegistration fieldRegistration) { + return new Pair<>("Long", "0L"); + } + + @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("val {} = buffer.readLong", result)).append(LS); + return result; + } + +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaMapSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaMapSerializer.java new file mode 100644 index 00000000..3352d647 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaMapSerializer.java @@ -0,0 +1,107 @@ +/* + * 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.scala; + +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 ScalaMapSerializer implements IScalaSerializer { + + @Override + public Pair field(Field field, IFieldRegistration fieldRegistration) { + var type = StringUtils.format("{}", CodeGenerateScala.toScalaClassName(field.getGenericType().toString())); + return new Pair<>(type, "_"); + } + + @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.Scala)) { + return; + } + + MapField mapField = (MapField) fieldRegistration; + + builder.append(StringUtils.format("buffer.writeInt({}.size)", objectStr)).append(LS); + + GenerateProtocolFile.addTab(builder, deep); + String key = "keyElement" + GenerateProtocolFile.localVariableId++; + String value = "valueElement" + GenerateProtocolFile.localVariableId++; + builder.append(StringUtils.format("for (({}, {}) <- {}) {", key,value, objectStr)).append(LS); + + CodeGenerateScala.scalaSerializer(mapField.getMapKeyRegistration().serializer()) + .writeObject(builder, key, deep + 1, field, mapField.getMapKeyRegistration()); + CodeGenerateScala.scalaSerializer(mapField.getMapValueRegistration().serializer()) + .writeObject(builder, value, deep + 1, field, mapField.getMapValueRegistration()); + + 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.Scala); + if (cutDown != null) { + return cutDown; + } + + MapField mapField = (MapField) fieldRegistration; + String result = "result" + GenerateProtocolFile.localVariableId++; + + var typeName = CodeGenerateScala.toScalaClassName(mapField.getType().toString()); + + String size = "size" + GenerateProtocolFile.localVariableId++; + builder.append(StringUtils.format("val {} = buffer.readInt", size)).append(LS); + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("val {} = new mutable.HashMap{}()", result, StringUtils.substringAfterFirst(typeName, "Map"))).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 ({} <- 0 until {}) {", i, size)).append(LS); + + String keyObject = CodeGenerateScala.scalaSerializer(mapField.getMapKeyRegistration().serializer()) + .readObject(builder, deep + 2, field, mapField.getMapKeyRegistration()); + + + String valueObject = CodeGenerateScala.scalaSerializer(mapField.getMapValueRegistration().serializer()) + .readObject(builder, deep + 2, field, mapField.getMapValueRegistration()); + GenerateProtocolFile.addTab(builder, deep + 2); + + builder.append(StringUtils.format("{}.put({}, {})", result, keyObject, valueObject)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("}").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("}").append(LS); + return result + ".toMap"; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaObjectProtocolSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaObjectProtocolSerializer.java new file mode 100644 index 00000000..a154c655 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaObjectProtocolSerializer.java @@ -0,0 +1,61 @@ +/* + * 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.scala; + +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 ScalaObjectProtocolSerializer implements IScalaSerializer { + + @Override + public Pair field(Field field, IFieldRegistration fieldRegistration) { + ObjectProtocolField objectProtocolField = (ObjectProtocolField) fieldRegistration; + var protocolSimpleName = EnhanceObjectProtocolSerializer.getProtocolClassSimpleName(objectProtocolField.getProtocolId()); + return new Pair<>(protocolSimpleName, "_"); + } + + @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; + String result = "result" + GenerateProtocolFile.localVariableId++; + + var protocolSimpleName = EnhanceObjectProtocolSerializer.getProtocolClassSimpleName(objectProtocolField.getProtocolId()); + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("val {} = buffer.readPacket({}).asInstanceOf[{}]", result, objectProtocolField.getProtocolId(), protocolSimpleName)) + .append(LS); + return result; + } + +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaSetSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaSetSerializer.java new file mode 100644 index 00000000..59220e59 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaSetSerializer.java @@ -0,0 +1,98 @@ +/* + * 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.scala; + +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 ScalaSetSerializer implements IScalaSerializer { + + @Override + public Pair field(Field field, IFieldRegistration fieldRegistration) { + var type = StringUtils.format("{}", CodeGenerateScala.toScalaClassName(field.getGenericType().toString())); + return new Pair<>(type, "_"); + } + + @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.Scala)) { + return; + } + + SetField setField = (SetField) fieldRegistration; + + builder.append(StringUtils.format("buffer.writeInt({}.size)", objectStr)).append(LS); + + String element = "i" + GenerateProtocolFile.localVariableId++; + GenerateProtocolFile.addTab(builder, deep ); + builder.append(StringUtils.format("for ({} <- {}) {", element, objectStr)).append(LS); + + CodeGenerateScala.scalaSerializer(setField.getSetElementRegistration().serializer()) + .writeObject(builder, element, deep + 1, field, setField.getSetElementRegistration()); + + 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.Scala); + if (cutDown != null) { + return cutDown; + } + + SetField setField = (SetField) fieldRegistration; + var result = "result" + GenerateProtocolFile.localVariableId++; + + var typeName = CodeGenerateScala.toScalaClassName(setField.getType().toString()); + + var i = "index" + GenerateProtocolFile.localVariableId++; + var size = "size" + GenerateProtocolFile.localVariableId++; + builder.append(StringUtils.format("val {} = buffer.readInt", size)).append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("val {} = new mutable.HashSet{}()", result, StringUtils.substringAfterFirst(typeName, "Set"))).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 ({} <- 0 until {}) {", i, size)).append(LS); + + var readObject = CodeGenerateScala.scalaSerializer(setField.getSetElementRegistration().serializer()) + .readObject(builder, deep + 2, field, setField.getSetElementRegistration()); + GenerateProtocolFile.addTab(builder, deep + 2); + builder.append(StringUtils.format("{}.add({})", result, readObject)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("}").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("}").append(LS); + + return result + ".toSet"; + } + +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaShortSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaShortSerializer.java new file mode 100644 index 00000000..1dcb25a4 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaShortSerializer.java @@ -0,0 +1,50 @@ +/* + * 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.scala; + +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 ScalaShortSerializer implements IScalaSerializer { + + @Override + public Pair field(Field field, IFieldRegistration fieldRegistration) { + return new Pair<>("Short", "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("val {} = buffer.readShort", result)).append(LS); + return result; + } + +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaStringSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaStringSerializer.java new file mode 100644 index 00000000..b93848a6 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/scala/ScalaStringSerializer.java @@ -0,0 +1,51 @@ +/* + * 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.scala; + +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 ScalaStringSerializer implements IScalaSerializer { + + @Override + public Pair field(Field field, IFieldRegistration fieldRegistration) { + return new Pair<>("String", "_"); + } + + @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("val {} = buffer.readString", result)).append(LS); + return result; + } + + +} diff --git a/protocol/src/main/resources/scala/ByteBuffer.scala b/protocol/src/main/resources/scala/ByteBuffer.scala new file mode 100644 index 00000000..fd68ff6a --- /dev/null +++ b/protocol/src/main/resources/scala/ByteBuffer.scala @@ -0,0 +1,1207 @@ +${protocol_root_path} +import java.nio.charset.Charset +import scala.collection.mutable +import scala.collection.mutable.{ArrayBuffer, ListBuffer} + +class ByteBuffer { + val INIT_SIZE: Int = 128 + val MAX_SIZE: Int = 655537 + // *******************************************String*************************************************** + val DEFAULT_CHARSET_NAME: String = "UTF-8" + val DEFAULT_CHARSET: Charset = Charset.forName(DEFAULT_CHARSET_NAME) + + private var buffer: Array[Byte] = new Array[Byte](INIT_SIZE) + private var writeOffset: Int = 0 + private var readOffset: Int = 0 + + def adjustPadding(predictionLength: Int, beforewriteIndex: Int): Unit = { + // 因为写入的是可变长的int,如果预留的位置过多,则清除多余的位置 + val currentwriteIndex: Int = writeOffset + val predictionCount: Int = writeIntCount(predictionLength) + val length: Int = currentwriteIndex - beforewriteIndex - predictionCount + val lengthCount: Int = writeIntCount(length) + val padding: Int = lengthCount - predictionCount + if (padding == 0) { + writeOffset = beforewriteIndex + writeInt(length) + writeOffset = currentwriteIndex + } + else { + val bytes: Array[Byte] = new Array[Byte](length) + System.arraycopy(buffer, currentwriteIndex - length, bytes, 0, length) + writeOffset = beforewriteIndex + writeInt(length) + writeBytes(bytes) + } + } + + def compatibleRead(beforeReadIndex: Int, length: Int): Boolean = length != -1 && readOffset < length + beforeReadIndex + + // -------------------------------------------------get/set------------------------------------------------- + def getWriteOffset: Int = writeOffset + + def setWriteOffset(writeIndex: Int): Unit = { + if (writeIndex > buffer.length) throw new RuntimeException("writeIndex[" + writeIndex + "] out of bounds exception: readerIndex: " + readOffset + ", writerIndex: " + writeOffset + "(expected: 0 <= readerIndex <= writerIndex <= capacity:" + buffer.length) + writeOffset = writeIndex + } + + def getReadOffset: Int = readOffset + + def setReadOffset(readIndex: Int): Unit = { + if (readIndex > writeOffset) throw new RuntimeException("readIndex[" + readIndex + "] out of bounds exception: readerIndex: " + readOffset + ", writerIndex: " + writeOffset + "(expected: 0 <= readerIndex <= writerIndex <= capacity:" + buffer.length) + readOffset = readIndex + } + + def getBytes: Array[Byte] = buffer + + def toBytes: Array[Byte] = buffer.slice(0, writeOffset) + + def isReadable: Boolean = writeOffset > readOffset + + // -------------------------------------------------write/read------------------------------------------------- + def writeBool(value: Boolean): Unit = { + ensureCapacity(1) + buffer(writeOffset) = if (value) 1.toByte else 0.toByte + writeOffset += 1 + } + + def readBool: Boolean = { + val byteValue: Byte = buffer(readOffset) + readOffset += 1 + byteValue == 1 + } + + def writeByte(value: Byte): Unit = { + ensureCapacity(1) + buffer(writeOffset) = value + writeOffset += 1 + } + + def readByte: Byte = buffer({ + readOffset += 1; + readOffset - 1 + }) + + def getCapacity: Int = buffer.length - writeOffset + + def ensureCapacity(capacity: Int): Unit = { + while (capacity - getCapacity > 0) { + val newSize: Int = buffer.length * 2 + if (newSize > MAX_SIZE) throw new RuntimeException("Bytebuf max size is [655537], out of memory error") + val newBytes: Array[Byte] = new Array[Byte](newSize) + System.arraycopy(buffer, 0, newBytes, 0, buffer.length) + this.buffer = newBytes + } + } + + def writeBytes(bytes: Array[Byte]): Unit = { + writeBytes(bytes, bytes.length) + } + + def writeBytes(bytes: Array[Byte], length: Int): Unit = { + ensureCapacity(length) + System.arraycopy(bytes, 0, buffer, writeOffset, length) + writeOffset += length + } + + def readBytes(count: Int): Array[Byte] = { + val bytes: Array[Byte] = new Array[Byte](count) + System.arraycopy(buffer, readOffset, bytes, 0, count) + readOffset += count + bytes + } + + def writeShort(value: Short): Unit = { + ensureCapacity(2) + buffer(writeOffset) = (value >>> 8).toByte + writeOffset = writeOffset + 1 + buffer(writeOffset) = value.toByte + writeOffset = writeOffset + 1 + } + + def readShort: Short = (buffer({ + readOffset += 1; + readOffset - 1 + }) << 8 | buffer({ + readOffset += 1; + readOffset - 1 + }) & 255).toShort + + // *******************************************int*************************************************** + def writeInt(value: Int): Int = writeVarInt((value << 1) ^ (value >> 31)) + + def writeVarInt(value: Int): Int = { + var a: Int = value >>> 7 + if (a == 0) { + writeByte(value.toByte) + return 1 + } + ensureCapacity(5) + buffer({ + writeOffset += 1; + writeOffset - 1 + }) = (value | 0x80).toByte + var b: Int = value >>> 14 + if (b == 0) { + buffer({ + writeOffset += 1; + writeOffset - 1 + }) = a.toByte + return 2 + } + buffer({ + writeOffset += 1; + writeOffset - 1 + }) = (a | 0x80).toByte + a = value >>> 21 + if (a == 0) { + buffer({ + writeOffset += 1; + writeOffset - 1 + }) = b.toByte + return 3 + } + buffer({ + writeOffset += 1; + writeOffset - 1 + }) = (b | 0x80).toByte + b = value >>> 28 + if (b == 0) { + buffer({ + writeOffset += 1; + writeOffset - 1 + }) = a.toByte + return 4 + } + buffer({ + writeOffset += 1; + writeOffset - 1 + }) = (a | 0x80).toByte + buffer({ + writeOffset += 1; + writeOffset - 1 + }) = b.toByte + 5 + } + + def readInt: Int = { + var b: Int = readByte + var value: Int = b + if (b < 0) { + b = readByte + value = value & 0x0000007F | b << 7 + if (b < 0) { + b = readByte + value = value & 0x00003FFF | b << 14 + if (b < 0) { + b = readByte + value = value & 0x001FFFFF | b << 21 + if (b < 0) value = value & 0x0FFFFFFF | readByte << 28 + } + } + } + (value >>> 1) ^ -(value & 1) + } + + def writeIntCount(value: Int): Int = { + val v = (value << 1) ^ (value >> 31) + if (v >>> 7 == 0) return 1 + if (v >>> 14 == 0) return 2 + if (v >>> 21 == 0) return 3 + if (v >>> 28 == 0) return 4 + 5 + } + + // 写入没有压缩的int + def writeRawInt(value: Int): Unit = { + ensureCapacity(4) + buffer({ + writeOffset += 1; + writeOffset - 1 + }) = (value >>> 24).toByte + buffer({ + writeOffset += 1; + writeOffset - 1 + }) = (value >>> 16).toByte + buffer({ + writeOffset += 1; + writeOffset - 1 + }) = (value >>> 8).toByte + buffer({ + writeOffset += 1; + writeOffset - 1 + }) = value.toByte + } + + // 读取没有压缩的int + def readRawInt: Int = (buffer({ + readOffset += 1; + readOffset - 1 + }) & 255) << 24 | (buffer({ + readOffset += 1; + readOffset - 1 + }) & 255) << 16 | (buffer({ + readOffset += 1; + readOffset - 1 + }) & 255) << 8 | buffer({ + readOffset += 1; + readOffset - 1 + }) & 255 + + // *******************************************long************************************************** + def writeLong(value: Long): Unit = { + val mask: Long = (value << 1) ^ (value >> 63) + if (mask >>> 32 == 0) { + writeVarInt(mask.toInt) + return + } + val bytes: Array[Byte] = new Array[Byte](9) + bytes(0) = (mask | 0x80).toByte + bytes(1) = (mask >>> 7 | 0x80).toByte + bytes(2) = (mask >>> 14 | 0x80).toByte + bytes(3) = (mask >>> 21 | 0x80).toByte + var a: Int = (mask >>> 28).toInt + var b: Int = (mask >>> 35).toInt + if (b == 0) { + bytes(4) = a.toByte + writeBytes(bytes, 5) + return + } + bytes(4) = (a | 0x80).toByte + a = (mask >>> 42).toInt + if (a == 0) { + bytes(5) = b.toByte + writeBytes(bytes, 6) + return + } + bytes(5) = (b | 0x80).toByte + b = (mask >>> 49).toInt + if (b == 0) { + bytes(6) = a.toByte + writeBytes(bytes, 7) + return + } + bytes(6) = (a | 0x80).toByte + a = (mask >>> 56).toInt + if (a == 0) { + bytes(7) = b.toByte + writeBytes(bytes, 8) + return + } + bytes(7) = (b | 0x80).toByte + bytes(8) = a.toByte + writeBytes(bytes, 9) + } + + def readLong: Long = { + var b: Long = readByte + var value: Long = b + if (b < 0) { + b = readByte + value = value & 0x00000000_0000007FL | b << 7 + if (b < 0) { + b = readByte + value = value & 0x00000000_00003FFFL | b << 14 + if (b < 0) { + b = readByte + value = value & 0x00000000_001FFFFFL | b << 21 + if (b < 0) { + b = readByte + value = value & 0x00000000_0FFFFFFFL | b << 28 + if (b < 0) { + b = readByte + value = value & 0x00000007_FFFFFFFFL | b << 35 + if (b < 0) { + b = readByte + value = value & 0x000003FF_FFFFFFFFL | b << 42 + if (b < 0) { + b = readByte + value = value & 0x0001FFFF_FFFFFFFFL | b << 49 + if (b < 0) { + b = readByte + value = value & 0x00FFFFFF_FFFFFFFFL | b << 56 + } + } + } + } + } + } + } + } + (value >>> 1) ^ -(value & 1) + } + + def writeRawLong(value: Long): Unit = { + ensureCapacity(8) + buffer({ + writeOffset += 1; + writeOffset - 1 + }) = (value >>> 56).toInt.toByte + buffer({ + writeOffset += 1; + writeOffset - 1 + }) = (value >>> 48).toInt.toByte + buffer({ + writeOffset += 1; + writeOffset - 1 + }) = (value >>> 40).toInt.toByte + buffer({ + writeOffset += 1; + writeOffset - 1 + }) = (value >>> 32).toInt.toByte + buffer({ + writeOffset += 1; + writeOffset - 1 + }) = (value >>> 24).toInt.toByte + buffer({ + writeOffset += 1; + writeOffset - 1 + }) = (value >>> 16).toInt.toByte + buffer({ + writeOffset += 1; + writeOffset - 1 + }) = (value >>> 8).toInt.toByte + buffer({ + writeOffset += 1; + writeOffset - 1 + }) = value.toInt.toByte + } + + def readRawLong: Long = (buffer({ + readOffset += 1; + readOffset - 1 + }).toLong & 255L) << 56 | (buffer({ + readOffset += 1; + readOffset - 1 + }).toLong & 255L) << 48 | (buffer({ + readOffset += 1; + readOffset - 1 + }).toLong & 255L) << 40 | (buffer({ + readOffset += 1; + readOffset - 1 + }).toLong & 255L) << 32 | (buffer({ + readOffset += 1; + readOffset - 1 + }).toLong & 255L) << 24 | (buffer({ + readOffset += 1; + readOffset - 1 + }).toLong & 255L) << 16 | (buffer({ + readOffset += 1; + readOffset - 1 + }).toLong & 255L) << 8 | buffer({ + readOffset += 1; + readOffset - 1 + }).toLong & 255L + + // *******************************************float*************************************************** + def writeFloat(value: Float): Unit = { + writeRawInt(java.lang.Float.floatToRawIntBits(value)) + } + + def readFloat: Float = java.lang.Float.intBitsToFloat(readRawInt) + + // *******************************************double*************************************************** + def writeDouble(value: Double): Unit = { + writeRawLong(java.lang.Double.doubleToRawLongBits(value)) + } + + def readDouble: Double = java.lang.Double.longBitsToDouble(readRawLong) + + def writeString(value: String): Unit = { + if (value == null || value.isEmpty) { + writeInt(0) + return + } + val bytes: Array[Byte] = value.getBytes(DEFAULT_CHARSET) + writeInt(bytes.length) + writeBytes(bytes) + } + + def readString: String = { + val length: Int = readInt + if (length <= 0) return "" + val bytes: Array[Byte] = readBytes(length) + new String(bytes, DEFAULT_CHARSET) + } + + def writeBooleanArray(array: Array[Boolean]): Unit = { + if ((array == null) || (array.length == 0)) writeInt(0) + else { + writeInt(array.length) + val length: Int = array.length + for (index <- 0 until length) { + writeBool(array(index)) + } + } + } + + def readBooleanArray: Array[Boolean] = { + val size: Int = readInt + val array: Array[Boolean] = new Array[Boolean](size) + if (size > 0) for (index <- 0 until size) { + array(index) = readBool + } + array + } + + def writeByteArray(array: Array[Byte]): Unit = { + if ((array == null) || (array.length == 0)) writeInt(0) + else { + writeInt(array.length) + val length: Int = array.length + for (index <- 0 until length) { + writeByte(array(index)) + } + } + } + + def readByteArray: Array[Byte] = { + val size: Int = readInt + val array: Array[Byte] = new Array[Byte](size) + if (size > 0) for (index <- 0 until size) { + array(index) = readByte + } + array + } + + def writeShortArray(array: Array[Short]): Unit = { + if ((array == null) || (array.length == 0)) writeInt(0) + else { + writeInt(array.length) + val length: Int = array.length + for (index <- 0 until length) { + writeShort(array(index)) + } + } + } + + def readShortArray: Array[Short] = { + val size: Int = readInt + val array: Array[Short] = new Array[Short](size) + if (size > 0) for (index <- 0 until size) { + array(index) = readShort + } + array + } + + def writeIntArray(array: Array[Int]): Unit = { + if ((array == null) || (array.length == 0)) writeInt(0) + else { + writeInt(array.length) + val length: Int = array.length + for (index <- 0 until length) { + writeInt(array(index)) + } + } + } + + def readIntArray: Array[Int] = { + val size: Int = readInt + val array: Array[Int] = new Array[Int](size) + if (size > 0) for (index <- 0 until size) { + array(index) = readInt + } + array + } + + def writeLongArray(array: Array[Long]): Unit = { + if ((array == null) || (array.length == 0)) writeInt(0) + else { + writeInt(array.length) + val length: Int = array.length + for (index <- 0 until length) { + writeLong(array(index)) + } + } + } + + def readLongArray: Array[Long] = { + val size: Int = readInt + val array: Array[Long] = new Array[Long](size) + if (size > 0) for (index <- 0 until size) { + array(index) = readLong + } + array + } + + def writeFloatArray(array: Array[Float]): Unit = { + if ((array == null) || (array.length == 0)) writeInt(0) + else { + writeInt(array.length) + val length: Int = array.length + for (index <- 0 until length) { + writeFloat(array(index)) + } + } + } + + def readFloatArray: Array[Float] = { + val size: Int = readInt + val array: Array[Float] = new Array[Float](size) + if (size > 0) for (index <- 0 until size) { + array(index) = readFloat + } + array + } + + def writeDoubleArray(array: Array[Double]): Unit = { + if ((array == null) || (array.length == 0)) writeInt(0) + else { + writeInt(array.length) + val length: Int = array.length + for (index <- 0 until length) { + writeDouble(array(index)) + } + } + } + + def readDoubleArray: Array[Double] = { + val size: Int = readInt + val array: Array[Double] = new Array[Double](size) + if (size > 0) for (index <- 0 until size) { + array(index) = readDouble + } + array + } + + def writeStringArray(array: Array[String]): Unit = { + if ((array == null) || (array.length == 0)) writeInt(0) + else { + writeInt(array.length) + val length: Int = array.length + for (index <- 0 until length) { + writeString(array(index)) + } + } + } + + def readStringArray: Array[String] = { + val size: Int = readInt + val array: Array[String] = new Array[String](size) + if (size > 0) for (index <- 0 until size) { + array(index) = readString + } + array + } + + def writeBooleanList(list: List[Boolean]): Unit = { + if ((list == null) || list.isEmpty) writeInt(0) + else { + writeInt(list.size) + for (ele <- list) { + writeBool(ele) + } + } + } + + def readBooleanList: List[Boolean] = { + val size: Int = readInt + var list: List[Boolean] = List() + if (size > 0) { + for (index <- 0 until size) { + list = list :+ readBool + } + } + list + } + + def writeByteList(list: List[Byte]): Unit = { + if ((list == null) || list.isEmpty) writeInt(0) + else { + writeInt(list.size) + for (ele <- list) { + writeByte(ele) + } + } + } + + def readByteList: List[Byte] = { + val size: Int = readInt + val list: ListBuffer[Byte] = new ListBuffer[Byte] + if (size > 0) { + for (index <- 0 until size) { + list.addOne(readByte) + } + } + list.toList + } + + def writeShortList(list: List[Short]): Unit = { + if ((list == null) || list.isEmpty) writeInt(0) + else { + writeInt(list.size) + for (ele <- list) { + writeShort(ele) + } + } + } + + def readShortList: List[Short] = { + val size: Int = readInt + val list: ListBuffer[Short] = new ListBuffer[Short] + if (size > 0) for (index <- 0 until size) { + list.addOne(readShort) + } + list.toList + } + + def writeIntList(list: List[Int]): Unit = { + if ((list == null) || list.isEmpty) writeInt(0) + else { + writeInt(list.size) + for (ele <- list) { + writeInt(ele) + } + } + } + + def readIntList: List[Int] = { + val size: Int = readInt + val list: ArrayBuffer[Int] = new ArrayBuffer[Int] + if (size > 0) for (index <- 0 until size) { + list.addOne(readInt) + } + list.toList + } + + def writeLongList(list: List[Long]): Unit = { + if ((list == null) || list.isEmpty) writeInt(0) + else { + writeInt(list.size) + for (ele <- list) { + writeLong(ele) + } + } + } + + def readLongList: List[Long] = { + val size: Int = readInt + val list: ArrayBuffer[Long] = new ArrayBuffer[Long] + if (size > 0) for (index <- 0 until size) { + list.addOne(readLong) + } + list.toList + } + + def writeFloatList(list: List[Float]): Unit = { + if ((list == null) || list.isEmpty) writeInt(0) + else { + writeInt(list.size) + for (ele <- list) { + writeFloat(ele) + } + } + } + + def readFloatList: List[Float] = { + val size: Int = readInt + val list: ArrayBuffer[Float] = new ArrayBuffer[Float] + if (size > 0) for (index <- 0 until size) { + list.addOne(readFloat) + } + list.toList + } + + def writeDoubleList(list: List[Double]): Unit = { + if ((list == null) || list.isEmpty) writeInt(0) + else { + writeInt(list.size) + for (ele <- list) { + writeDouble(ele) + } + } + } + + def readDoubleList: List[Double] = { + val size: Int = readInt + val list: ArrayBuffer[Double] = new ArrayBuffer[Double] + if (size > 0) for (index <- 0 until size) { + list.addOne(readDouble) + } + list.toList + } + + def writeStringList(list: List[String]): Unit = { + if ((list == null) || list.isEmpty) writeInt(0) + else { + writeInt(list.size) + for (ele <- list) { + writeString(ele) + } + } + } + + def readStringList: List[String] = { + val size: Int = readInt + val list: ArrayBuffer[String] = new ArrayBuffer[String] + if (size > 0) for (index <- 0 until size) { + list.addOne(readString) + } + list.toList + } + + def writePacketList(list: List[_], protocolId: Short): Unit = { + if ((list == null) || list.isEmpty) writeInt(0) + else { + val protocolRegistration: IProtocolRegistration = ProtocolManager.getProtocol(protocolId) + writeInt(list.size) + for (ele <- list) { + protocolRegistration.write(this, ele) + } + } + } + + def readPacketList[T](clazz: Class[T], protocolId: Short): List[T] = { + val size: Int = readInt + val list: ArrayBuffer[T] = new ArrayBuffer[T] + if (size > 0) { + val protocolRegistration: IProtocolRegistration = ProtocolManager.getProtocol(protocolId) + for (index <- 0 until size) { + list.addOne(protocolRegistration.read(this).asInstanceOf[T]) + } + } + list.toList + } + + def writeBooleanSet(set: Set[Boolean]): Unit = { + if ((set == null) || set.isEmpty) writeInt(0) + else { + writeInt(set.size) + for (ele <- set) { + writeBool(ele) + } + } + } + + def readBooleanSet: Set[Boolean] = { + val size: Int = readInt + val set: ArrayBuffer[Boolean] = new ArrayBuffer[Boolean] + if (size > 0) for (index <- 0 until size) { + set.addOne(readBool) + } + set.toSet + } + + def writeShortSet(set: Set[Short]): Unit = { + if ((set == null) || set.isEmpty) writeInt(0) + else { + writeInt(set.size) + for (ele <- set) { + writeShort(ele) + } + } + } + + def readShortSet: Set[Short] = { + val size: Int = readInt + val set: ArrayBuffer[Short] = new ArrayBuffer[Short] + if (size > 0) for (index <- 0 until size) { + set.addOne(readShort) + } + set.toSet + } + + def writeIntSet(set: Set[Int]): Unit = { + if ((set == null) || set.isEmpty) writeInt(0) + else { + writeInt(set.size) + for (ele <- set) { + writeInt(ele) + } + } + } + + def readIntSet: Set[Int] = { + val size: Int = readInt + val set: ArrayBuffer[Int] = new ArrayBuffer[Int] + if (size > 0) for (index <- 0 until size) { + set.addOne(readInt) + } + set.toSet + } + + def writeLongSet(set: Set[Long]): Unit = { + if ((set == null) || set.isEmpty) writeInt(0) + else { + writeInt(set.size) + for (ele <- set) { + writeLong(ele) + } + } + } + + def readLongSet: Set[Long] = { + val size: Int = readInt + val set: ArrayBuffer[Long] = new ArrayBuffer[Long] + if (size > 0) for (index <- 0 until size) { + set.addOne(readLong) + } + set.toSet + } + + def writeFloatSet(set: Set[Float]): Unit = { + if ((set == null) || set.isEmpty) writeInt(0) + else { + writeInt(set.size) + for (ele <- set) { + writeFloat(ele) + } + } + } + + def readFloatSet: Set[Float] = { + val size: Int = readInt + val set: ArrayBuffer[Float] = new ArrayBuffer[Float] + if (size > 0) for (index <- 0 until size) { + set.addOne(readFloat) + } + set.toSet + } + + def writeDoubleSet(set: Set[Double]): Unit = { + if ((set == null) || set.isEmpty) writeInt(0) + else { + writeInt(set.size) + for (ele <- set) { + writeDouble(ele) + } + } + } + + def readDoubleSet: Set[Double] = { + val size: Int = readInt + val set: ArrayBuffer[Double] = new ArrayBuffer[Double] + if (size > 0) for (index <- 0 until size) { + set.addOne(readDouble) + } + set.toSet + } + + def writeStringSet(set: Set[String]): Unit = { + if ((set == null) || set.isEmpty) writeInt(0) + else { + writeInt(set.size) + for (ele <- set) { + writeString(ele) + } + } + } + + def readStringSet: Set[String] = { + val size: Int = readInt + val set: ArrayBuffer[String] = new ArrayBuffer[String] + if (size > 0) for (index <- 0 until size) { + set.addOne(readString) + } + set.toSet + } + + def writePacketSet(set: Set[_], protocolId: Short): Unit = { + if ((set == null) || set.isEmpty) writeInt(0) + else { + val protocolRegistration: IProtocolRegistration = ProtocolManager.getProtocol(protocolId) + writeInt(set.size) + for (element <- set) { + protocolRegistration.write(this, element) + } + } + } + + def readPacketSet[T](clazz: Class[T], protocolId: Short): Set[T] = { + val size: Int = readInt + val set: ArrayBuffer[T] = new ArrayBuffer[T] + if (size > 0) { + val protocolRegistration: IProtocolRegistration = ProtocolManager.getProtocol(protocolId) + for (index <- 0 until size) { + set.addOne(protocolRegistration.read(this).asInstanceOf[T]) + } + } + set.toSet + } + + def writeIntIntMap(map: Map[Int, Int]): Unit = { + if ((map == null) || map.isEmpty) writeInt(0) + else { + writeInt(map.size) + for ((key, value) <- map) { + writeInt(key) + writeInt(value) + } + } + } + + def readIntIntMap: Map[Int, Int] = { + val size: Int = readInt + val map = mutable.Map[Int, Int]() + if (size > 0) for (index <- 0 until size) { + val key: Int = readInt + val value: Int = readInt + map.put(key, value) + } + map.toMap + } + + def writeIntLongMap(map: Map[Int, Long]): Unit = { + if ((map == null) || map.isEmpty) writeInt(0) + else { + writeInt(map.size) + for ((key, value) <- map) { + writeInt(key) + writeLong(value) + } + } + } + + def readIntLongMap: Map[Int, Long] = { + val size: Int = readInt + val map = mutable.Map[Int, Long]() + if (size > 0) for (index <- 0 until size) { + val key: Int = readInt + val value: Long = readLong + map.put(key, value) + } + map.toMap + } + + def writeIntStringMap(map: Map[Int, String]): Unit = { + if ((map == null) || map.isEmpty) writeInt(0) + else { + writeInt(map.size) + for ((key, value) <- map) { + writeInt(key) + writeString(value) + } + } + } + + def readIntStringMap: Map[Int, String] = { + val size: Int = readInt + val map = mutable.Map[Int, String]() + if (size > 0) for (index <- 0 until size) { + val key: Int = readInt + val value: String = readString + map.put(key, value) + } + map.toMap + } + + def writeIntPacketMap(map: Map[Int, _], protocolId: Short): Unit = { + if ((map == null) || map.isEmpty) writeInt(0) + else { + val protocolRegistration: IProtocolRegistration = ProtocolManager.getProtocol(protocolId) + writeInt(map.size) + for ((key, value) <- map) { + writeInt(key) + protocolRegistration.write(this, value) + } + } + } + + def readIntPacketMap[T](clazz: Class[T], protocolId: Short): Map[Int, T] = { + val size: Int = readInt + val map = mutable.Map[Int, T]() + if (size > 0) { + val protocolRegistration: IProtocolRegistration = ProtocolManager.getProtocol(protocolId) + for (index <- 0 until size) { + val key: Int = readInt + val value: T = protocolRegistration.read(this).asInstanceOf[T] + map.put(key, value) + } + } + map.toMap + } + + def writeLongIntMap(map: Map[Long, Int]): Unit = { + if ((map == null) || map.isEmpty) writeInt(0) + else { + writeInt(map.size) + for ((key, value) <- map) { + writeLong(key) + writeInt(value) + } + } + } + + def readLongIntMap: Map[Long, Int] = { + val size: Int = readInt + val map = mutable.Map[Long, Int]() + if (size > 0) for (index <- 0 until size) { + val key: Long = readLong + val value: Int = readInt + map.put(key, value) + } + map.toMap + } + + def writeLongLongMap(map: Map[Long, Long]): Unit = { + if ((map == null) || map.isEmpty) writeInt(0) + else { + writeInt(map.size) + for ((key, value) <- map) { + writeLong(key) + writeLong(value) + } + } + } + + def readLongLongMap: Map[Long, Long] = { + val size: Int = readInt + val map = mutable.Map[Long, Long]() + if (size > 0) for (index <- 0 until size) { + val key: Long = readLong + val value: Long = readLong + map.put(key, value) + } + map.toMap + } + + def writeLongStringMap(map: Map[Long, String]): Unit = { + if ((map == null) || map.isEmpty) writeInt(0) + else { + writeInt(map.size) + for ((key, value) <- map) { + writeLong(key) + writeString(value) + } + } + } + + def readLongStringMap: Map[Long, String] = { + val size: Int = readInt + val map = mutable.Map[Long, String]() + if (size > 0) for (index <- 0 until size) { + val key: Long = readLong + val value: String = readString + map.put(key, value) + } + map.toMap + } + + def writeLongPacketMap(map: Map[Long, _], protocolId: Short): Unit = { + if ((map == null) || map.isEmpty) writeInt(0) + else { + val protocolRegistration: IProtocolRegistration = ProtocolManager.getProtocol(protocolId) + writeInt(map.size) + for ((key, value) <- map) { + writeLong(key) + protocolRegistration.write(this, value) + } + } + } + + def readLongPacketMap[T](clazz: Class[T], protocolId: Short): Map[Long, T] = { + val size: Int = readInt + val map = mutable.Map[Long, T]() + if (size > 0) { + val protocolRegistration: IProtocolRegistration = ProtocolManager.getProtocol(protocolId) + for (index <- 0 until size) { + val key: Long = readLong + val value: T = protocolRegistration.read(this).asInstanceOf[T] + map.put(key, value) + } + } + map.toMap + } + + def writeStringIntMap(map: Map[String, Int]): Unit = { + if ((map == null) || map.isEmpty) writeInt(0) + else { + writeInt(map.size) + for ((key, value) <- map) { + writeString(key) + writeInt(value) + } + } + } + + def readStringIntMap: Map[String, Int] = { + val size: Int = readInt + val map = mutable.Map[String, Int]() + if (size > 0) for (index <- 0 until size) { + val key: String = readString + val value: Int = readInt + map.put(key, value) + } + map.toMap + } + + def writeStringLongMap(map: Map[String, Long]): Unit = { + if ((map == null) || map.isEmpty) writeInt(0) + else { + writeInt(map.size) + for ((key, value) <- map) { + writeString(key) + writeLong(value) + } + } + } + + def readStringLongMap: Map[String, Long] = { + val size: Int = readInt + val map = mutable.Map[String, Long]() + if (size > 0) for (index <- 0 until size) { + val key: String = readString + val value: Long = readLong + map.put(key, value) + } + map.toMap + } + + def writeStringStringMap(map: Map[String, String]): Unit = { + if ((map == null) || map.isEmpty) writeInt(0) + else { + writeInt(map.size) + for ((key, value) <- map) { + writeString(key) + writeString(value) + } + } + } + + def readStringStringMap: Map[String, String] = { + val size: Int = readInt + val map = mutable.Map[String, String]() + if (size > 0) for (index <- 0 until size) { + val key: String = readString + val value: String = readString + map.put(key, value) + } + map.toMap + } + + def writeStringPacketMap(map: Map[String, _], protocolId: Short): Unit = { + if ((map == null) || map.isEmpty) writeInt(0) + else { + val protocolRegistration: IProtocolRegistration = ProtocolManager.getProtocol(protocolId) + writeInt(map.size) + for ((key, value) <- map) { + writeString(key) + protocolRegistration.write(this, value) + } + } + } + + def readStringPacketMap[T](clazz: Class[T], protocolId: Short): Map[String, T] = { + val size: Int = readInt + val map = mutable.Map[String, T]() + if (size > 0) { + val protocolRegistration: IProtocolRegistration = ProtocolManager.getProtocol(protocolId) + for (index <- 0 until size) { + val key: String = readString + val value: T = protocolRegistration.read(this).asInstanceOf[T] + map.put(key, value) + } + } + map.toMap + } + + def writePacket(packet: Any, protocolId: Short): Unit = { + val protocolRegistration: IProtocolRegistration = ProtocolManager.getProtocol(protocolId) + protocolRegistration.write(this, packet) + } + + def readPacket(protocolId: Short): Any = { + val protocolRegistration: IProtocolRegistration = ProtocolManager.getProtocol(protocolId) + protocolRegistration.read(this) + } +} \ No newline at end of file diff --git a/protocol/src/main/resources/scala/IProtocolRegistration.scala b/protocol/src/main/resources/scala/IProtocolRegistration.scala new file mode 100644 index 00000000..563d8ff3 --- /dev/null +++ b/protocol/src/main/resources/scala/IProtocolRegistration.scala @@ -0,0 +1,8 @@ +${protocol_root_path} +trait IProtocolRegistration { + def protocolId: Short + + def write(buffer: ByteBuffer, packet: Any): Unit + + def read(buffer: ByteBuffer): Any +} \ No newline at end of file diff --git a/protocol/src/main/resources/scala/ProtocolClassTemplate.scala b/protocol/src/main/resources/scala/ProtocolClassTemplate.scala new file mode 100644 index 00000000..efad9f60 --- /dev/null +++ b/protocol/src/main/resources/scala/ProtocolClassTemplate.scala @@ -0,0 +1,4 @@ +${protocol_note} +class ${protocol_name} { + ${protocol_field_definition} +} \ No newline at end of file diff --git a/protocol/src/main/resources/scala/ProtocolManagerTemplate.scala b/protocol/src/main/resources/scala/ProtocolManagerTemplate.scala new file mode 100644 index 00000000..cf4d1d75 --- /dev/null +++ b/protocol/src/main/resources/scala/ProtocolManagerTemplate.scala @@ -0,0 +1,35 @@ +${protocol_root_path} +${protocol_imports} +import scala.collection.mutable + +object ProtocolManager { + val MAX_PROTOCOL_NUM: Short = Short.MaxValue + val protocols = new Array[IProtocolRegistration](MAX_PROTOCOL_NUM) + val protocolIdMap = mutable.Map[Class[_], Short]() + + def initProtocol(): Unit = { + // initProtocol + ${protocol_manager_registrations} + } + + def getProtocolId(clazz: Class[_]): Short = protocolIdMap.getOrElse(clazz, -1) + + def getProtocol(protocolId: Short): IProtocolRegistration = { + val protocol = protocols(protocolId) + if (protocol == null) throw new RuntimeException("[protocolId:" + protocolId + "] not exist") + protocol + } + + def write(buffer: ByteBuffer, packet: Any): Unit = { + val protocolId = getProtocolId(packet.getClass) + // write protocol id to buffer + buffer.writeShort(protocolId) + // write packet + getProtocol(protocolId).write(buffer, packet) + } + + def read(buffer: ByteBuffer): Any = { + val protocolId = buffer.readShort + getProtocol(protocolId).read(buffer) + } +} \ No newline at end of file diff --git a/protocol/src/main/resources/scala/ProtocolRegistrationTemplate.scala b/protocol/src/main/resources/scala/ProtocolRegistrationTemplate.scala new file mode 100644 index 00000000..39767ca2 --- /dev/null +++ b/protocol/src/main/resources/scala/ProtocolRegistrationTemplate.scala @@ -0,0 +1,22 @@ +object Registration${protocol_name} extends IProtocolRegistration { + override def protocolId: Short = ${protocol_id} + + override def write(buffer: ByteBuffer, packet: Any): Unit = { + if (packet == null) { + buffer.writeInt(0) + return + } + val message = packet.asInstanceOf[${protocol_name}] + ${protocol_write_serialization} + } + + override def read(buffer: ByteBuffer): AnyRef = { + val length: Int = buffer.readInt + if (length == 0) return null + val beforeReadIndex: Int = buffer.getReadOffset + val packet: ${protocol_name} = new ${protocol_name} + ${protocol_read_deserialization} + if (length > 0) buffer.setReadOffset(beforeReadIndex + length) + packet + } +} \ No newline at end of file diff --git a/protocol/src/main/resources/scala/ProtocolTemplate.scala b/protocol/src/main/resources/scala/ProtocolTemplate.scala new file mode 100644 index 00000000..d470ef86 --- /dev/null +++ b/protocol/src/main/resources/scala/ProtocolTemplate.scala @@ -0,0 +1,7 @@ +${protocol_root_path} +${protocol_imports} +import scala.collection.mutable + +${protocol_class} + +${protocol_registration} \ No newline at end of file diff --git a/protocol/src/main/resources/scala/ProtocolsTemplate.scala b/protocol/src/main/resources/scala/ProtocolsTemplate.scala new file mode 100644 index 00000000..9550a49b --- /dev/null +++ b/protocol/src/main/resources/scala/ProtocolsTemplate.scala @@ -0,0 +1,9 @@ +${protocol_root_path} +${protocol_imports} +import scala.collection.mutable + +${protocol_class} + +// ----------------------------------------------------------------------------------------------------------------- + +${protocol_registration}