From 99d3cd8b3da461f954ad7a552d636c32feae69df Mon Sep 17 00:00:00 2001 From: godotg Date: Sat, 26 Aug 2023 18:30:23 +0800 Subject: [PATCH] feat[python]: support python --- .gitignore | 1 + .../generate/GenerateProtocolFile.java | 17 +- .../generate/GenerateProtocolNote.java | 12 +- .../registration/ProtocolAnalysis.java | 2 + .../serializer/python/GeneratePyUtils.java | 187 +++++++++++ .../serializer/python/IPySerializer.java | 32 ++ .../serializer/python/PyArraySerializer.java | 92 ++++++ .../python/PyBooleanSerializer.java | 49 +++ .../serializer/python/PyByteSerializer.java | 49 +++ .../serializer/python/PyCharSerializer.java | 48 +++ .../serializer/python/PyDoubleSerializer.java | 49 +++ .../serializer/python/PyFloatSerializer.java | 49 +++ .../serializer/python/PyIntSerializer.java | 49 +++ .../serializer/python/PyListSerializer.java | 92 ++++++ .../serializer/python/PyLongSerializer.java | 49 +++ .../serializer/python/PyMapSerializer.java | 104 ++++++ .../python/PyObjectProtocolSerializer.java | 51 +++ .../serializer/python/PySetSerializer.java | 92 ++++++ .../serializer/python/PyShortSerializer.java | 49 +++ .../serializer/python/PyStringSerializer.java | 48 +++ .../main/resources/python/ProtocolTemplate.py | 18 ++ .../src/main/resources/python/byte_buffer.py | 303 ++++++++++++++++++ .../java/com/zfoo/protocol/SpeedTest.java | 2 + 23 files changed, 1434 insertions(+), 10 deletions(-) create mode 100644 protocol/src/main/java/com/zfoo/protocol/serializer/python/GeneratePyUtils.java create mode 100644 protocol/src/main/java/com/zfoo/protocol/serializer/python/IPySerializer.java create mode 100644 protocol/src/main/java/com/zfoo/protocol/serializer/python/PyArraySerializer.java create mode 100644 protocol/src/main/java/com/zfoo/protocol/serializer/python/PyBooleanSerializer.java create mode 100644 protocol/src/main/java/com/zfoo/protocol/serializer/python/PyByteSerializer.java create mode 100644 protocol/src/main/java/com/zfoo/protocol/serializer/python/PyCharSerializer.java create mode 100644 protocol/src/main/java/com/zfoo/protocol/serializer/python/PyDoubleSerializer.java create mode 100644 protocol/src/main/java/com/zfoo/protocol/serializer/python/PyFloatSerializer.java create mode 100644 protocol/src/main/java/com/zfoo/protocol/serializer/python/PyIntSerializer.java create mode 100644 protocol/src/main/java/com/zfoo/protocol/serializer/python/PyListSerializer.java create mode 100644 protocol/src/main/java/com/zfoo/protocol/serializer/python/PyLongSerializer.java create mode 100644 protocol/src/main/java/com/zfoo/protocol/serializer/python/PyMapSerializer.java create mode 100644 protocol/src/main/java/com/zfoo/protocol/serializer/python/PyObjectProtocolSerializer.java create mode 100644 protocol/src/main/java/com/zfoo/protocol/serializer/python/PySetSerializer.java create mode 100644 protocol/src/main/java/com/zfoo/protocol/serializer/python/PyShortSerializer.java create mode 100644 protocol/src/main/java/com/zfoo/protocol/serializer/python/PyStringSerializer.java create mode 100644 protocol/src/main/resources/python/ProtocolTemplate.py create mode 100644 protocol/src/main/resources/python/byte_buffer.py diff --git a/.gitignore b/.gitignore index fb832270..a391a886 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,7 @@ test.md # 忽略生成的协议文件 **/jsProtocol/ **/gdProtocol/ +**/pyProtocol/ **/CsProtocol/ **/LuaProtocol/ **/cppProtocol/ diff --git a/protocol/src/main/java/com/zfoo/protocol/generate/GenerateProtocolFile.java b/protocol/src/main/java/com/zfoo/protocol/generate/GenerateProtocolFile.java index 5e8937fa..7d8a83ba 100644 --- a/protocol/src/main/java/com/zfoo/protocol/generate/GenerateProtocolFile.java +++ b/protocol/src/main/java/com/zfoo/protocol/generate/GenerateProtocolFile.java @@ -25,6 +25,7 @@ import com.zfoo.protocol.serializer.go.GenerateGoUtils; import com.zfoo.protocol.serializer.javascript.GenerateJsUtils; import com.zfoo.protocol.serializer.lua.GenerateLuaUtils; import com.zfoo.protocol.serializer.protobuf.GenerateProtobufUtils; +import com.zfoo.protocol.serializer.python.GeneratePyUtils; import com.zfoo.protocol.serializer.typescript.GenerateTsUtils; import java.io.IOException; @@ -62,11 +63,8 @@ public abstract class GenerateProtocolFile { } /** - * 生成各种语言的协议文件 - * - * @param generateOperation - * @throws IOException - * @throws ClassNotFoundException + * EN: Generate protocol files to various languages + * CN: 生成各种语言的协议文件 */ public static void generate(GenerateOperation generateOperation) throws IOException, ClassNotFoundException { var protocols = ProtocolManager.protocols; @@ -172,6 +170,15 @@ public abstract class GenerateProtocolFile { } } + // 生成Python协议 + if (generateLanguages.contains(CodeLanguage.Python)) { + GeneratePyUtils.init(generateOperation); + GeneratePyUtils.createProtocolManager(allSortedGenerateProtocols); + for (var protocolRegistration : allSortedGenerateProtocols) { + GeneratePyUtils.createPyProtocolFile((ProtocolRegistration) protocolRegistration); + } + } + // 生成Protobuf协议 if (generateLanguages.contains(CodeLanguage.Protobuf)) { GenerateProtobufUtils.init(generateOperation); 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 eca46d74..1aef10dc 100644 --- a/protocol/src/main/java/com/zfoo/protocol/generate/GenerateProtocolNote.java +++ b/protocol/src/main/java/com/zfoo/protocol/generate/GenerateProtocolNote.java @@ -28,7 +28,8 @@ import java.util.List; import java.util.Map; /** - * 生成协议的时候,协议的文档注释和字段注释会使用这个类 + * EN: When generating the protocol, the document comments and field comments of the protocol will use this class + * CN: 生成协议的时候,协议的文档注释和字段注释会使用这个类 * * @author godotg * @version 3.0 @@ -38,14 +39,14 @@ public abstract class GenerateProtocolNote { // 临时变量,启动完成就会销毁,协议的文档,外层map的key为协议类;pair的key为总的注释,value为属性字段的注释,value表示的map的key为属性名称 // 比如在Test中的ComplexObject生成的pari是如下格式 /** - * key docTitle: + * key is docTitle note: * // 复杂的对象 * // 包括了各种复杂的结构,数组,List,Set,Map * // * // @author godotg * // @version 1.0 *

- * value aa: + * value is field note: * // byte的包装类型 * // 优先使用基础类型,包装类型会有装箱拆箱 */ @@ -92,18 +93,19 @@ public abstract class GenerateProtocolNote { case Lua: fieldNote = StringUtils.format("-- {}", fieldNote).replace("\n", "\n-- "); break; + case Python: case GdScript: fieldNote = StringUtils.format("# {}", fieldNote).replace("\n", "\n# "); break; case Enhance: default: - throw new RunException("无法识别的枚举类型[{}]", language); + throw new RunException("unrecognized enum type [{}]", language); } return fieldNote; } public static void initProtocolNote(List protocolRegistrations) { - AssertionUtils.notNull(protocolNoteMap, "[{}]已经初始完成,初始化完成过后不能调用initProtocolDocument", GenerateProtocolNote.class.getSimpleName()); + AssertionUtils.notNull(protocolNoteMap, "[{}] duplicate initialization", GenerateProtocolNote.class.getSimpleName()); for (var protocolRegistration : protocolRegistrations) { var protocolClazz = protocolRegistration.protocolConstructor().getDeclaringClass(); diff --git a/protocol/src/main/java/com/zfoo/protocol/registration/ProtocolAnalysis.java b/protocol/src/main/java/com/zfoo/protocol/registration/ProtocolAnalysis.java index 592e039d..f334a1dc 100644 --- a/protocol/src/main/java/com/zfoo/protocol/registration/ProtocolAnalysis.java +++ b/protocol/src/main/java/com/zfoo/protocol/registration/ProtocolAnalysis.java @@ -33,6 +33,7 @@ import com.zfoo.protocol.serializer.go.GenerateGoUtils; import com.zfoo.protocol.serializer.javascript.GenerateJsUtils; import com.zfoo.protocol.serializer.lua.GenerateLuaUtils; import com.zfoo.protocol.serializer.protobuf.GenerateProtobufUtils; +import com.zfoo.protocol.serializer.python.GeneratePyUtils; import com.zfoo.protocol.serializer.reflect.*; import com.zfoo.protocol.serializer.typescript.GenerateTsUtils; import com.zfoo.protocol.util.AssertionUtils; @@ -352,6 +353,7 @@ public class ProtocolAnalysis { GenerateTsUtils.clear(); GenerateLuaUtils.clear(); GenerateGdUtils.clear(); + GeneratePyUtils.clear(); GenerateProtobufUtils.clear(); } diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/python/GeneratePyUtils.java b/protocol/src/main/java/com/zfoo/protocol/serializer/python/GeneratePyUtils.java new file mode 100644 index 00000000..c515bac4 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/python/GeneratePyUtils.java @@ -0,0 +1,187 @@ +/* + * 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.python; + +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.IProtocolRegistration; +import com.zfoo.protocol.registration.ProtocolRegistration; +import com.zfoo.protocol.registration.anno.Compatible; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.serializer.CodeLanguage; +import com.zfoo.protocol.serializer.csharp.GenerateCsUtils; +import com.zfoo.protocol.serializer.reflect.*; +import com.zfoo.protocol.util.*; + +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; +import static com.zfoo.protocol.util.StringUtils.TAB_ASCII; + +/** + * @author godotg + * @version 3.0 + */ +public abstract class GeneratePyUtils { + + private static String protocolOutputRootPath = "pyProtocol/"; + + private static Map pySerializerMap; + + + public static IPySerializer pySerializer(ISerializer serializer) { + return pySerializerMap.get(serializer); + } + + public static void init(GenerateOperation generateOperation) { + protocolOutputRootPath = FileUtils.joinPath(generateOperation.getProtocolPath(), protocolOutputRootPath); + + FileUtils.deleteFile(new File(protocolOutputRootPath)); + FileUtils.createDirectory(protocolOutputRootPath); + + pySerializerMap = new HashMap<>(); + pySerializerMap.put(BooleanSerializer.INSTANCE, new PyBooleanSerializer()); + pySerializerMap.put(ByteSerializer.INSTANCE, new PyByteSerializer()); + pySerializerMap.put(ShortSerializer.INSTANCE, new PyShortSerializer()); + pySerializerMap.put(IntSerializer.INSTANCE, new PyIntSerializer()); + pySerializerMap.put(LongSerializer.INSTANCE, new PyLongSerializer()); + pySerializerMap.put(FloatSerializer.INSTANCE, new PyFloatSerializer()); + pySerializerMap.put(DoubleSerializer.INSTANCE, new PyDoubleSerializer()); + pySerializerMap.put(CharSerializer.INSTANCE, new PyCharSerializer()); + pySerializerMap.put(StringSerializer.INSTANCE, new PyStringSerializer()); + pySerializerMap.put(ArraySerializer.INSTANCE, new PyArraySerializer()); + pySerializerMap.put(ListSerializer.INSTANCE, new PyListSerializer()); + pySerializerMap.put(SetSerializer.INSTANCE, new PySetSerializer()); + pySerializerMap.put(MapSerializer.INSTANCE, new PyMapSerializer()); + pySerializerMap.put(ObjectProtocolSerializer.INSTANCE, new PyObjectProtocolSerializer()); + } + + public static void clear() { + pySerializerMap = null; + protocolOutputRootPath = null; + } + + public static void createProtocolManager(List protocolList) throws IOException { + var list = List.of("python/byte_buffer.py"); + for (var fileName : list) { + var fileInputStream = ClassUtils.getFileFromClassPath(fileName); + var createFile = new File(StringUtils.format("{}/{}", protocolOutputRootPath, StringUtils.substringAfterFirst(fileName, "python/"))); + FileUtils.writeInputStreamToFile(createFile, fileInputStream); + } + + // 生成ProtocolManager.js文件 + var protocolManagerTemplate = StringUtils.bytesToString(IOUtils.toByteArray(ClassUtils.getFileFromClassPath("javascript/ProtocolManagerTemplate.js"))); + + var importBuilder = new StringBuilder(); + var initProtocolBuilder = new StringBuilder(); + for (var protocol : protocolList) { + var protocolId = protocol.protocolId(); + var protocolName = protocol.protocolConstructor().getDeclaringClass().getSimpleName(); + var path = GenerateProtocolPath.protocolAbsolutePath(protocol.protocolId(), CodeLanguage.JavaScript); + importBuilder.append(StringUtils.format("import {} from './{}.js';", protocolName, path)).append(LS); + initProtocolBuilder.append(StringUtils.format("protocols.set({}, {});", protocolId, protocolName)).append(LS); + } + + protocolManagerTemplate = StringUtils.format(protocolManagerTemplate, importBuilder.toString().trim(), StringUtils.EMPTY_JSON, initProtocolBuilder.toString().trim()); + FileUtils.writeStringToFile(new File(StringUtils.format("{}/{}", protocolOutputRootPath, "ProtocolManager.js")), protocolManagerTemplate, true); + } + + public static void createPyProtocolFile(ProtocolRegistration registration) { + GenerateProtocolFile.index.set(0); + + var protocolId = registration.protocolId(); + var registrationConstructor = registration.getConstructor(); + var protocolClazzName = registrationConstructor.getDeclaringClass().getSimpleName(); + + var protocolTemplate = ClassUtils.getFileFromClassPathToString("python/ProtocolTemplate.py"); + + var classNote = GenerateProtocolNote.classNote(protocolId, CodeLanguage.Python); + var fieldDefinition = fieldDefinition(registration); + var writeObject = writeObject(registration); + var readObject = readObject(registration); + + protocolTemplate = StringUtils.format(protocolTemplate, classNote, protocolClazzName + , fieldDefinition.trim(), protocolId, writeObject.trim(), readObject.trim(), protocolClazzName); + var protocolOutputPath = StringUtils.format("{}/{}/{}.py", protocolOutputRootPath + , GenerateProtocolPath.getProtocolPath(protocolId), protocolClazzName); + FileUtils.writeStringToFile(new File(protocolOutputPath), protocolTemplate, true); + } + + private static String fieldDefinition(ProtocolRegistration registration) { + var protocolId = registration.getId(); + var fields = registration.getFields(); + var fieldRegistrations = registration.getFieldRegistrations(); + var pyBuilder = 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 fieldNote = GenerateProtocolNote.fieldNote(protocolId, fieldName, CodeLanguage.Python); + if (StringUtils.isNotBlank(fieldNote)) { + pyBuilder.append(TAB).append(fieldNote).append(LS); + } + var fieldDefaultValue = pySerializer(fieldRegistration.serializer()).fieldDefaultValue(field, fieldRegistration); + // 生成类型的注释 + pyBuilder.append(StringUtils.format("{}{} = {}", TAB, fieldName, fieldDefaultValue)); + pyBuilder.append(StringUtils.format(" # {}", GenerateCsUtils.toCsClassName(field.getGenericType().getTypeName()))); + pyBuilder.append(LS); + } + return pyBuilder.toString(); + } + + private static String writeObject(ProtocolRegistration registration) { + var fields = registration.getFields(); + var fieldRegistrations = registration.getFieldRegistrations(); + var pyBuilder = new StringBuilder(); + for (var i = 0; i < fields.length; i++) { + var field = fields[i]; + var fieldRegistration = fieldRegistrations[i]; + pySerializer(fieldRegistration.serializer()).writeObject(pyBuilder, "packet." + field.getName(), 2, field, fieldRegistration); + } + return pyBuilder.toString(); + } + + private static String readObject(ProtocolRegistration registration) { + var fields = registration.getFields(); + var fieldRegistrations = registration.getFieldRegistrations(); + var pyBuilder = new StringBuilder(); + for (var i = 0; i < fields.length; i++) { + var field = fields[i]; + var fieldRegistration = fieldRegistrations[i]; + if (field.isAnnotationPresent(Compatible.class)) { + pyBuilder.append(TAB+ TAB).append("if !buffer.isReadable():").append(LS); + pyBuilder.append(TAB + TAB+ TAB).append("return packet").append(LS); + pyBuilder.append(TAB+ TAB).append("pass").append(LS); + } + var readObject = pySerializer(fieldRegistration.serializer()).readObject(pyBuilder, 2, field, fieldRegistration); + pyBuilder.append(TAB + TAB).append(StringUtils.format("packet.{} = {}", field.getName(), readObject)).append(LS); + } + return pyBuilder.toString(); + } + + public static StringBuilder addTab(StringBuilder builder, int deep) { + builder.append(TAB_ASCII.repeat(Math.max(0, deep))); + return builder; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/python/IPySerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/python/IPySerializer.java new file mode 100644 index 00000000..8db2caf1 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/python/IPySerializer.java @@ -0,0 +1,32 @@ +/* + * 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.python; + +import com.zfoo.protocol.registration.field.IFieldRegistration; + +import java.lang.reflect.Field; + +/** + * @author godotg + * @version 3.0 + */ +public interface IPySerializer { + + 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/python/PyArraySerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyArraySerializer.java new file mode 100644 index 00000000..7b27ba6a --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyArraySerializer.java @@ -0,0 +1,92 @@ +/* + * 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.python; + +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 + * @version 3.0 + */ +public class PyArraySerializer implements IPySerializer { + @Override + public String fieldDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return "[]"; + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GeneratePyUtils.addTab(builder, deep); + if (CutDownArraySerializer.getInstance().writeObject(builder, objectStr, field, fieldRegistration, CodeLanguage.GdScript)) { + return; + } + + ArrayField arrayField = (ArrayField) fieldRegistration; + + builder.append(StringUtils.format("if ({} == null):", objectStr)).append(LS); + GeneratePyUtils.addTab(builder, deep + 1); + builder.append("buffer.writeInt(0)").append(LS); + GeneratePyUtils.addTab(builder, deep); + + builder.append("else:").append(LS); + GeneratePyUtils.addTab(builder, deep + 1); + builder.append(StringUtils.format("buffer.writeInt({}.size())", objectStr)).append(LS); + + String element = "element" + GenerateProtocolFile.index.getAndIncrement(); + GeneratePyUtils.addTab(builder, deep + 1); + builder.append(StringUtils.format("for {} in {}:", element, objectStr)).append(LS); + GeneratePyUtils.pySerializer(arrayField.getArrayElementRegistration().serializer()) + .writeObject(builder, element, deep + 2, field, arrayField.getArrayElementRegistration()); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + GeneratePyUtils.addTab(builder, deep); + var cutDown = CutDownArraySerializer.getInstance().readObject(builder, field, fieldRegistration, CodeLanguage.GdScript); + if (cutDown != null) { + return cutDown; + } + + ArrayField arrayField = (ArrayField) fieldRegistration; + String result = "result" + GenerateProtocolFile.index.getAndIncrement(); + + builder.append(StringUtils.format("{} = []", result)).append(LS); + + String i = "index" + GenerateProtocolFile.index.getAndIncrement(); + String size = "size" + GenerateProtocolFile.index.getAndIncrement(); + + GeneratePyUtils.addTab(builder, deep); + builder.append(StringUtils.format("{} = buffer.readInt()", size)).append(LS); + + GeneratePyUtils.addTab(builder, deep); + builder.append(StringUtils.format("if ({} > 0):", size)).append(LS); + GeneratePyUtils.addTab(builder, deep + 1); + builder.append(StringUtils.format("for {} in range({}):", i, size)).append(LS); + String readObject = GeneratePyUtils.pySerializer(arrayField.getArrayElementRegistration().serializer()) + .readObject(builder, deep + 2, field, arrayField.getArrayElementRegistration()); + GeneratePyUtils.addTab(builder, deep + 2); + builder.append(StringUtils.format("{}.append({})", result, readObject)).append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyBooleanSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyBooleanSerializer.java new file mode 100644 index 00000000..7aac0b3a --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyBooleanSerializer.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.python; + +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 + * @version 3.0 + */ +public class PyBooleanSerializer implements IPySerializer { + @Override + public String fieldDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return "False"; + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GeneratePyUtils.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.index.getAndIncrement(); + + GeneratePyUtils.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/python/PyByteSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyByteSerializer.java new file mode 100644 index 00000000..62a5e043 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyByteSerializer.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.python; + +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 + * @version 3.0 + */ +public class PyByteSerializer implements IPySerializer { + @Override + public String fieldDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return "0"; + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GeneratePyUtils.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.index.getAndIncrement(); + + GeneratePyUtils.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/python/PyCharSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyCharSerializer.java new file mode 100644 index 00000000..b152b749 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyCharSerializer.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.python; + +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 + * @version 3.0 + */ +public class PyCharSerializer implements IPySerializer { + @Override + public String fieldDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return StringUtils.EMPTY; + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GeneratePyUtils.addTab(builder, deep); + builder.append(StringUtils.format("buffer.writeChar({})", objectStr)).append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + String result = "result" + GenerateProtocolFile.index.getAndIncrement(); + GeneratePyUtils.addTab(builder, deep); + builder.append(StringUtils.format("{} = buffer.readChar()", result)).append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyDoubleSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyDoubleSerializer.java new file mode 100644 index 00000000..ece68a52 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyDoubleSerializer.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.python; + +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 + * @version 3.0 + */ +public class PyDoubleSerializer implements IPySerializer { + @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) { + GeneratePyUtils.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.index.getAndIncrement(); + + GeneratePyUtils.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/python/PyFloatSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyFloatSerializer.java new file mode 100644 index 00000000..1e29b461 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyFloatSerializer.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.python; + +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 + * @version 3.0 + */ +public class PyFloatSerializer implements IPySerializer { + @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) { + GeneratePyUtils.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.index.getAndIncrement(); + + GeneratePyUtils.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/python/PyIntSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyIntSerializer.java new file mode 100644 index 00000000..2d444c32 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyIntSerializer.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.python; + +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 + * @version 3.0 + */ +public class PyIntSerializer implements IPySerializer { + @Override + public String fieldDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return "0"; + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GeneratePyUtils.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.index.getAndIncrement(); + + GeneratePyUtils.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/python/PyListSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyListSerializer.java new file mode 100644 index 00000000..85542fb5 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyListSerializer.java @@ -0,0 +1,92 @@ +/* + * 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.python; + +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 + * @version 3.0 + */ +public class PyListSerializer implements IPySerializer { + @Override + public String fieldDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return "[]"; + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GeneratePyUtils.addTab(builder, deep); + if (CutDownListSerializer.getInstance().writeObject(builder, objectStr, field, fieldRegistration, CodeLanguage.GdScript)) { + return; + } + + ListField listField = (ListField) fieldRegistration; + + builder.append(StringUtils.format("if ({} == null):", objectStr)).append(LS); + GeneratePyUtils.addTab(builder, deep + 1); + builder.append("buffer.writeInt(0)").append(LS); + GeneratePyUtils.addTab(builder, deep); + + builder.append("else:").append(LS); + GeneratePyUtils.addTab(builder, deep + 1); + builder.append(StringUtils.format("buffer.writeInt({}.size())", objectStr)).append(LS); + + String element = "element" + GenerateProtocolFile.index.getAndIncrement(); + GeneratePyUtils.addTab(builder, deep + 1); + builder.append(StringUtils.format("for {} in {}:", element, objectStr)).append(LS); + GeneratePyUtils.pySerializer(listField.getListElementRegistration().serializer()) + .writeObject(builder, element, deep + 2, field, listField.getListElementRegistration()); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + GeneratePyUtils.addTab(builder, deep); + var cutDown = CutDownListSerializer.getInstance().readObject(builder, field, fieldRegistration, CodeLanguage.GdScript); + if (cutDown != null) { + return cutDown; + } + + ListField listField = (ListField) fieldRegistration; + String result = "result" + GenerateProtocolFile.index.getAndIncrement(); + + builder.append(StringUtils.format("{} = []", result)).append(LS); + + String i = "index" + GenerateProtocolFile.index.getAndIncrement(); + String size = "size" + GenerateProtocolFile.index.getAndIncrement(); + + GeneratePyUtils.addTab(builder, deep); + builder.append(StringUtils.format("{} = buffer.readInt()", size)).append(LS); + + GeneratePyUtils.addTab(builder, deep); + builder.append(StringUtils.format("if ({} > 0):", size)).append(LS); + GeneratePyUtils.addTab(builder, deep + 1); + builder.append(StringUtils.format("for {} in range({}):", i, size)).append(LS); + String readObject = GeneratePyUtils.pySerializer(listField.getListElementRegistration().serializer()) + .readObject(builder, deep + 2, field, listField.getListElementRegistration()); + GeneratePyUtils.addTab(builder, deep + 2); + builder.append(StringUtils.format("{}.append({})", result, readObject)).append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyLongSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyLongSerializer.java new file mode 100644 index 00000000..4815cd06 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyLongSerializer.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.python; + +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 + * @version 3.0 + */ +public class PyLongSerializer implements IPySerializer { + @Override + public String fieldDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return "0"; + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GeneratePyUtils.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.index.getAndIncrement(); + + GeneratePyUtils.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/python/PyMapSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyMapSerializer.java new file mode 100644 index 00000000..49e2f183 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyMapSerializer.java @@ -0,0 +1,104 @@ +/* + * 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.python; + +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 + * @version 3.0 + */ +public class PyMapSerializer implements IPySerializer { + @Override + public String fieldDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return "{}"; + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GeneratePyUtils.addTab(builder, deep); + if (CutDownMapSerializer.getInstance().writeObject(builder, objectStr, field, fieldRegistration, CodeLanguage.GdScript)) { + return; + } + + MapField mapField = (MapField) fieldRegistration; + builder.append(StringUtils.format("if ({} == null):", objectStr)).append(LS); + GeneratePyUtils.addTab(builder, deep + 1); + builder.append("buffer.writeInt(0)").append(LS); + + GeneratePyUtils.addTab(builder, deep); + builder.append("else:").append(LS); + + GeneratePyUtils.addTab(builder, deep + 1); + builder.append(StringUtils.format("buffer.writeInt({}.size())", objectStr)).append(LS); + + String key = "key" + GenerateProtocolFile.index.getAndIncrement(); + String value = "value" + GenerateProtocolFile.index.getAndIncrement(); + + GeneratePyUtils.addTab(builder, deep + 1); + builder.append(StringUtils.format("for {} in {}:", key, objectStr)).append(LS); + GeneratePyUtils.addTab(builder, deep + 2); + builder.append(StringUtils.format("{} = {}[{}]", value, objectStr, key)).append(LS); + GeneratePyUtils.pySerializer(mapField.getMapKeyRegistration().serializer()) + .writeObject(builder, key, deep + 2, field, mapField.getMapKeyRegistration()); + GeneratePyUtils.pySerializer(mapField.getMapValueRegistration().serializer()) + .writeObject(builder, value, deep + 2, field, mapField.getMapValueRegistration()); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + GeneratePyUtils.addTab(builder, deep); + var cutDown = CutDownMapSerializer.getInstance().readObject(builder, field, fieldRegistration, CodeLanguage.GdScript); + if (cutDown != null) { + return cutDown; + } + + MapField mapField = (MapField) fieldRegistration; + String result = "result" + GenerateProtocolFile.index.getAndIncrement(); + + builder.append(StringUtils.format("{} = {}", result)).append(LS); + + GeneratePyUtils.addTab(builder, deep); + String size = "size" + GenerateProtocolFile.index.getAndIncrement(); + builder.append(StringUtils.format("{} = buffer.readInt()", size)).append(LS); + + GeneratePyUtils.addTab(builder, deep); + builder.append(StringUtils.format("if ({} > 0):", size)).append(LS); + + String i = "index" + GenerateProtocolFile.index.getAndIncrement(); + GeneratePyUtils.addTab(builder, deep + 1); + builder.append(StringUtils.format("for {} in range({}):", i, size)).append(LS); + + String keyObject = GeneratePyUtils.pySerializer(mapField.getMapKeyRegistration().serializer()) + .readObject(builder, deep + 2, field, mapField.getMapKeyRegistration()); + + + String valueObject = GeneratePyUtils.pySerializer(mapField.getMapValueRegistration().serializer()) + .readObject(builder, deep + 2, field, mapField.getMapValueRegistration()); + GeneratePyUtils.addTab(builder, deep + 2); + + builder.append(StringUtils.format("{}[{}] = {}", result, keyObject, valueObject)).append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyObjectProtocolSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyObjectProtocolSerializer.java new file mode 100644 index 00000000..d3812a8d --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyObjectProtocolSerializer.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.python; + +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 + * @version 3.0 + */ +public class PyObjectProtocolSerializer implements IPySerializer { + @Override + public String fieldDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return "None"; + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + ObjectProtocolField objectProtocolField = (ObjectProtocolField) fieldRegistration; + GeneratePyUtils.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.index.getAndIncrement(); + GeneratePyUtils.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/python/PySetSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PySetSerializer.java new file mode 100644 index 00000000..ad4103dc --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PySetSerializer.java @@ -0,0 +1,92 @@ +/* + * 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.python; + +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 + * @version 3.0 + */ +public class PySetSerializer implements IPySerializer { + @Override + public String fieldDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return "{}"; + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GeneratePyUtils.addTab(builder, deep); + if (CutDownSetSerializer.getInstance().writeObject(builder, objectStr, field, fieldRegistration, CodeLanguage.GdScript)) { + return; + } + + SetField setField = (SetField) fieldRegistration; + + builder.append(StringUtils.format("if ({} == null):", objectStr)).append(LS); + GeneratePyUtils.addTab(builder, deep + 1); + builder.append("buffer.writeInt(0)").append(LS); + GeneratePyUtils.addTab(builder, deep); + + builder.append("else:").append(LS); + GeneratePyUtils.addTab(builder, deep + 1); + builder.append(StringUtils.format("buffer.writeInt({}.size())", objectStr)).append(LS); + + String element = "element" + GenerateProtocolFile.index.getAndIncrement(); + GeneratePyUtils.addTab(builder, deep + 1); + builder.append(StringUtils.format("for {} in {}:", element, objectStr)).append(LS); + GeneratePyUtils.pySerializer(setField.getSetElementRegistration().serializer()) + .writeObject(builder, element, deep + 2, field, setField.getSetElementRegistration()); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + GeneratePyUtils.addTab(builder, deep); + var cutDown = CutDownSetSerializer.getInstance().readObject(builder, field, fieldRegistration, CodeLanguage.GdScript); + if (cutDown != null) { + return cutDown; + } + + SetField setField = (SetField) fieldRegistration; + String result = "result" + GenerateProtocolFile.index.getAndIncrement(); + + builder.append(StringUtils.format("{} = []", result)).append(LS); + + String i = "index" + GenerateProtocolFile.index.getAndIncrement(); + String size = "size" + GenerateProtocolFile.index.getAndIncrement(); + + GeneratePyUtils.addTab(builder, deep); + builder.append(StringUtils.format("{} = buffer.readInt()", size)).append(LS); + + GeneratePyUtils.addTab(builder, deep); + builder.append(StringUtils.format("if ({} > 0):", size)).append(LS); + GeneratePyUtils.addTab(builder, deep + 1); + builder.append(StringUtils.format("for {} in range({}):", i, size)).append(LS); + String readObject = GeneratePyUtils.pySerializer(setField.getSetElementRegistration().serializer()) + .readObject(builder, deep + 2, field, setField.getSetElementRegistration()); + GeneratePyUtils.addTab(builder, deep + 2); + builder.append(StringUtils.format("{}.append({})", result, readObject)).append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyShortSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyShortSerializer.java new file mode 100644 index 00000000..030d1cb7 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyShortSerializer.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.python; + +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 + * @version 3.0 + */ +public class PyShortSerializer implements IPySerializer { + @Override + public String fieldDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return "0"; + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GeneratePyUtils.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.index.getAndIncrement(); + + GeneratePyUtils.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/python/PyStringSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyStringSerializer.java new file mode 100644 index 00000000..cfe89dcc --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/python/PyStringSerializer.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.python; + +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 + * @version 3.0 + */ +public class PyStringSerializer implements IPySerializer { + @Override + public String fieldDefaultValue(Field field, IFieldRegistration fieldRegistration) { + return StringUtils.EMPTY; + } + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GeneratePyUtils.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.index.getAndIncrement(); + GeneratePyUtils.addTab(builder, deep); + builder.append(StringUtils.format("{} = buffer.readString()", result)).append(LS); + return result; + } +} diff --git a/protocol/src/main/resources/python/ProtocolTemplate.py b/protocol/src/main/resources/python/ProtocolTemplate.py new file mode 100644 index 00000000..81281b81 --- /dev/null +++ b/protocol/src/main/resources/python/ProtocolTemplate.py @@ -0,0 +1,18 @@ +{} +class {}(): + + {} + + def protocolId(self): + return {} + + @classmethod + def write(cls, buffer, packet): + if (buffer.writePacketFlag(packet)): + return + {} + + @classmethod + def read(cls, buffer): + {} + pass \ No newline at end of file diff --git a/protocol/src/main/resources/python/byte_buffer.py b/protocol/src/main/resources/python/byte_buffer.py new file mode 100644 index 00000000..0227bcdd --- /dev/null +++ b/protocol/src/main/resources/python/byte_buffer.py @@ -0,0 +1,303 @@ +import struct + +maxSize = 655537 +maxInt = 2147483647 +minInt = -2147483648 +maxLong = 9223372036854775807 +minLong = -9223372036854775808 +empty_str = "" + + +class ByteBuffer(): + writeOffset = 0 + readOffset = 0 + buffer = bytearray(8) + + def setWriteOffset(self, writeOffset): + if writeOffset > len(self.buffer): + raise ValueError("index out of bounds exception:readerIndex:" + str(self.readOffset) + + ", writerIndex:" + str(self.writeOffset) + + "(expected:0 <= readerIndex <= writerIndex <= capacity:" + str(len(self.buffer))) + self.writeOffset = writeOffset + + def setReadOffset(self, readOffset): + if readOffset > self.writeOffset: + raise ValueError("index out of bounds exception:readerIndex:" + str(self.readOffset) + + ", writerIndex:" + str(self.writeOffset) + + "(expected:0 <= readerIndex <= writerIndex <= capacity:" + str(len(self.buffer))) + self.readOffset = readOffset + + def isReadable(self): + return self.writeOffset > self.readOffset + pass + + def getCapacity(self): + return len(self.buffer) - self.writeOffset + + def ensureCapacity(self, minCapacity): + while (minCapacity - self.getCapacity() > 0): + newSize = len(self.buffer) * 2 + if newSize > maxSize: + raise ValueError("out of memory error") + # auto grow capacity + self.buffer.extend(bytearray(len(self.buffer))) + + def writeBool(self, value): + if value: + self.writeByte(1) + else: + self.writeByte(0) + + def readBool(self): + if self.readByte(): + return True + else: + return False + + def writeByte(self, value): + self.ensureCapacity(1) + struct.pack_into('>b', self.buffer, self.writeOffset, value) + self.writeOffset += 1 + + def readByte(self): + value = struct.unpack_from('>b', self.buffer, self.readOffset)[0] + self.readOffset += 1 + return value + + def writeUByte(self, value): + self.ensureCapacity(1) + struct.pack_into('>B', self.buffer, self.writeOffset, value) + self.writeOffset += 1 + + def readUByte(self): + value = struct.unpack_from('>B', self.buffer, self.readOffset)[0] + self.readOffset += 1 + return value + + def writeShort(self, value): + self.ensureCapacity(1) + struct.pack_into('>h', self.buffer, self.writeOffset, value) + self.writeOffset += 2 + + def readShort(self): + value = struct.unpack_from('>h', self.buffer, self.readOffset)[0] + self.readOffset += 2 + return value + + def writeRawInt(self, value): + self.ensureCapacity(4) + struct.pack_into('>i', self.buffer, self.writeOffset, value) + self.writeOffset += 4 + + def readRawInt(self): + value = struct.unpack_from('>i', self.buffer, self.readOffset)[0] + self.readOffset += 4 + return value + + def writeInt(self, value): + if not (minInt <= value <= maxInt): + raise ValueError('value must range between minInt:-2147483648 and maxInt:2147483647') + value = (value << 1) ^ (value >> 31) + self.ensureCapacity(5) + if value >> 7 == 0: + self.writeUByte(value) + return + + if value >> 14 == 0: + self.writeUByte(value & 0x7F | 0x80) + self.writeUByte((value >> 7) & 0x7F) + return + + if value >> 21 == 0: + self.writeUByte((value & 0x7F) | 0x80) + self.writeUByte(((value >> 7) & 0x7F | 0x80)) + self.writeUByte((value >> 14) & 0x7F) + return + + if value >> 28 == 0: + self.writeUByte(value & 0x7F | 0x80) + self.writeUByte(((value >> 7) & 0x7F | 0x80)) + self.writeUByte(((value >> 14) & 0x7F | 0x80)) + self.writeUByte((value >> 21) & 0x7F) + return + + self.writeUByte(value & 0x7F | 0x80) + self.writeUByte(((value >> 7) & 0x7F | 0x80)) + self.writeUByte(((value >> 14) & 0x7F | 0x80)) + self.writeUByte(((value >> 21) & 0x7F | 0x80)) + self.writeUByte((value >> 28) & 0x7F) + pass + + def readInt(self): + b = self.readUByte() + value = b & 0x7F + if (b & 0x80) != 0: + b = self.readUByte() + value |= (b & 0x7F) << 7 + if (b & 0x80) != 0: + b = self.readUByte() + value |= (b & 0x7F) << 14 + if (b & 0x80) != 0: + b = self.readUByte() + value |= (b & 0x7F) << 21 + if (b & 0x80) != 0: + b = self.readUByte() + value |= (b & 0x7F) << 28 + return (value >> 1) ^ -(value & 1) + + def writeLong(self, value): + if not (minLong <= value <= maxLong): + raise ValueError('value must range between minLong:-9223372036854775808 and maxLong:9223372036854775807') + value = (value << 1) ^ (value >> 63) + self.ensureCapacity(9) + if value >> 7 == 0: + self.writeUByte(value) + return + + if value >> 14 == 0: + self.writeUByte(value & 0x7F | 0x80) + self.writeUByte((value >> 7) & 0x7F) + return + + if value >> 21 == 0: + self.writeUByte((value & 0x7F) | 0x80) + self.writeUByte(((value >> 7) & 0x7F | 0x80)) + self.writeUByte((value >> 14) & 0x7F) + return + + if value >> 28 == 0: + self.writeUByte(value & 0x7F | 0x80) + self.writeUByte(((value >> 7) & 0x7F | 0x80)) + self.writeUByte(((value >> 14) & 0x7F | 0x80)) + self.writeUByte((value >> 21) & 0x7F) + return + if value >> 35 == 0: + self.writeUByte(value & 0x7F | 0x80) + self.writeUByte(((value >> 7) & 0x7F | 0x80)) + self.writeUByte(((value >> 14) & 0x7F | 0x80)) + self.writeUByte(((value >> 21) & 0x7F | 0x80)) + self.writeUByte((value >> 28) & 0x7F) + return + if value >> 42 == 0: + self.writeUByte(value & 0x7F | 0x80) + self.writeUByte(((value >> 7) & 0x7F | 0x80)) + self.writeUByte(((value >> 14) & 0x7F | 0x80)) + self.writeUByte(((value >> 21) & 0x7F | 0x80)) + self.writeUByte(((value >> 28) & 0x7F | 0x80)) + self.writeUByte((value >> 35) & 0x7F) + return + if value >> 49 == 0: + self.writeUByte(value & 0x7F | 0x80) + self.writeUByte(((value >> 7) & 0x7F | 0x80)) + self.writeUByte(((value >> 14) & 0x7F | 0x80)) + self.writeUByte(((value >> 21) & 0x7F | 0x80)) + self.writeUByte(((value >> 28) & 0x7F | 0x80)) + self.writeUByte(((value >> 35) & 0x7F | 0x80)) + self.writeUByte((value >> 42) & 0x7F) + return + if value >> 56 == 0: + self.writeUByte(value & 0x7F | 0x80) + self.writeUByte(((value >> 7) & 0x7F | 0x80)) + self.writeUByte(((value >> 14) & 0x7F | 0x80)) + self.writeUByte(((value >> 21) & 0x7F | 0x80)) + self.writeUByte(((value >> 28) & 0x7F | 0x80)) + self.writeUByte(((value >> 35) & 0x7F | 0x80)) + self.writeUByte(((value >> 42) & 0x7F | 0x80)) + self.writeUByte((value >> 49) & 0x7F) + return + self.writeUByte(value & 0x7F | 0x80) + self.writeUByte(((value >> 7) & 0x7F | 0x80)) + self.writeUByte(((value >> 14) & 0x7F | 0x80)) + self.writeUByte(((value >> 21) & 0x7F | 0x80)) + self.writeUByte(((value >> 28) & 0x7F | 0x80)) + self.writeUByte(((value >> 35) & 0x7F | 0x80)) + self.writeUByte(((value >> 42) & 0x7F | 0x80)) + self.writeUByte(((value >> 49) & 0x7F | 0x80)) + self.writeUByte(value >> 56) + pass + + def readLong(self): + b = self.readUByte() + value = b & 0x7F + if (b & 0x80) != 0: + b = self.readUByte() + value |= (b & 0x7F) << 7 + if (b & 0x80) != 0: + b = self.readUByte() + value |= (b & 0x7F) << 14 + if (b & 0x80) != 0: + b = self.readUByte() + value |= (b & 0x7F) << 21 + if (b & 0x80) != 0: + b = self.readUByte() + value |= (b & 0x7F) << 28 + if (b & 0x80) != 0: + b = self.readUByte() + value |= (b & 0x7F) << 35 + if (b & 0x80) != 0: + b = self.readUByte() + value |= (b & 0x7F) << 42 + if (b & 0x80) != 0: + b = self.readUByte() + value |= (b & 0x7F) << 49 + if (b & 0x80) != 0: + b = self.readUByte() + value |= b << 56 + return (value >> 1) ^ -(value & 1) + + def writeFloat(self, value): + self.ensureCapacity(4) + struct.pack_into('>f', self.buffer, self.writeOffset, value) + self.writeOffset += 4 + + def readFloat(self): + value = struct.unpack_from('>f', self.buffer, self.readOffset)[0] + self.readOffset += 4 + return value + + def writeDouble(self, value): + self.ensureCapacity(8) + struct.pack_into('>d', self.buffer, self.writeOffset, value) + self.writeOffset += 8 + + def readDouble(self): + value = struct.unpack_from('>d', self.buffer, self.readOffset)[0] + self.readOffset += 8 + return value + + def writeChar(self, value): + if len(value) == 0: + self.writeInt(0) + return + self.writeString(value[0]) + + def readChar(self): + return self.readString() + + def writeString(self, value): + if len(value) == 0: + self.writeInt(0) + return + byte_array = bytearray(value, 'utf-8') + length = len(byte_array) + self.ensureCapacity(5 + length) + self.writeInt(length) + self.buffer[self.writeOffset:self.writeOffset + length] = byte_array[:] + self.writeOffset += length + + def readString(self): + length = self.readInt() + if (length <= 0): + return empty_str + byte_array = self.buffer[self.readOffset:self.readOffset + length] + # 使用utf-8编码进行解码 + value = byte_array.decode('utf-8') + self.readOffset += length + return value + + def writePacketFlag(self, value): + if value is None: + self.writeBool(False) + else: + self.writeBool(True) + pass \ No newline at end of file diff --git a/protocol/src/test/java/com/zfoo/protocol/SpeedTest.java b/protocol/src/test/java/com/zfoo/protocol/SpeedTest.java index e820ec97..26dc59d5 100644 --- a/protocol/src/test/java/com/zfoo/protocol/SpeedTest.java +++ b/protocol/src/test/java/com/zfoo/protocol/SpeedTest.java @@ -23,6 +23,7 @@ import com.google.protobuf.CodedOutputStream; import com.zfoo.protocol.collection.ArrayUtils; import com.zfoo.protocol.generate.GenerateOperation; import com.zfoo.protocol.packet.*; +import com.zfoo.protocol.serializer.CodeLanguage; import com.zfoo.protocol.util.StringUtils; import io.fury.Fury; import io.fury.Language; @@ -375,6 +376,7 @@ public class SpeedTest { // op.getGenerateLanguages().add(CodeLanguage.Lua); // op.getGenerateLanguages().add(CodeLanguage.CSharp); // op.getGenerateLanguages().add(CodeLanguage.GdScript); + op.getGenerateLanguages().add(CodeLanguage.Python); // 需要protocol协议的字段里面都加上JProtobuf注解才能用 // op.setProtocolParam("protobuf=protobuf.xml");