diff --git a/protocol/src/main/java/com/zfoo/protocol/generate/GenerateProtocolNote.java b/protocol/src/main/java/com/zfoo/protocol/generate/GenerateProtocolNote.java index 94c620b0..d1fac1d1 100644 --- a/protocol/src/main/java/com/zfoo/protocol/generate/GenerateProtocolNote.java +++ b/protocol/src/main/java/com/zfoo/protocol/generate/GenerateProtocolNote.java @@ -100,6 +100,7 @@ public abstract class GenerateProtocolNote { break; case Python: case GdScript: + case Ruby: note = StringUtils.format("# {}", note); break; case Enhance: 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 c56ad65f..c119090e 100644 --- a/protocol/src/main/java/com/zfoo/protocol/serializer/CodeLanguage.java +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/CodeLanguage.java @@ -23,6 +23,7 @@ import com.zfoo.protocol.serializer.kotlin.CodeGenerateKotlin; import com.zfoo.protocol.serializer.lua.CodeGenerateLua; import com.zfoo.protocol.serializer.php.CodeGeneratePhp; import com.zfoo.protocol.serializer.python.CodeGeneratePython; +import com.zfoo.protocol.serializer.ruby.CodeGenerateRuby; import com.zfoo.protocol.serializer.rust.CodeGenerateRust; import com.zfoo.protocol.serializer.scala.CodeGenerateScala; import com.zfoo.protocol.serializer.typescript.CodeGenerateTypeScript; @@ -65,6 +66,8 @@ public enum CodeLanguage { Php(1 << 28, CodeGeneratePhp.class), + Ruby(1 << 29, CodeGenerateRuby.class), + Protobuf(1 << 30, null); public final int id; diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/CodeTemplatePlaceholder.java b/protocol/src/main/java/com/zfoo/protocol/serializer/CodeTemplatePlaceholder.java index 449630e5..31efb00b 100644 --- a/protocol/src/main/java/com/zfoo/protocol/serializer/CodeTemplatePlaceholder.java +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/CodeTemplatePlaceholder.java @@ -47,6 +47,9 @@ public enum CodeTemplatePlaceholder { protocol_read_deserialization("${protocol_read_deserialization}"), + // ----------------------------------------------------------------------------------------------------------------- + protocol_field_accessor("${protocol_field_accessor}"), + protocol_json("${protocol_json}"), protocol_to_string("${protocol_to_string}"), diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/CodeGenerateRuby.java b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/CodeGenerateRuby.java new file mode 100644 index 00000000..81966500 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/CodeGenerateRuby.java @@ -0,0 +1,315 @@ +/* + * 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.ruby; + +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.ProtocolRegistration; +import com.zfoo.protocol.serializer.CodeLanguage; +import com.zfoo.protocol.serializer.CodeTemplatePlaceholder; +import com.zfoo.protocol.serializer.ICodeGenerate; +import com.zfoo.protocol.serializer.csharp.CodeGenerateCsharp; +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 CodeGenerateRuby implements ICodeGenerate { + private static final Logger logger = LoggerFactory.getLogger(CodeGenerateRuby.class); + + // custom configuration + public static String protocolOutputRootPath = "zfooruby"; + private static String protocolOutputPath = StringUtils.EMPTY; + + private static Map rbSerializerMap = new HashMap<>(); + + public static IRubySerializer rbSerializer(ISerializer serializer) { + return rbSerializerMap.get(serializer); + } + + @Override + public void init(GenerateOperation generateOperation) { + protocolOutputPath = FileUtils.joinPath(generateOperation.getProtocolPath(), protocolOutputRootPath); + FileUtils.deleteFile(new File(protocolOutputPath)); + + rbSerializerMap.put(BoolSerializer.INSTANCE, new RubyBoolSerializer()); + rbSerializerMap.put(ByteSerializer.INSTANCE, new RubyByteSerializer()); + rbSerializerMap.put(ShortSerializer.INSTANCE, new RubyShortSerializer()); + rbSerializerMap.put(IntSerializer.INSTANCE, new RubyIntSerializer()); + rbSerializerMap.put(LongSerializer.INSTANCE, new RubyLongSerializer()); + rbSerializerMap.put(FloatSerializer.INSTANCE, new RubyFloatSerializer()); + rbSerializerMap.put(DoubleSerializer.INSTANCE, new RubyDoubleSerializer()); + rbSerializerMap.put(StringSerializer.INSTANCE, new RubyStringSerializer()); + rbSerializerMap.put(ArraySerializer.INSTANCE, new RubyArraySerializer()); + rbSerializerMap.put(ListSerializer.INSTANCE, new RubyListSerializer()); + rbSerializerMap.put(SetSerializer.INSTANCE, new RubySetSerializer()); + rbSerializerMap.put(MapSerializer.INSTANCE, new RubyMapSerializer()); + rbSerializerMap.put(ObjectProtocolSerializer.INSTANCE, new RubyObjectProtocolSerializer()); + } + + @Override + public void mergerProtocol(List registrations) throws IOException { + createTemplateFile(); + + + var protocolManagerTemplate = ClassUtils.getFileFromClassPathToString("python/ProtocolManagerTemplate.py"); + var protocol_imports = new StringBuilder(); + var protocol_manager_registrations = new StringBuilder(); + protocol_imports.append("from . import Protocols").append(LS); + for (var registration : registrations) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + protocol_manager_registrations.append(StringUtils.format("protocols[{}] = Protocols.{}Registration", protocol_id, protocol_name)).append(LS); + protocol_manager_registrations.append(StringUtils.format("protocolIdMap[Protocols.{}] = {}", protocol_name, protocol_id)).append(LS); + } + var placeholderMap = Map.of(CodeTemplatePlaceholder.protocol_imports, protocol_imports.toString() + , CodeTemplatePlaceholder.protocol_manager_registrations, protocol_manager_registrations.toString()); + var formatProtocolManagerTemplate = CodeTemplatePlaceholder.formatTemplate(protocolManagerTemplate, placeholderMap); + var protocolManagerFile = new File(StringUtils.format("{}/{}", protocolOutputPath, "ProtocolManager.py")); + FileUtils.writeStringToFile(protocolManagerFile, formatProtocolManagerTemplate, true); + logger.info("Generated Python protocol manager file:[{}] is in path:[{}]", protocolManagerFile.getName(), protocolManagerFile.getAbsolutePath()); + + + var protocol_class = new StringBuilder(); + var protocol_registration = new StringBuilder(); + for (var registration : registrations) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + protocol_class.append(protocol_class(registration)).append(LS); + protocol_registration.append(protocol_registration(registration)).append(LS); + } + var protocolTemplate = ClassUtils.getFileFromClassPathToString("python/ProtocolsTemplate.py"); + var formatProtocolTemplate = CodeTemplatePlaceholder.formatTemplate(protocolTemplate, Map.of( + CodeTemplatePlaceholder.protocol_class, protocol_class.toString() + , CodeTemplatePlaceholder.protocol_registration, protocol_registration.toString() + )); + var outputPath = StringUtils.format("{}/Protocols.py", protocolOutputPath); + var file = new File(outputPath); + FileUtils.writeStringToFile(file, formatProtocolTemplate, true); + logger.info("Generated Python protocol file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath()); + + } + + @Override + public void foldProtocol(List registrations) throws IOException { + createTemplateFile(); + + + var protocolManagerTemplate = ClassUtils.getFileFromClassPathToString("python/ProtocolManagerTemplate.py"); + var protocol_imports = new StringBuilder(); + var protocol_manager_registrations = new StringBuilder(); + for (var registration : registrations) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + protocol_imports.append(StringUtils.format("from .{} import {}", GenerateProtocolPath.protocolPathPeriod(protocol_id), protocol_name)).append(LS); + protocol_manager_registrations.append(StringUtils.format("protocols[{}] = {}.{}Registration", protocol_id, protocol_name, protocol_name)).append(LS); + protocol_manager_registrations.append(StringUtils.format("protocolIdMap[{}.{}] = {}", protocol_name, protocol_name, protocol_id)).append(LS); + } + var placeholderMap = Map.of(CodeTemplatePlaceholder.protocol_imports, protocol_imports.toString() + , CodeTemplatePlaceholder.protocol_manager_registrations, protocol_manager_registrations.toString()); + var formatProtocolManagerTemplate = CodeTemplatePlaceholder.formatTemplate(protocolManagerTemplate, placeholderMap); + var protocolManagerFile = new File(StringUtils.format("{}/{}", protocolOutputPath, "ProtocolManager.py")); + FileUtils.writeStringToFile(protocolManagerFile, formatProtocolManagerTemplate, true); + logger.info("Generated Python 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("python/ProtocolTemplate.py"); + var formatProtocolTemplate = CodeTemplatePlaceholder.formatTemplate(protocolTemplate, Map.of( + CodeTemplatePlaceholder.protocol_name, protocol_name + , CodeTemplatePlaceholder.protocol_class, protocol_class(registration) + , CodeTemplatePlaceholder.protocol_registration, protocol_registration(registration) + )); + var outputPath = StringUtils.format("{}/{}/{}.py", protocolOutputPath, GenerateProtocolPath.protocolPathSlash(protocol_id), protocol_name); + var file = new File(outputPath); + FileUtils.writeStringToFile(file, formatProtocolTemplate, true); + logger.info("Generated Python protocol file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath()); + } + } + + @Override + public void defaultProtocol(List registrations) throws IOException { + createTemplateFile(); + + + var protocolManagerTemplate = ClassUtils.getFileFromClassPathToString("ruby/ProtocolManagerTemplate.rb"); + var protocol_imports = new StringBuilder(); + var protocol_manager_registrations = new StringBuilder(); + for (var registration : registrations) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + protocol_imports.append(StringUtils.format("require_relative '{}.rb'", protocol_name)).append(LS); + protocol_manager_registrations.append(StringUtils.format("@@protocols[{}] = {}Registration.new()", protocol_id, protocol_name)).append(LS); + protocol_manager_registrations.append(StringUtils.format("@@protocolIdMap[{}] = {}", protocol_name, protocol_id)).append(LS); + } + var placeholderMap = Map.of(CodeTemplatePlaceholder.protocol_imports, protocol_imports.toString() + , CodeTemplatePlaceholder.protocol_manager_registrations, protocol_manager_registrations.toString()); + var formatProtocolManagerTemplate = CodeTemplatePlaceholder.formatTemplate(protocolManagerTemplate, placeholderMap); + var protocolManagerFile = new File(StringUtils.format("{}/{}", protocolOutputPath, "ProtocolManager.rb")); + FileUtils.writeStringToFile(protocolManagerFile, formatProtocolManagerTemplate, true); + logger.info("Generated Ruby 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("ruby/ProtocolTemplate.rb"); + var formatProtocolTemplate = CodeTemplatePlaceholder.formatTemplate(protocolTemplate, Map.of( + CodeTemplatePlaceholder.protocol_name, protocol_name + , CodeTemplatePlaceholder.protocol_class, protocol_class(registration) + , CodeTemplatePlaceholder.protocol_registration, protocol_registration(registration) + )); + var outputPath = StringUtils.format("{}/{}.rb", protocolOutputPath, protocol_name); + var file = new File(outputPath); + FileUtils.writeStringToFile(file, formatProtocolTemplate, true); + logger.info("Generated Ruby protocol file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath()); + } + } + + private void createTemplateFile() throws IOException { + var list = List.of("ruby/ByteBuffer.rb"); + for (var fileName : list) { + var fileInputStream = ClassUtils.getFileFromClassPath(fileName); + var outputPath = StringUtils.format("{}/{}", protocolOutputPath, StringUtils.substringAfterFirst(fileName, "ruby/")); + var createFile = new File(outputPath); + FileUtils.writeInputStreamToFile(createFile, fileInputStream); + } + } + + public String protocol_class(ProtocolRegistration registration) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.getConstructor().getDeclaringClass().getSimpleName(); + var protocolTemplate = ClassUtils.getFileFromClassPathToString("ruby/ProtocolClassTemplate.rb"); + var placeholderMap = Map.of( + CodeTemplatePlaceholder.protocol_note, GenerateProtocolNote.protocol_note(protocol_id, CodeLanguage.Ruby) + , CodeTemplatePlaceholder.protocol_name, protocol_name + , CodeTemplatePlaceholder.protocol_id, String.valueOf(protocol_id) + , CodeTemplatePlaceholder.protocol_field_accessor, protocol_field_accessor(registration) + , CodeTemplatePlaceholder.protocol_field_definition, protocol_field_definition(registration) + ); + return CodeTemplatePlaceholder.formatTemplate(protocolTemplate, placeholderMap); + } + + public String protocol_registration(ProtocolRegistration registration) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.getConstructor().getDeclaringClass().getSimpleName(); + var protocolTemplate = ClassUtils.getFileFromClassPathToString("ruby/ProtocolRegistrationTemplate.rb"); + var placeholderMap = Map.of( + CodeTemplatePlaceholder.protocol_note, GenerateProtocolNote.protocol_note(protocol_id, CodeLanguage.Ruby) + , 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 CodeTemplatePlaceholder.formatTemplate(protocolTemplate, placeholderMap); + } + + private String protocol_field_accessor(ProtocolRegistration registration) { + var protocolId = registration.getId(); + var rbBuilder = new StringBuilder(); + // when generate source code fields, use origin fields sort + var sequencedFields = ReflectionUtils.notStaticAndTransientFields(registration.getConstructor().getDeclaringClass()); + for (var field : sequencedFields) { + var fieldName = field.getName(); + // 生成注释 + var fieldNotes = GenerateProtocolNote.fieldNotes(protocolId, fieldName, CodeLanguage.Ruby); + for (var fieldNote : fieldNotes) { + rbBuilder.append(fieldNote).append(LS); + } + // 生成类型的注释 + rbBuilder.append(StringUtils.format("attr_accessor :{}", fieldName)); + rbBuilder.append(StringUtils.format(" # {}", CodeGenerateCsharp.toCsClassName(field.getGenericType().getTypeName()))); + rbBuilder.append(LS); + } + return rbBuilder.toString(); + } + + private String protocol_field_definition(ProtocolRegistration registration) { + var protocolId = registration.getId(); + var fields = registration.getFields(); + var fieldRegistrations = registration.getFieldRegistrations(); + var rbBuilder = new StringBuilder(); + var sequencedFields = ReflectionUtils.notStaticAndTransientFields(registration.getConstructor().getDeclaringClass()); + for (var field : sequencedFields) { + var fieldRegistration = fieldRegistrations[GenerateProtocolFile.indexOf(fields, field)]; + var fieldName = field.getName(); + var fieldDefaultValue = rbSerializer(fieldRegistration.serializer()).fieldDefaultValue(field, fieldRegistration); + rbBuilder.append(StringUtils.format("@{} = {}", fieldName, fieldDefaultValue)); + rbBuilder.append(LS); + } + return rbBuilder.toString(); + } + + private String protocol_write_serialization(ProtocolRegistration registration) { + GenerateProtocolFile.localVariableId = 0; + var fields = registration.getFields(); + var fieldRegistrations = registration.getFieldRegistrations(); + var rbBuilder = new StringBuilder(); + if (registration.isCompatible()) { + rbBuilder.append("beforeWriteIndex = buffer.getWriteOffset()").append(LS); + rbBuilder.append(StringUtils.format("buffer.writeInt({})", registration.getPredictionLength())).append(LS); + } else { + rbBuilder.append("buffer.writeInt(-1)").append(LS); + } + for (var i = 0; i < fields.length; i++) { + var field = fields[i]; + var fieldRegistration = fieldRegistrations[i]; + rbSerializer(fieldRegistration.serializer()).writeObject(rbBuilder, "packet." + field.getName(), 0, field, fieldRegistration); + } + if (registration.isCompatible()) { + rbBuilder.append(StringUtils.format("buffer.adjustPadding({}, beforeWriteIndex)", registration.getPredictionLength())).append(LS); + } + return rbBuilder.toString(); + } + + private String protocol_read_deserialization(ProtocolRegistration registration) { + GenerateProtocolFile.localVariableId = 0; + var fields = registration.getFields(); + var fieldRegistrations = registration.getFieldRegistrations(); + var rbBuilder = new StringBuilder(); + for (var i = 0; i < fields.length; i++) { + var field = fields[i]; + var fieldRegistration = fieldRegistrations[i]; + if (field.isAnnotationPresent(Compatible.class)) { + rbBuilder.append("if buffer.compatibleRead(beforeReadIndex, length):").append(LS); + var compatibleReadObject = rbSerializer(fieldRegistration.serializer()).readObject(rbBuilder, 1, field, fieldRegistration); + rbBuilder.append(TAB).append(StringUtils.format("packet.{} = {}", field.getName(), compatibleReadObject)).append(LS); + continue; + } + var readObject = rbSerializer(fieldRegistration.serializer()).readObject(rbBuilder, 0, field, fieldRegistration); + rbBuilder.append(StringUtils.format("packet.{} = {}", field.getName(), readObject)).append(LS); + } + return rbBuilder.toString(); + } + +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/IRubySerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/IRubySerializer.java new file mode 100644 index 00000000..6e28fa5d --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/IRubySerializer.java @@ -0,0 +1,31 @@ +/* + * 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.ruby; + +import com.zfoo.protocol.registration.field.IFieldRegistration; + +import java.lang.reflect.Field; + +/** + * @author godotg + */ +public interface IRubySerializer { + + String fieldDefaultValue(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/ruby/RubyArraySerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyArraySerializer.java new file mode 100644 index 00000000..1595c7ed --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyArraySerializer.java @@ -0,0 +1,100 @@ +/* + * 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.ruby; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +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 RubyArraySerializer implements IRubySerializer { + @Override + public String fieldDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return "Array.new()"; + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + if (CutDownArraySerializer.getInstance().writeObject(builder, objectStr, field, fieldRegistration, CodeLanguage.Ruby)) { + return; + } + + ArrayField arrayField = (ArrayField) fieldRegistration; + + builder.append(StringUtils.format("if {}.nil? || {}.empty?", objectStr, objectStr)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("buffer.writeInt(0)").append(LS); + GenerateProtocolFile.addTab(builder, deep); + + builder.append("else").append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("buffer.writeInt({}.length)", objectStr)).append(LS); + + String element = "element" + GenerateProtocolFile.localVariableId++; + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("for {} in {}", element, objectStr)).append(LS); + CodeGenerateRuby.rbSerializer(arrayField.getArrayElementRegistration().serializer()) + .writeObject(builder, element, deep + 2, field, arrayField.getArrayElementRegistration()); + + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("end").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("end").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.Ruby); + if (cutDown != null) { + return cutDown; + } + + ArrayField arrayField = (ArrayField) fieldRegistration; + String result = "result" + GenerateProtocolFile.localVariableId++; + + builder.append(StringUtils.format("{} = Array.new()", result)).append(LS); + + String i = "index" + GenerateProtocolFile.localVariableId++; + String size = "size" + GenerateProtocolFile.localVariableId++; + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("{} = buffer.readInt()", size)).append(LS); + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("if {} > 0", size)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("for {} in 0..{} - 1", i, size)).append(LS); + String readObject = CodeGenerateRuby.rbSerializer(arrayField.getArrayElementRegistration().serializer()) + .readObject(builder, deep + 2, field, arrayField.getArrayElementRegistration()); + GenerateProtocolFile.addTab(builder, deep + 2); + builder.append(StringUtils.format("{}.push({})", result, readObject)).append(LS); + + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("end").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("end").append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyBoolSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyBoolSerializer.java new file mode 100644 index 00000000..d7dcde95 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyBoolSerializer.java @@ -0,0 +1,47 @@ +/* + * 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.ruby; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +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 RubyBoolSerializer implements IRubySerializer { + @Override + public String fieldDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return "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("{} = buffer.readBool() ", result)).append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyByteSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyByteSerializer.java new file mode 100644 index 00000000..ddb0218d --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyByteSerializer.java @@ -0,0 +1,47 @@ +/* + * 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.ruby; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +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 RubyByteSerializer implements IRubySerializer { + @Override + public String fieldDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return "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("{} = buffer.readByte()", result)).append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyDoubleSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyDoubleSerializer.java new file mode 100644 index 00000000..3594e849 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyDoubleSerializer.java @@ -0,0 +1,47 @@ +/* + * 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.ruby; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +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 RubyDoubleSerializer implements IRubySerializer { + @Override + public String fieldDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return "0.0"; + } + + @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("{} = buffer.readDouble()", result)).append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyFloatSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyFloatSerializer.java new file mode 100644 index 00000000..98ac0a69 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyFloatSerializer.java @@ -0,0 +1,47 @@ +/* + * 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.ruby; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +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 RubyFloatSerializer implements IRubySerializer { + @Override + public String fieldDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return "0.0"; + } + + @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("{} = buffer.readFloat()", result)).append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyIntSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyIntSerializer.java new file mode 100644 index 00000000..5ee64247 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyIntSerializer.java @@ -0,0 +1,47 @@ +/* + * 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.ruby; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +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 RubyIntSerializer implements IRubySerializer { + @Override + public String fieldDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return "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("{} = buffer.readInt()", result)).append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyListSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyListSerializer.java new file mode 100644 index 00000000..6a613731 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyListSerializer.java @@ -0,0 +1,100 @@ +/* + * 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.ruby; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +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 RubyListSerializer implements IRubySerializer { + @Override + public String fieldDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return "Array.new()"; + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + if (CutDownListSerializer.getInstance().writeObject(builder, objectStr, field, fieldRegistration, CodeLanguage.Ruby)) { + return; + } + + ListField listField = (ListField) fieldRegistration; + + builder.append(StringUtils.format("if {}.nil? || {}.empty?", objectStr, objectStr)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("buffer.writeInt(0)").append(LS); + GenerateProtocolFile.addTab(builder, deep); + + builder.append("else").append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("buffer.writeInt({}.length)", objectStr)).append(LS); + + String element = "element" + GenerateProtocolFile.localVariableId++; + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("for {} in {}", element, objectStr)).append(LS); + CodeGenerateRuby.rbSerializer(listField.getListElementRegistration().serializer()) + .writeObject(builder, element, deep + 2, field, listField.getListElementRegistration()); + + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("end").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("end").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.Ruby); + if (cutDown != null) { + return cutDown; + } + + ListField listField = (ListField) fieldRegistration; + String result = "result" + GenerateProtocolFile.localVariableId++; + + builder.append(StringUtils.format("{} = Array.new()", result)).append(LS); + + String i = "index" + GenerateProtocolFile.localVariableId++; + String size = "size" + GenerateProtocolFile.localVariableId++; + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("{} = buffer.readInt()", size)).append(LS); + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("if {} > 0", size)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("for {} in 0..{} - 1", i, size)).append(LS); + String readObject = CodeGenerateRuby.rbSerializer(listField.getListElementRegistration().serializer()) + .readObject(builder, deep + 2, field, listField.getListElementRegistration()); + GenerateProtocolFile.addTab(builder, deep + 2); + builder.append(StringUtils.format("{}.push({})", result, readObject)).append(LS); + + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("end").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("end").append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyLongSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyLongSerializer.java new file mode 100644 index 00000000..fd56ddfe --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyLongSerializer.java @@ -0,0 +1,47 @@ +/* + * 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.ruby; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +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 RubyLongSerializer implements IRubySerializer { + @Override + public String fieldDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return "0"; + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("buffer.writeLong({})", objectStr)).append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + String result = "result" + GenerateProtocolFile.localVariableId++; + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("{} = buffer.readLong()", result)).append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyMapSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyMapSerializer.java new file mode 100644 index 00000000..9e331c37 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyMapSerializer.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.ruby; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +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 RubyMapSerializer implements IRubySerializer { + @Override + public String fieldDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return "Hash.new()"; + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + if (CutDownMapSerializer.getInstance().writeObject(builder, objectStr, field, fieldRegistration, CodeLanguage.Ruby)) { + return; + } + + MapField mapField = (MapField) fieldRegistration; + builder.append(StringUtils.format("if {}.nil? || {}.empty?", objectStr, objectStr)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("buffer.writeInt(0)").append(LS); + + GenerateProtocolFile.addTab(builder, deep); + builder.append("else").append(LS); + + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("buffer.writeInt({}.length)", objectStr)).append(LS); + + String key = "key" + GenerateProtocolFile.localVariableId++; + String value = "value" + GenerateProtocolFile.localVariableId++; + + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("{}.each do |{}, {}|", objectStr, key, value)).append(LS); + CodeGenerateRuby.rbSerializer(mapField.getMapKeyRegistration().serializer()) + .writeObject(builder, key, deep + 2, field, mapField.getMapKeyRegistration()); + CodeGenerateRuby.rbSerializer(mapField.getMapValueRegistration().serializer()) + .writeObject(builder, value, deep + 2, field, mapField.getMapValueRegistration()); + + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("end").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("end").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.Ruby); + if (cutDown != null) { + return cutDown; + } + + MapField mapField = (MapField) fieldRegistration; + String result = "result" + GenerateProtocolFile.localVariableId++; + + builder.append(StringUtils.format("{} = Hash.new()", result)).append(LS); + + GenerateProtocolFile.addTab(builder, deep); + String size = "size" + GenerateProtocolFile.localVariableId++; + builder.append(StringUtils.format("{} = buffer.readInt()", size)).append(LS); + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("if {} > 0", size)).append(LS); + + String i = "index" + GenerateProtocolFile.localVariableId++; + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("for {} in 0..{} - 1", i, size)).append(LS); + + String keyObject = CodeGenerateRuby.rbSerializer(mapField.getMapKeyRegistration().serializer()) + .readObject(builder, deep + 2, field, mapField.getMapKeyRegistration()); + + + String valueObject = CodeGenerateRuby.rbSerializer(mapField.getMapValueRegistration().serializer()) + .readObject(builder, deep + 2, field, mapField.getMapValueRegistration()); + GenerateProtocolFile.addTab(builder, deep + 2); + + builder.append(StringUtils.format("{}[{}] = {}", result, keyObject, valueObject)).append(LS); + + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("end").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("end").append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyObjectProtocolSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyObjectProtocolSerializer.java new file mode 100644 index 00000000..63d4e65a --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyObjectProtocolSerializer.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.ruby; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.registration.field.ObjectProtocolField; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + +/** + * @author godotg + */ +public class RubyObjectProtocolSerializer implements IRubySerializer { + @Override + public String fieldDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return "nil"; + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + ObjectProtocolField objectProtocolField = (ObjectProtocolField) fieldRegistration; + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("buffer.writePacket({}, {})", objectStr, objectProtocolField.getProtocolId())).append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + ObjectProtocolField objectProtocolField = (ObjectProtocolField) fieldRegistration; + var result = "result" + GenerateProtocolFile.localVariableId++; + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("{} = buffer.readPacket({})", result, objectProtocolField.getProtocolId())).append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubySetSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubySetSerializer.java new file mode 100644 index 00000000..5cd041d2 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubySetSerializer.java @@ -0,0 +1,100 @@ +/* + * 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.ruby; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +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 RubySetSerializer implements IRubySerializer { + @Override + public String fieldDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return "Set.new()"; + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + if (CutDownSetSerializer.getInstance().writeObject(builder, objectStr, field, fieldRegistration, CodeLanguage.Ruby)) { + return; + } + + SetField setField = (SetField) fieldRegistration; + + builder.append(StringUtils.format("if {}.nil? || {}.empty?", objectStr, objectStr)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("buffer.writeInt(0)").append(LS); + GenerateProtocolFile.addTab(builder, deep); + + builder.append("else").append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("buffer.writeInt({}.length)", objectStr)).append(LS); + + String element = "element" + GenerateProtocolFile.localVariableId++; + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("for {} in {}", element, objectStr)).append(LS); + CodeGenerateRuby.rbSerializer(setField.getSetElementRegistration().serializer()) + .writeObject(builder, element, deep + 2, field, setField.getSetElementRegistration()); + + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("end").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("end").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.Ruby); + if (cutDown != null) { + return cutDown; + } + + SetField setField = (SetField) fieldRegistration; + String result = "result" + GenerateProtocolFile.localVariableId++; + + builder.append(StringUtils.format("{} = Set.new()", result)).append(LS); + + String i = "index" + GenerateProtocolFile.localVariableId++; + String size = "size" + GenerateProtocolFile.localVariableId++; + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("{} = buffer.readInt()", size)).append(LS); + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("if {} > 0", size)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("for {} in 0..{} - 1", i, size)).append(LS); + String readObject = CodeGenerateRuby.rbSerializer(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("end").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("end").append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyShortSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyShortSerializer.java new file mode 100644 index 00000000..4bfb67ee --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyShortSerializer.java @@ -0,0 +1,47 @@ +/* + * 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.ruby; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +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 RubyShortSerializer implements IRubySerializer { + @Override + public String fieldDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return "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("{} = buffer.readShort()", result)).append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyStringSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyStringSerializer.java new file mode 100644 index 00000000..91561cf1 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/ruby/RubyStringSerializer.java @@ -0,0 +1,46 @@ +/* + * 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.ruby; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +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 RubyStringSerializer implements IRubySerializer { + @Override + public String fieldDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return "\"\""; + } + + @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("{} = buffer.readString()", result)).append(LS); + return result; + } +} diff --git a/protocol/src/main/resources/ruby/ByteBuffer.rb b/protocol/src/main/resources/ruby/ByteBuffer.rb new file mode 100644 index 00000000..074d9447 --- /dev/null +++ b/protocol/src/main/resources/ruby/ByteBuffer.rb @@ -0,0 +1,320 @@ +require_relative "ProtocolManager.rb" + +class ByteBuffer + def initialize() + @writeOffset = 0 + @readOffset = 0 + @buffer = "\u0000" * 2 + end + + def compatibleRead(beforeReadIndex, length) + return length != -1 && getWriteOffset() < length + beforeReadIndex + end + + def getCapacity() + return @buffer.length - @writeOffset + end + + def ensureCapacity(capacity) + while capacity > getCapacity() + @buffer += "\u0000" * @buffer.length + end + end + + def getBuffer() + return @buffer + end + + def getWriteOffset() + return @writeOffset + end + + def setWriteOffset(writeIndex) + if writeIndex > @buffer.length + raise "writeIndex[#{writeIndex}] out of bounds exception: readOffset: #{@readOffset} , writeOffset: #{@writeOffset}(expected: 0 <= readOffset <= writeOffset <= capacity:#{@buffer.length})" + end + @writeOffset = writeIndex + end + + def getReadOffset() + return @readOffset + end + + def setReadOffset(readIndex) + if readIndex > @writeOffset + raise "readIndex[#{readIndex}] out of bounds exception: readOffset: #{@readOffset} , writeOffset: #{@writeOffset}(expected: 0 <= readOffset <= writeOffset <= capacity:#{@buffer.length})" + end + @readOffset = readIndex + end + + def writeBytes(bytes) + ensureCapacity(bytes.length) + for i in 0..bytes.length + writeByte(bytes[i]) + end + end + + def writeBytesString(bytes) + length = bytes.length + ensureCapacity(length) + @buffer[@writeOffset..(@writeOffset + length - 1)] = bytes[0..(length - 1)] + @writeOffset += length + end + + def writeBool(value) + ensureCapacity(1) + if value == true + @buffer[@writeOffset] = "\u0001" + else + @buffer[@writeOffset] = "\u0000" + end + @writeOffset += 1 + end + + def readBool() + value = false + if @buffer[@readOffset] == "\u0001" + value = true + end + @readOffset += 1 + return value + end + + def writeByte(value) + ensureCapacity(1) + @buffer[@writeOffset] = [value].pack('c')[0] + @writeOffset += 1 + end + + def readByte() + value = @buffer[@readOffset].unpack('c').first + @readOffset += 1 + return value + end + + def readUByte() + value = @buffer.getbyte(@readOffset) + @readOffset += 1 + return value + end + + + def writeShort(value) + ensureCapacity(2) + @buffer[@writeOffset..(@writeOffset + 1)] = [value].pack('s>')[0..1] + @writeOffset += 2 + end + + def readShort() + value = @buffer[@readOffset..(@readOffset + 1)].unpack('s>').first + @readOffset += 2 + return value + end + + def writeRawInt(value) + ensureCapacity(4) + @buffer[@writeOffset..(@writeOffset + 3)] = [value].pack('i>')[0..3] + @writeOffset += 4 + end + + def readRawInt() + value = @buffer[@readOffset..(@readOffset + 3)].unpack('i>').first + @readOffset += 4 + return value + end + + def writeInt(value) + writeLong(value) + end + + def readInt() + return readLong() + end + + def writeLong(longValue) + value = (longValue << 1) ^ (longValue >> 63) + if value < 0 + writeByte(value & 0xFF | 0x80) + writeByte(value >> 7 & 0xFF | 0x80) + writeByte(value >> 14 & 0xFF | 0x80) + writeByte(value >> 21 & 0xFF | 0x80) + writeByte(value >> 28 & 0xFF | 0x80) + writeByte(value >> 35 & 0xFF | 0x80) + writeByte(value >> 42 & 0xFF | 0x80) + writeByte(value >> 49 & 0xFF | 0x80) + writeByte(value >> 56 & 0xFF) + return + end + if value >> 7 == 0 + writeByte(value) + return + end + if value >> 14 == 0 + writeByte(value | 0x80) + writeByte(value >> 7) + return + end + if value >> 21 == 0 + writeByte(value | 0x80) + writeByte(value >> 7 | 0x80) + writeByte(value >> 14) + return + end + if value >> 28 == 0 + writeByte(value | 0x80) + writeByte(value >> 7 | 0x80) + writeByte(value >> 14 | 0x80) + writeByte(value >> 21) + return + end + if value >> 35 == 0 + writeByte(value | 0x80) + writeByte(value >> 7 | 0x80) + writeByte(value >> 14 | 0x80) + writeByte(value >> 21 | 0x80) + writeByte(value >> 28) + return + end + if value >> 42 == 0 + writeByte(value | 0x80) + writeByte(value >> 7 | 0x80) + writeByte(value >> 14 | 0x80) + writeByte(value >> 21 | 0x80) + writeByte(value >> 28 | 0x80) + writeByte(value >> 35) + return + end + if value >> 49 == 0 + writeByte(value | 0x80) + writeByte(value >> 7 | 0x80) + writeByte(value >> 14 | 0x80) + writeByte(value >> 21 | 0x80) + writeByte(value >> 28 | 0x80) + writeByte(value >> 35 | 0x80) + writeByte(value >> 42) + return + end + if (value >> 56) == 0 + writeByte(value | 0x80) + writeByte(value >> 7 | 0x80) + writeByte(value >> 14 | 0x80) + writeByte(value >> 21 | 0x80) + writeByte(value >> 28 | 0x80) + writeByte(value >> 35 | 0x80) + writeByte(value >> 42 | 0x80) + writeByte(value >> 49) + return + end + writeByte(value | 0x80) + writeByte(value >> 7 | 0x80) + writeByte(value >> 14 | 0x80) + writeByte(value >> 21 | 0x80) + writeByte(value >> 28 | 0x80) + writeByte(value >> 35 | 0x80) + writeByte(value >> 42 | 0x80) + writeByte(value >> 49 | 0x80) + writeByte(value >> 56) + return + end + + def readLong() + b = readUByte() + value = b + if b > 127 + b = readUByte() + value = value & 0x00000000_0000007F | b << 7 + if b > 127 + b = readUByte() + value = value & 0x00000000_00003FFF | b << 14 + if b > 127 + b = readUByte() + value = value & 0x00000000_001FFFFF | b << 21 + if b > 127 + b = readUByte() + value = value & 0x00000000_0FFFFFFF | b << 28 + if b > 127 + b = readUByte() + value = value & 0x00000007_FFFFFFFF | b << 35 + if b > 127 + b = readUByte() + value = value & 0x000003FF_FFFFFFFF | b << 42 + if b > 127 + b = readUByte() + value = value & 0x0001FFFF_FFFFFFFF | b << 49 + if b > 127 + b = readUByte() + value = value & 0x00FFFFFF_FFFFFFFF | b << 56 + end + end + end + end + end + end + end + end + return ((value >> 1 & 0x7FFFFFFF_FFFFFFFF) ^ -(value & 1)) + end + + def writeFloat(value) + ensureCapacity(4) + @buffer[@writeOffset..(@writeOffset + 3)] = [value].pack('f')[0..3] + @writeOffset += 4 + end + + def readFloat() + value = @buffer[@readOffset..(@readOffset + 3)].unpack('f').first + @readOffset += 4 + return value + end + + def writeDouble(value) + ensureCapacity(8) + @buffer[@writeOffset..(@writeOffset + 7)] = [value].pack('d')[0..7] + @writeOffset += 8 + end + + def readDouble() + value = @buffer[@readOffset..(@readOffset + 7)].unpack('d').first + @readOffset += 8 + return value + end + + def writeString(value) + if value.nil? || value.empty? + writeInt(0) + return + end + value = value.dup + value.force_encoding("UTF-8") + bytes = value.bytes() + length = bytes.length + writeInt(length) + ensureCapacity(length) + @buffer[@writeOffset..(@writeOffset + length - 1)] = bytes.pack('C*')[0..(length - 1)] + @writeOffset += length + end + + def readString() + length = readInt() + if length == 0 + return "" + end + value = "\u0000" * length + for i in 0..(length - 1) + value.setbyte(i, readUByte()) + end + value.force_encoding("UTF-8") + return value + end + + def writePacket(packet, protocolId) + protocolRegistration = ProtocolManager.getProtocol(protocolId) + protocolRegistration.write(self, packet) + end + + def readPacket(protocolId) + protocolRegistration = ProtocolManager.getProtocol(protocolId) + return protocolRegistration.read(self) + end + +end \ No newline at end of file diff --git a/protocol/src/main/resources/ruby/ProtocolClassTemplate.rb b/protocol/src/main/resources/ruby/ProtocolClassTemplate.rb new file mode 100644 index 00000000..1fcc5b5c --- /dev/null +++ b/protocol/src/main/resources/ruby/ProtocolClassTemplate.rb @@ -0,0 +1,7 @@ +${protocol_note} +class ${protocol_name} + ${protocol_field_accessor} + def initialize() + ${protocol_field_definition} + end +end diff --git a/protocol/src/main/resources/ruby/ProtocolManagerTemplate.rb b/protocol/src/main/resources/ruby/ProtocolManagerTemplate.rb new file mode 100644 index 00000000..740b4c19 --- /dev/null +++ b/protocol/src/main/resources/ruby/ProtocolManagerTemplate.rb @@ -0,0 +1,29 @@ +${protocol_imports} + + +class ProtocolManager + @@protocols = Array.new(32767) + @@protocolIdMap = Hash.new() + + def self.initProtocol() + ${protocol_manager_registrations} + end + + def self.getProtocol(protocolId) + return @@protocols[protocolId] + end + + def self.write(buffer, packet) + protocolId = @@protocolIdMap[packet.class] + buffer.writeShort(protocolId) + protocol = @@protocols[protocolId] + protocol.write(buffer, packet) + end + + def self.read(buffer) + protocolId = buffer.readShort() + protocol = @@protocols[protocolId] + packet = protocol.read(buffer) + return packet + end +end \ No newline at end of file diff --git a/protocol/src/main/resources/ruby/ProtocolRegistrationTemplate.rb b/protocol/src/main/resources/ruby/ProtocolRegistrationTemplate.rb new file mode 100644 index 00000000..07c652bc --- /dev/null +++ b/protocol/src/main/resources/ruby/ProtocolRegistrationTemplate.rb @@ -0,0 +1,27 @@ +class ${protocol_name}Registration + def protocolId() + return ${protocol_id} + end + + def write(buffer, packet) + if packet.nil? + buffer.writeInt(0) + return + end + ${protocol_write_serialization} + end + + def read(buffer) + length = buffer.readInt() + if length == 0 + return nil + end + beforeReadIndex = buffer.getReadOffset() + packet = ${protocol_name}.new() + ${protocol_read_deserialization} + if length > 0 + buffer.setReadOffset(beforeReadIndex + length) + end + return packet + end +end \ No newline at end of file diff --git a/protocol/src/main/resources/ruby/ProtocolTemplate.rb b/protocol/src/main/resources/ruby/ProtocolTemplate.rb new file mode 100644 index 00000000..f1867def --- /dev/null +++ b/protocol/src/main/resources/ruby/ProtocolTemplate.rb @@ -0,0 +1,3 @@ +${protocol_class} + +${protocol_registration} \ No newline at end of file diff --git a/protocol/src/main/resources/ruby/ProtocolsTemplate.rb b/protocol/src/main/resources/ruby/ProtocolsTemplate.rb new file mode 100644 index 00000000..f1867def --- /dev/null +++ b/protocol/src/main/resources/ruby/ProtocolsTemplate.rb @@ -0,0 +1,3 @@ +${protocol_class} + +${protocol_registration} \ No newline at end of file