├── .gitignore ├── LICENSE ├── Make.sh ├── MakeProtobufBinaries.sh ├── README.md ├── api ├── csharp │ └── ProtoPlus │ │ ├── FastBitConverter.cs │ │ ├── InputStream.cs │ │ ├── MessageMeta.cs │ │ ├── OutputStream.cs │ │ ├── ProtoPlus.csproj │ │ ├── ProtoStruct.cs │ │ ├── SizeCaculator.cs │ │ └── WireType.cs └── golang │ ├── api.go │ ├── text_marshaler.go │ ├── text_marshaler_test.go │ ├── text_parser.go │ ├── text_writer.go │ └── wire │ ├── buffer.go │ ├── err.go │ ├── field_marshal.go │ ├── field_size.go │ ├── field_unmarshal.go │ ├── slice_marshal.go │ ├── slice_size.go │ ├── slice_unmarshal.go │ ├── struct.go │ ├── variant.go │ └── wiretype.go ├── build └── build.go ├── cmd └── protoplus │ └── main.go ├── codegen ├── codegen.go ├── funcmap.go ├── helper_cs.go ├── helper_go.go └── msgid.go ├── csharp └── Example │ └── ProtoGen.cs ├── example └── csharp │ ├── Example.sln │ └── Example │ ├── Example.csproj │ ├── ProtoGen.cs │ ├── ProtoGenReg.cs │ └── Test.cs ├── gen ├── gen.go ├── pbscheme │ ├── func.go │ ├── gen_dir.go │ └── gen_proto.go ├── ppcpp │ ├── func.go │ ├── gen_cpp.go │ └── text.go ├── ppcs │ ├── func.go │ ├── gen_cs.go │ └── text.go ├── ppgo │ ├── func.go │ ├── gen_go.go │ └── text.go ├── ppscheme │ └── json.go └── route │ ├── msgdir.go │ └── route.go ├── go.mod ├── go.sum ├── model ├── comment.go ├── descriptor.go ├── descriptorset.go ├── field.go ├── pbdescset.go ├── route.go ├── service.go ├── tag.go └── type.go ├── parser ├── context.go ├── entry.go ├── enumfield.go ├── parse_descriptor.go ├── parse_descriptorset.go ├── parse_import.go ├── parse_tag.go ├── parse_test.go ├── parser.go └── structfield.go ├── tests ├── Make.sh ├── code_gen.go ├── code_test.go ├── filelist.proto ├── msg.proto ├── pb_gen.proto ├── route.json └── type.proto └── util └── flagwrapper.go /.gitignore: -------------------------------------------------------------------------------- 1 | example/csharp/.vs 2 | example/csharp/Example/bin 3 | example/csharp/Example/obj 4 | api/csharp/ProtoPlus/obj 5 | api/csharp/ProtoPlus/bin 6 | *.gz 7 | tests/reg_gen.go 8 | bin/windows 9 | bin/darwin 10 | bin/linux 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Davy xu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Make.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | Version=2.0.0 3 | 4 | 5 | Platform=$1 6 | 7 | 8 | if [[ "$Platform" == "" ]]; then 9 | Platform=$(go env GOHOSTOS) 10 | fi 11 | 12 | 13 | function ReportError() 14 | { 15 | if [ $? -ne 0 ] ; then read -rsp $'Errors occurred...\n' ; fi 16 | } 17 | 18 | trap ReportError EXIT 19 | set -e 20 | 21 | if [[ "$Platform" == "" ]]; then 22 | Platform=$(go env GOHOSTOS) 23 | fi 24 | 25 | #export GOARCH=amd64 26 | 27 | BuildSourcePackage="github.com/davyxu/protoplus/build" 28 | BinaryPackage="github.com/davyxu/protoplus/cmd/protoplus" 29 | BinaryName="protoplus" 30 | 31 | BuildBinary() 32 | { 33 | TargetDir=bin/"${1}" 34 | mkdir -p "${TargetDir}" 35 | export GOOS=${1} 36 | 37 | BuildTime=$(date -R) 38 | GitCommit=$(git rev-parse HEAD) 39 | VersionString="-X \"${BuildSourcePackage}.BuildTime=${BuildTime}\" -X \"${BuildSourcePackage}.Version=${Version}\" -X \"${BuildSourcePackage}.GitCommit=${GitCommit}\"" 40 | 41 | go build -p 4 -o "${TargetDir}"/${BinaryName} -ldflags "${VersionString}" ${BinaryPackage} 42 | echo "${TargetDir}"/${BinaryName} 43 | } 44 | 45 | 46 | BuildBinary "${Platform}" -------------------------------------------------------------------------------- /MakeProtobufBinaries.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | Platform=$1 4 | 5 | 6 | if [[ "$Platform" == "" ]]; then 7 | Platform=$(go env GOHOSTOS) 8 | fi 9 | 10 | 11 | function ReportError() 12 | { 13 | if [ $? -ne 0 ] ; then read -rsp $'Errors occurred...\n' ; fi 14 | } 15 | 16 | trap ReportError EXIT 17 | set -e 18 | 19 | BuildGoPlugin() 20 | { 21 | TargetDir=bin/"${1}" 22 | mkdir -p "${TargetDir}" 23 | export GOOS=${1} 24 | 25 | # Download & compile protoc-gen-go 26 | go get google.golang.org/protobuf/cmd/protoc-gen-go 27 | go build -o "${TargetDir}"/protoc-gen-go google.golang.org/protobuf/cmd/protoc-gen-go 28 | echo "${TargetDir}"/protoc-gen-go 29 | } 30 | 31 | 32 | 33 | 34 | DownloadProtoc() 35 | { 36 | #export http_proxy="http://127.0.0.1:7890" 37 | #export https_proxy="http://127.0.0.1:7890" 38 | 39 | wget https://github.com/protocolbuffers/protobuf/releases/download/v21.6/protoc-21.6-win64.zip 40 | } 41 | 42 | 43 | BuildGoPlugin "${Platform}" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # protoplus 2 | 适用于游戏开发的协议格式、代码生成器及相关开发API 3 | 4 | # Why ProtoPlus? 5 | Protobuf作为行业通用的协议格式已经存在多年,各种历史遗留问题及语言设计上的缺陷对游戏开发阻碍非常大。 6 | 7 | 为了提高协议编写效率,增加协议使用灵活度,急需一套强于Protobuf的工具集提高开发效率和使用便捷性,ProtoPlus应运而生! 8 | 9 | # 特性对比 10 | 11 | ___ | ProtoPlus | Protobuf 12 | ---|---|--- 13 | 生成字段Tag | 自动/手动 | 手动 14 | 生成枚举值 | 自动/手动 | 手动 15 | 注释扩展 | API简单 | API复杂 16 | 字段扩展 | 专属API支持 | 手动解析注释 17 | 结构扩展 | 专属API支持 | 手动解析注释 18 | 消息ID生成 | 自动/手动 | 不支持 19 | 路由表生成 | 支持 | 不支持 20 | 扩展方式 | 描述文件输出JSON | 复杂的插件格式,调试复杂 21 | 22 | 注: 23 | 24 | * ProtoPlus中的枚举值,不再需要为了兼容C++而必须加上前缀,保证全局枚举值唯一 25 | 26 | * ProtoPlus二进制编码格式与Protobuf一致,方便调试、分析、优化 27 | 28 | # 描述文件格式 29 | 30 | ``` 31 | 32 | enum Vocation { 33 | Monkey 34 | Monk 35 | Pig 36 | } 37 | 38 | struct PhoneNumber { 39 | 40 | number string 41 | 42 | type int32 43 | } 44 | 45 | 46 | struct Person { 47 | 48 | name string 49 | 50 | id int32 51 | 52 | email string 53 | 54 | phone PhoneNumber 55 | 56 | voc Vocation 57 | } 58 | 59 | struct AddressBook { 60 | 61 | person []Person 62 | } 63 | 64 | 65 | ``` 66 | 67 | 68 | 69 | # 协议类型及输出语言类型对应 70 | 71 | 描述 |ProtoPlus | Go | C# | Protobuf 72 | ---|---|---|---|--- 73 | 32位整形| int32 | int32 | int | int32 74 | 64位整形 | int64|int64 | long | int64 75 | 无符号32位整形| uint32|uint32 | uint | uint32 76 | 无符号64位整形| uint64|uint64 | ulong|uint64 77 | 字符串| string|string|string | string 78 | 单精度浮点数| float32|float32 | float | float 79 | 双精度浮点数|float64|float64| double | double 80 | 二进制数据 | bytes | []byte | byte[] |repeated byte 81 | 枚举| enum | int32类型常量封装| enum | enum 82 | 布尔| bool | bool| bool | bool 83 | 结构体| struct | struct| class | message 84 | 85 | 86 | # 编译 87 | 88 | ``` 89 | go get -u -v github.com/davyxu/protoplus/cmd/protoplus 90 | ``` 91 | 92 | # 功能 93 | 94 | ## 输出ProtoPlus编码消息序列化的Go源码 95 | 96 | 命令行示例: 97 | ```bash 98 | protoplus --ppgo_out=msg_gen.go --package=proto proto1.proto proto2.proto 99 | ``` 100 | 101 | 参数说明: 102 | * ppgo_out 103 | 104 | Go源码文件名 105 | 106 | * package 107 | 108 | 指定输出时的Go包名 109 | 110 | ## 输出消息绑定的Go源码 111 | 112 | 输出源码被引用时, 自动注册到cellnet的消息Registry中 113 | 114 | 命令行示例: 115 | ```bash 116 | protoplus --ppgoreg_out=msg_gen.go --package=proto proto1.proto proto2.proto 117 | ``` 118 | 119 | 参数说明: 120 | * ppgoreg_out 121 | 122 | Go源码文件名 123 | 124 | * package 125 | 126 | 指定输出时的Go包名 127 | 128 | * codec 129 | 生成消息注册的默认编码,如在消息中指定编码时,优先使用指定的编码 130 | 131 | 132 | ## 输出ProtoPlus编码的消息序列化C#源码 133 | 134 | 输出的C#源码, 需要配合[ProtoPlus C# SDK](https://github.com/davyxu/protoplus/tree/master/api/csharp/ProtoPlus) 使用 135 | 136 | 命令行示例: 137 | ```bash 138 | protoplus --ppcs_out=MsgGen.cs --package=Proto proto1.proto proto2.proto 139 | ``` 140 | 141 | 参数说明: 142 | * ppcs_out 143 | 144 | C#源码文件名 145 | 146 | * package 147 | 148 | 指定输出时的C#命名空间 149 | 150 | * classbase 151 | 152 | C#代码生成时,消息类默认基类名称, 默认基类为IProtoStruct 153 | 154 | 155 | ## 输出消息绑定的C#源码 156 | 157 | 输出的C#源码, 需要配合[ProtoPlus C# SDK](https://github.com/davyxu/protoplus/tree/master/api/csharp/ProtoPlus) 使用 158 | 159 | 命令行示例: 160 | ```bash 161 | protoplus --ppcsreg_out=MsgGen.cs --package=Proto proto1.proto proto2.proto 162 | ``` 163 | 164 | 参数说明: 165 | * ppcsreg_out 166 | 167 | C#源码文件名 168 | 169 | * package 170 | 171 | 指定输出时的C#命名空间 172 | 173 | 174 | ## 输出Protobuf协议描述文件 175 | 176 | 输出的Protobuf协议描述文件,可使用protoc编译器编译 177 | 178 | 命令行示例: 179 | ```bash 180 | protoplus --pbscheme_out=pb.proto --package=proto proto1.proto proto2.proto 181 | ``` 182 | 183 | 参数说明: 184 | * pbscheme_out 185 | 186 | 生成protobuf 3.0协议文件 187 | 188 | * package 189 | 190 | 指定输出时的Protobuf包名 191 | 192 | 193 | ## 输出ProtoPlus描述文件 194 | 195 | ProtoPlus协议描述文件可输出为JSON格式, 方便插件及工具链获取ProtoPlus的格式信息 196 | 197 | 命令行示例: 198 | ```bash 199 | protoplus --ppscheme_out=pp.json proto1.proto proto2.proto 200 | ``` 201 | 202 | 参数说明: 203 | * ppscheme_out 204 | 205 | JSON格式的ProtoPlus协议描述文件, 格式参见 [协议描述定义](https://github.com/davyxu/protoplus/tree/master/model/descriptorset.go) 206 | 207 | 也可将描述文件的JSON直接输出,示例如下: 208 | 209 | ```bash 210 | protoplus --ppscheme proto1.proto proto2.proto 211 | ``` 212 | ## 输出路由配置 213 | 214 | 在结构体上添加MsgDir字段,标记结构体作为消息时的消息流转方向, 格式范例: 215 | ```protoplus 216 | [MsgDir: "client -> game"] 217 | struct LoginREQ { 218 | } 219 | ``` 220 | 路由信息将输出为JSON格式: 221 | ```json 222 | { 223 | "Rule": [ 224 | { 225 | "MsgName": "proto.LoginREQ", 226 | "SvcName": "game" 227 | } 228 | ] 229 | } 230 | ``` 231 | ### MsgDir格式说明 232 | 233 | MsgDir的格式包含3个部分 234 | ``` 235 | MsgDir: From -> Mid -> To 236 | ``` 237 | 238 | * From 239 | 240 | 消息的发起方,路由一般忽略此部分信息 241 | 242 | * Mid 243 | 244 | 消息的中间处理, 一般为网关或者路由等 245 | 246 | * To 247 | 248 | 消息的目标送达点,消息处理最终方, 一般为某种消息服务, 路由表的SvcName字段读取该字段 249 | 250 | 命令行示例: 251 | ```bash 252 | protoplus --route_out=route.json --package=proto proto1.proto proto2.proto 253 | ``` 254 | 255 | 参数说明: 256 | * route_out 257 | 258 | JSON格式的ProtoPlus路由配置, 格式参见 [路由定义](https://github.com/davyxu/protoplus/tree/master/model/route.go) 259 | 260 | * package 261 | 262 | 指定输出时消息的包名 263 | 264 | 也可将路由信息的JSON直接输出,示例如下: 265 | 266 | ```bash 267 | protoplus --route --package=proto proto1.proto proto2.proto 268 | ``` 269 | 270 | # 备注 271 | 272 | 感觉不错请star, 谢谢! 273 | 274 | 提交bug及特性: https://github.com/davyxu/protoplus/issues 275 | -------------------------------------------------------------------------------- /api/csharp/ProtoPlus/FastBitConverter.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace ProtoPlus 4 | { 5 | public static class FastBitConverter 6 | { 7 | [StructLayout(LayoutKind.Explicit)] 8 | private struct ConverterHelperDouble 9 | { 10 | [FieldOffset(0)] 11 | public ulong Along; 12 | 13 | [FieldOffset(0)] 14 | public double Adouble; 15 | } 16 | 17 | [StructLayout(LayoutKind.Explicit)] 18 | private struct ConverterHelperFloat 19 | { 20 | [FieldOffset(0)] 21 | public int Aint; 22 | 23 | [FieldOffset(0)] 24 | public float Afloat; 25 | } 26 | 27 | private static void WriteLittleEndian(byte[] buffer, int offset, ulong data) 28 | { 29 | #if BIGENDIAN 30 | buffer[offset + 7] = (byte)(data); 31 | buffer[offset + 6] = (byte)(data >> 8); 32 | buffer[offset + 5] = (byte)(data >> 16); 33 | buffer[offset + 4] = (byte)(data >> 24); 34 | buffer[offset + 3] = (byte)(data >> 32); 35 | buffer[offset + 2] = (byte)(data >> 40); 36 | buffer[offset + 1] = (byte)(data >> 48); 37 | buffer[offset ] = (byte)(data >> 56); 38 | #else 39 | buffer[offset] = (byte)(data); 40 | buffer[offset + 1] = (byte)(data >> 8); 41 | buffer[offset + 2] = (byte)(data >> 16); 42 | buffer[offset + 3] = (byte)(data >> 24); 43 | buffer[offset + 4] = (byte)(data >> 32); 44 | buffer[offset + 5] = (byte)(data >> 40); 45 | buffer[offset + 6] = (byte)(data >> 48); 46 | buffer[offset + 7] = (byte)(data >> 56); 47 | #endif 48 | } 49 | 50 | private static void WriteLittleEndian(byte[] buffer, int offset, int data) 51 | { 52 | #if BIGENDIAN 53 | buffer[offset + 3] = (byte)(data); 54 | buffer[offset + 2] = (byte)(data >> 8); 55 | buffer[offset + 1] = (byte)(data >> 16); 56 | buffer[offset ] = (byte)(data >> 24); 57 | #else 58 | buffer[offset] = (byte)(data); 59 | buffer[offset + 1] = (byte)(data >> 8); 60 | buffer[offset + 2] = (byte)(data >> 16); 61 | buffer[offset + 3] = (byte)(data >> 24); 62 | #endif 63 | } 64 | 65 | public static void WriteLittleEndian(byte[] buffer, int offset, short data) 66 | { 67 | #if BIGENDIAN 68 | buffer[offset + 1] = (byte)(data); 69 | buffer[offset ] = (byte)(data >> 8); 70 | #else 71 | buffer[offset] = (byte)(data); 72 | buffer[offset + 1] = (byte)(data >> 8); 73 | #endif 74 | } 75 | 76 | public static void GetBytes(byte[] bytes, int startIndex, double value) 77 | { 78 | ConverterHelperDouble ch = new ConverterHelperDouble { Adouble = value }; 79 | WriteLittleEndian(bytes, startIndex, ch.Along); 80 | } 81 | 82 | public static void GetBytes(byte[] bytes, int startIndex, float value) 83 | { 84 | ConverterHelperFloat ch = new ConverterHelperFloat { Afloat = value }; 85 | WriteLittleEndian(bytes, startIndex, ch.Aint); 86 | } 87 | 88 | public static void GetBytes(byte[] bytes, int startIndex, short value) 89 | { 90 | WriteLittleEndian(bytes, startIndex, value); 91 | } 92 | 93 | public static void GetBytes(byte[] bytes, int startIndex, ushort value) 94 | { 95 | WriteLittleEndian(bytes, startIndex, (short)value); 96 | } 97 | 98 | public static void GetBytes(byte[] bytes, int startIndex, int value) 99 | { 100 | WriteLittleEndian(bytes, startIndex, value); 101 | } 102 | 103 | public static void GetBytes(byte[] bytes, int startIndex, uint value) 104 | { 105 | WriteLittleEndian(bytes, startIndex, (int)value); 106 | } 107 | 108 | public static void GetBytes(byte[] bytes, int startIndex, long value) 109 | { 110 | WriteLittleEndian(bytes, startIndex, (ulong)value); 111 | } 112 | 113 | public static void GetBytes(byte[] bytes, int startIndex, ulong value) 114 | { 115 | WriteLittleEndian(bytes, startIndex, value); 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /api/csharp/ProtoPlus/MessageMeta.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ProtoPlus 5 | { 6 | public class MetaInfo 7 | { 8 | public ushort ID; // 消息ID 9 | public Type Type; // 消息类型 10 | 11 | // 消息方向 12 | // 在proto中添加[MsgDir: "client -> game" ], 左边为源, 右边为目标 13 | public string SourcePeer; // 消息发起的源 14 | public string TargetPeer; // 消息的目标 15 | 16 | public string Name; 17 | } 18 | 19 | // 消息扩展信息集合 20 | public partial class MessageMeta 21 | { 22 | readonly Dictionary metaByID = new Dictionary(); 23 | readonly Dictionary metaByType = new Dictionary(); 24 | readonly Dictionary metaByName = new Dictionary(); 25 | 26 | static MessageMeta _ins; 27 | 28 | public static MessageMeta Instance 29 | { 30 | get 31 | { 32 | if (_ins == null) 33 | { 34 | _ins = new MessageMeta(); 35 | } 36 | 37 | return _ins; 38 | } 39 | } 40 | 41 | // 注册消息的扩展信息 42 | public void RegisterMeta(MetaInfo info) 43 | { 44 | if (info.ID != 0) 45 | { 46 | metaByID.Add(info.ID, info); 47 | } 48 | 49 | metaByType.Add(info.Type, info); 50 | metaByName.Add(info.Name, info); 51 | } 52 | 53 | // 通过ID取信息 54 | public MetaInfo GetMetaByID(ushort msgid) 55 | { 56 | if (metaByID.TryGetValue(msgid, out var value)) 57 | { 58 | return value; 59 | } 60 | 61 | return null; 62 | } 63 | 64 | public MetaInfo GetMetaByName(string msgName) 65 | { 66 | if (metaByName.TryGetValue(msgName, out var value)) 67 | { 68 | return value; 69 | } 70 | 71 | return null; 72 | } 73 | 74 | // 通过类型取信息 75 | public MetaInfo GetMetaByType(Type t) 76 | { 77 | if (metaByType.TryGetValue(t, out var value)) 78 | { 79 | return value; 80 | } 81 | 82 | return null; 83 | } 84 | 85 | // 用类型取消息ID 86 | public ushort GetMsgIDByType(Type t) 87 | { 88 | var meta = GetMetaByType(t); 89 | if (meta == null) 90 | return 0; 91 | 92 | return meta.ID; 93 | } 94 | 95 | public string GetMsgNameByType(Type t) 96 | { 97 | var meta = GetMetaByType(t); 98 | if (meta == null) 99 | return string.Empty; 100 | 101 | return meta.Type.FullName; 102 | } 103 | 104 | // 通过消息ID创建消息 105 | public IProtoStruct NewStruct(ushort msgid) 106 | { 107 | var meta = GetMetaByID(msgid); 108 | if (meta == null) 109 | return null; 110 | 111 | return NewStruct(meta.Type); 112 | } 113 | 114 | public IProtoStruct NewStruct(string msgName) 115 | { 116 | var meta = GetMetaByName(msgName); 117 | if (meta == null) 118 | return null; 119 | 120 | return NewStruct(meta.Type); 121 | } 122 | 123 | // 通过类型创建消息 124 | public static IProtoStruct NewStruct(Type t) 125 | { 126 | var s = Activator.CreateInstance(t) as IProtoStruct; 127 | if (s == null) 128 | { 129 | return null; 130 | } 131 | 132 | s.Init(); 133 | 134 | return s; 135 | } 136 | 137 | public static T NewStruct( ) where T: IProtoStruct 138 | { 139 | return (T)NewStruct(typeof(T)); 140 | } 141 | 142 | 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /api/csharp/ProtoPlus/OutputStream.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace ProtoPlus 6 | { 7 | public partial class OutputStream 8 | { 9 | int _pos; 10 | byte[] _buffer; 11 | int _len; 12 | bool _extend; 13 | 14 | public int Position => _pos; 15 | 16 | public int BufferLeft => _len - _pos; 17 | 18 | public OutputStream() 19 | { 20 | 21 | } 22 | 23 | public OutputStream(byte[] buffer ) 24 | { 25 | Init(buffer, 0, buffer.Length, false); 26 | } 27 | 28 | public void Init(byte[] buffer, int offset, int length, bool extend) 29 | { 30 | _pos = offset; 31 | _buffer = buffer; 32 | _len = length; 33 | _extend = extend; 34 | } 35 | 36 | public void SetPos(int pos) 37 | { 38 | _pos = pos; 39 | } 40 | 41 | void CheckBuffer(int requireSize) 42 | { 43 | if (_len - _pos < requireSize) 44 | { 45 | if (_extend) 46 | { 47 | var newdata = new byte[2 * _buffer.Length + requireSize]; 48 | WireFormat.CopyBytes(_buffer, newdata, 0, 0, _buffer.Length); 49 | _len = newdata.Length; 50 | _buffer = newdata; 51 | } 52 | else 53 | { 54 | throw new Exception("No enough buffer"); 55 | } 56 | } 57 | } 58 | 59 | void WriteTag(int fieldNumber, WireFormat.WireType type) 60 | { 61 | WriteVarint32(WireFormat.MakeTag(fieldNumber, type)); 62 | } 63 | 64 | #region Proto API 65 | 66 | public void WriteBytes(int fieldIndex, byte[] value) 67 | { 68 | if (value == null || value.Length == 0) 69 | { 70 | return; 71 | } 72 | 73 | WriteTag(fieldIndex, WireFormat.WireType.Bytes); 74 | 75 | WriteVarint32((uint)value.Length); 76 | WriteRawBytes(value, value.Length); 77 | } 78 | 79 | 80 | public void WriteBool(int fieldIndex, bool value) 81 | { 82 | if (!value) 83 | return; 84 | 85 | WriteTag(fieldIndex, WireFormat.WireType.Varint); 86 | WriteByte(1); 87 | } 88 | 89 | public void WriteBool(int fieldIndex, List value) 90 | { 91 | if (value == null || value.Count == 0) 92 | { 93 | return; 94 | } 95 | 96 | WriteTag(fieldIndex, WireFormat.WireType.Bytes); 97 | 98 | WriteVarint32((uint)value.Count); 99 | 100 | for (int i = 0; i < value.Count; i++) 101 | { 102 | WriteByte(value[i] ? (byte)1: (byte)0); 103 | } 104 | } 105 | 106 | public void WriteEnum(int fieldIndex, T value) where T: struct, IConvertible 107 | { 108 | var v = Convert.ToInt32(value); 109 | WriteInt32(fieldIndex, v); 110 | } 111 | 112 | public void WriteEnum(int fieldIndex, List value) where T : struct, IConvertible 113 | { 114 | if (value == null || value.Count == 0) 115 | { 116 | return; 117 | } 118 | 119 | WriteTag(fieldIndex, WireFormat.WireType.Bytes); 120 | 121 | int size = 0; 122 | for (int i = 0; i < value.Count; i++) 123 | { 124 | size += GetVarint32Size((uint)Convert.ToInt32(value[i])); 125 | } 126 | 127 | WriteVarint32((uint)size); 128 | for (int i = 0; i < value.Count; i++) 129 | { 130 | WriteVarint32((uint)Convert.ToInt32(value[i])); 131 | } 132 | } 133 | 134 | public void WriteInt32(int fieldIndex, int value) 135 | { 136 | if (value == 0) 137 | { 138 | return; 139 | } 140 | 141 | if (value > 0) 142 | { 143 | WriteTag(fieldIndex, WireFormat.WireType.Varint); 144 | WriteVarint32((uint)value); 145 | } 146 | else 147 | { 148 | WriteTag(fieldIndex, WireFormat.WireType.Fixed32); 149 | WriteFixed32((uint)value); 150 | } 151 | } 152 | 153 | public void WriteInt32(int fieldIndex, List value) 154 | { 155 | if (value == null || value.Count == 0) 156 | { 157 | return; 158 | } 159 | 160 | WriteTag(fieldIndex, WireFormat.WireType.Bytes); 161 | 162 | int size = 0; 163 | for (int i = 0; i < value.Count; i++) 164 | { 165 | size += GetVarint32Size((uint) value[i]); 166 | } 167 | 168 | WriteVarint32((uint) size); 169 | for (int i = 0; i < value.Count; i++) 170 | { 171 | WriteVarint32((uint)value[i]); 172 | } 173 | } 174 | 175 | public void WriteUInt32(int fieldIndex, uint value) 176 | { 177 | if (value == 0) 178 | { 179 | return; 180 | } 181 | 182 | WriteTag(fieldIndex, WireFormat.WireType.Varint); 183 | WriteVarint32(value); 184 | } 185 | 186 | public void WriteUInt32(int fieldIndex, List value) 187 | { 188 | if (value == null || value.Count == 0) 189 | { 190 | return; 191 | } 192 | 193 | WriteTag(fieldIndex, WireFormat.WireType.Bytes); 194 | 195 | int size = 0; 196 | for (int i = 0; i < value.Count; i++) 197 | { 198 | size += GetVarint32Size(value[i]); 199 | } 200 | 201 | WriteVarint32((uint)size); 202 | for (int i = 0; i < value.Count; i++) 203 | { 204 | WriteVarint32(value[i]); 205 | } 206 | } 207 | 208 | public void WriteInt64(int fieldIndex, long value) 209 | { 210 | if (value == 0) 211 | { 212 | return; 213 | } 214 | 215 | if (value > 0) 216 | { 217 | WriteTag(fieldIndex, WireFormat.WireType.Varint); 218 | WriteVarint64((ulong)value); 219 | } 220 | else 221 | { 222 | WriteTag(fieldIndex, WireFormat.WireType.Fixed64); 223 | WriteFixed64((ulong)value); 224 | } 225 | } 226 | 227 | public void WriteInt64(int fieldIndex,List value) 228 | { 229 | if (value == null || value.Count == 0) 230 | { 231 | return; 232 | } 233 | 234 | WriteTag(fieldIndex, WireFormat.WireType.Bytes); 235 | 236 | int size = 0; 237 | for (int i = 0; i < value.Count; i++) 238 | { 239 | size += ComputeRawVarint64Size((ulong)value[i]); 240 | } 241 | 242 | WriteVarint32((uint)size); 243 | for (int i = 0; i < value.Count; i++) 244 | { 245 | WriteVarint64((ulong)value[i]); 246 | } 247 | } 248 | 249 | public void WriteUInt64(int fieldIndex, ulong value) 250 | { 251 | if (value == 0) 252 | { 253 | return; 254 | } 255 | 256 | WriteTag(fieldIndex, WireFormat.WireType.Varint); 257 | WriteVarint64(value); 258 | } 259 | 260 | public void WriteUInt64(int fieldIndex, List value) 261 | { 262 | if (value == null || value.Count == 0) 263 | { 264 | return; 265 | } 266 | 267 | WriteTag(fieldIndex, WireFormat.WireType.Bytes); 268 | 269 | int size = 0; 270 | for (int i = 0; i < value.Count; i++) 271 | { 272 | size += ComputeRawVarint64Size(value[i]); 273 | } 274 | 275 | WriteVarint32((uint)size); 276 | for (int i = 0; i < value.Count; i++) 277 | { 278 | WriteVarint64(value[i]); 279 | } 280 | } 281 | 282 | public void WriteFloat(int fieldIndex, float value) 283 | { 284 | if( value == 0F) 285 | { 286 | return; 287 | } 288 | 289 | WriteTag(fieldIndex, WireFormat.WireType.Fixed32); 290 | 291 | CheckBuffer(4); 292 | FastBitConverter.GetBytes(_buffer, _pos, value); 293 | _pos += 4; ; 294 | } 295 | 296 | public void WriteFloat(int fieldIndex, List value) 297 | { 298 | if (value == null || value.Count == 0) 299 | { 300 | return; 301 | } 302 | 303 | WriteTag(fieldIndex, WireFormat.WireType.Bytes); 304 | WriteVarint32((uint)value.Count * 4); 305 | 306 | CheckBuffer(value.Count * 4); 307 | 308 | 309 | for (int i = 0; i < value.Count; i++) 310 | { 311 | FastBitConverter.GetBytes(_buffer, _pos, value[i]); 312 | _pos += 4; 313 | } 314 | } 315 | 316 | public void WriteDouble(int fieldIndex, double value) 317 | { 318 | if (value == 0D) 319 | { 320 | return; 321 | } 322 | 323 | WriteTag(fieldIndex, WireFormat.WireType.Fixed64); 324 | 325 | CheckBuffer(8); 326 | FastBitConverter.GetBytes(_buffer, _pos, value); 327 | _pos += 8; 328 | } 329 | 330 | 331 | public void WriteDouble(int fieldIndex, List value) 332 | { 333 | if (value == null || value.Count == 0) 334 | { 335 | return; 336 | } 337 | 338 | WriteTag(fieldIndex, WireFormat.WireType.Bytes); 339 | WriteVarint32((uint)value.Count * 8); 340 | 341 | CheckBuffer(value.Count * 8); 342 | 343 | 344 | for (int i = 0; i < value.Count; i++) 345 | { 346 | FastBitConverter.GetBytes(_buffer, _pos, value[i]); 347 | _pos += 8; 348 | } 349 | } 350 | 351 | public void WriteString(int fieldIndex, string value) 352 | { 353 | if (String.IsNullOrEmpty(value)) 354 | { 355 | return; 356 | } 357 | 358 | 359 | WriteTag(fieldIndex, WireFormat.WireType.Bytes); 360 | 361 | WriteStringBytes(value); 362 | } 363 | 364 | void WriteStringBytes(string value ) 365 | { 366 | int strLen = Encoding.UTF8.GetByteCount(value); 367 | 368 | WriteVarint32((uint)strLen); 369 | 370 | CheckBuffer(strLen); 371 | 372 | // 全ASCII 373 | if (strLen == value.Length) 374 | { 375 | for (int i = 0; i < strLen; i++) 376 | { 377 | _buffer[_pos + i] = (byte)value[i]; 378 | } 379 | } 380 | else 381 | { 382 | Encoding.UTF8.GetBytes(value, 0, value.Length, _buffer, _pos); 383 | 384 | } 385 | 386 | _pos += strLen; 387 | } 388 | 389 | public void WriteString(int fieldIndex, List value) 390 | { 391 | if (value == null || value.Count == 0) 392 | { 393 | return; 394 | } 395 | 396 | for (int i = 0; i < value.Count; i++) 397 | { 398 | WriteTag(fieldIndex, WireFormat.WireType.Bytes); 399 | WriteStringBytes(value[i]); 400 | } 401 | } 402 | 403 | public void WriteStruct(int fieldIndex, IProtoStruct s) 404 | { 405 | if (s == null) 406 | { 407 | return; 408 | } 409 | 410 | var size = s.GetSize(); 411 | if (size == 0) 412 | { 413 | return; 414 | } 415 | 416 | WriteTag(fieldIndex, WireFormat.WireType.Bytes); 417 | 418 | WriteVarint32((uint)size); 419 | 420 | s.Marshal(this); 421 | } 422 | 423 | public void WriteStruct(int fieldIndex, List value) where T:IProtoStruct 424 | { 425 | if (value == null) 426 | return; 427 | 428 | for (int i = 0; i < value.Count; i++) 429 | { 430 | WriteStruct(fieldIndex, value[i]); 431 | } 432 | } 433 | 434 | #endregion 435 | 436 | public void Marshal(IProtoStruct s) 437 | { 438 | s.Marshal(this); 439 | } 440 | 441 | void WriteVarint32(uint value) 442 | { 443 | // Optimize for the common case of a single byte value 444 | if (value < 128 && _pos < _len) 445 | { 446 | _buffer[_pos++] = (byte)value; 447 | return; 448 | } 449 | 450 | while (value > 127 && _pos < _len) 451 | { 452 | _buffer[_pos++] = (byte)((value & 0x7F) | 0x80); 453 | value >>= 7; 454 | } 455 | 456 | while (value > 127) 457 | { 458 | WriteByte((byte)((value & 0x7F) | 0x80)); 459 | value >>= 7; 460 | } 461 | 462 | if (_pos < _len) 463 | { 464 | _buffer[_pos++] = (byte)value; 465 | } 466 | else 467 | { 468 | WriteByte((byte) value); 469 | } 470 | } 471 | 472 | internal void WriteByte(byte value ) 473 | { 474 | CheckBuffer(1); 475 | _buffer[_pos++] = value; 476 | } 477 | 478 | internal void WriteVarint64(ulong value) 479 | { 480 | while (value > 127 && _pos < _len) 481 | { 482 | _buffer[_pos++] = (byte)((value & 0x7F) | 0x80); 483 | value >>= 7; 484 | } 485 | while (value > 127) 486 | { 487 | WriteByte((byte) ((value & 0x7F) | 0x80)); 488 | value >>= 7; 489 | } 490 | if (_pos < _len) 491 | { 492 | _buffer[_pos++] = (byte)value; 493 | } 494 | else 495 | { 496 | WriteByte((byte) value); 497 | } 498 | } 499 | public void WriteFixed16(ushort value) 500 | { 501 | CheckBuffer(2); 502 | _buffer[_pos++] = ((byte)value); 503 | _buffer[_pos++] = ((byte)(value >> 8)); 504 | } 505 | 506 | public void WriteFixed32(uint value) 507 | { 508 | CheckBuffer(4); 509 | _buffer[_pos++] = ((byte)value); 510 | _buffer[_pos++] = ((byte)(value >> 8)); 511 | _buffer[_pos++] = ((byte)(value >> 16)); 512 | _buffer[_pos++] = ((byte)(value >> 24)); 513 | } 514 | 515 | public void WriteFixed64(ulong value) 516 | { 517 | CheckBuffer(8); 518 | _buffer[_pos++] = ((byte)value); 519 | _buffer[_pos++] = ((byte)(value >> 8)); 520 | _buffer[_pos++] = ((byte)(value >> 16)); 521 | _buffer[_pos++] = ((byte)(value >> 24)); 522 | _buffer[_pos++] = ((byte)(value >> 32)); 523 | _buffer[_pos++] = ((byte)(value >> 40)); 524 | _buffer[_pos++] = ((byte)(value >> 48)); 525 | _buffer[_pos++] = ((byte)(value >> 56)); 526 | } 527 | 528 | public void WriteFixedString(string value ) 529 | { 530 | int strLen = Encoding.UTF8.GetByteCount(value); 531 | 532 | WriteFixed16((ushort)strLen); 533 | 534 | CheckBuffer(strLen); 535 | 536 | // 全ASCII 537 | if (strLen == value.Length) 538 | { 539 | for (int i = 0; i < strLen; i++) 540 | { 541 | _buffer[_pos + i] = (byte)value[i]; 542 | } 543 | } 544 | else 545 | { 546 | Encoding.UTF8.GetBytes(value, 0, value.Length, _buffer, _pos); 547 | 548 | } 549 | 550 | _pos += strLen; 551 | } 552 | 553 | internal void WriteRawBytes(byte[] value, int length ) 554 | { 555 | CheckBuffer(length); 556 | WireFormat.CopyBytes(value, _buffer, 0, _pos, length); 557 | _pos += length; 558 | } 559 | 560 | 561 | } 562 | } 563 | -------------------------------------------------------------------------------- /api/csharp/ProtoPlus/ProtoPlus.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.0 5 | 6 | 7 | 8 | TRACE;DEBUG;NETCOREAPP2_0 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /api/csharp/ProtoPlus/ProtoStruct.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace ProtoPlus 3 | { 4 | public interface IProtoStruct 5 | { 6 | void Init(); 7 | 8 | bool Unmarshal(InputStream stream, int fieldNumber, WireFormat.WireType wt ); 9 | 10 | void Marshal(OutputStream stream); 11 | 12 | int GetSize(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /api/csharp/ProtoPlus/SizeCaculator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace ProtoPlus 6 | { 7 | public partial class OutputStream 8 | { 9 | #region Proto API 10 | 11 | 12 | public static int SizeBytes(int fieldIndex, byte[] value) 13 | { 14 | if (value == null || value.Length == 0) 15 | { 16 | return 0; 17 | } 18 | 19 | int size = value.Length; 20 | 21 | return GetVarint32Size(WireFormat.MakeTag(fieldIndex, WireFormat.WireType.Bytes)) + 22 | GetVarint32Size((uint)size) + 23 | size; 24 | 25 | } 26 | 27 | public static int SizeBool(int fieldIndex, bool value) 28 | { 29 | if (value == false) 30 | { 31 | return 0; 32 | } 33 | 34 | return GetVarint32Size(WireFormat.MakeTag(fieldIndex, WireFormat.WireType.Varint)) + 1; 35 | } 36 | 37 | public static int SizeBool(int fieldIndex, List value) 38 | { 39 | if (value == null || value.Count == 0) 40 | { 41 | return 0; 42 | } 43 | 44 | int size = value.Count; 45 | 46 | return GetVarint32Size(WireFormat.MakeTag(fieldIndex, WireFormat.WireType.Bytes)) + 47 | GetVarint32Size((uint)size) + 48 | size; 49 | } 50 | 51 | public static int SizeEnum(int fieldIndex, T value) where T : struct, IConvertible 52 | { 53 | var v = Convert.ToInt32(value); 54 | return SizeInt32(fieldIndex, v); 55 | } 56 | 57 | public static int SizeEnum(int fieldIndex, List value) where T : struct, IConvertible 58 | { 59 | if (value == null || value.Count == 0) 60 | { 61 | return 0; 62 | } 63 | 64 | int size = 0; 65 | for (int i = 0; i < value.Count; i++) 66 | { 67 | size += GetVarint32Size((uint)Convert.ToInt32(value[i])); 68 | } 69 | 70 | return GetVarint32Size(WireFormat.MakeTag(fieldIndex, WireFormat.WireType.Bytes)) + 71 | GetVarint32Size((uint)size) + 72 | size; 73 | } 74 | 75 | 76 | public static int SizeFloat(int fieldIndex, float value) 77 | { 78 | if (value == 0F) 79 | { 80 | return 0; 81 | } 82 | 83 | return GetVarint32Size(WireFormat.MakeTag(fieldIndex, WireFormat.WireType.Fixed32)) + 4; 84 | } 85 | 86 | public static int SizeFloat(int fieldIndex, List value) 87 | { 88 | if (value == null || value.Count == 0) 89 | { 90 | return 0; 91 | } 92 | 93 | int size = value.Count * 4; 94 | 95 | return GetVarint32Size(WireFormat.MakeTag(fieldIndex, WireFormat.WireType.Bytes)) + 96 | GetVarint32Size((uint)size) + 97 | size; 98 | } 99 | 100 | 101 | public static int SizeDouble(int fieldIndex, double value) 102 | { 103 | if (value == 0D) 104 | { 105 | return 0; 106 | } 107 | 108 | return GetVarint32Size(WireFormat.MakeTag(fieldIndex, WireFormat.WireType.Fixed64)) + 8; 109 | } 110 | 111 | public static int SizeDouble(int fieldIndex, List value) 112 | { 113 | if (value == null || value.Count == 0) 114 | { 115 | return 0; 116 | } 117 | 118 | int size = value.Count * 8; 119 | 120 | return GetVarint32Size(WireFormat.MakeTag(fieldIndex, WireFormat.WireType.Bytes)) + 121 | GetVarint32Size((uint)size) + 122 | size; 123 | } 124 | 125 | public static int SizeInt32(int fieldIndex, int value) 126 | { 127 | if (value == 0) 128 | return 0; 129 | 130 | if (value > 0) 131 | return GetVarint32Size(WireFormat.MakeTag(fieldIndex, WireFormat.WireType.Varint)) + 132 | GetVarint32Size((uint)value); 133 | 134 | return GetVarint32Size(WireFormat.MakeTag(fieldIndex, WireFormat.WireType.Fixed32)) + 4; 135 | } 136 | 137 | public static int SizeInt32(int fieldIndex, List value) 138 | { 139 | if (value == null || value.Count == 0) 140 | { 141 | return 0; 142 | } 143 | 144 | int size = 0; 145 | for (int i = 0; i < value.Count; i++) 146 | { 147 | size += GetVarint32Size((uint)value[i]); 148 | } 149 | 150 | return GetVarint32Size(WireFormat.MakeTag(fieldIndex, WireFormat.WireType.Bytes)) + 151 | GetVarint32Size((uint)size) + 152 | size; 153 | } 154 | 155 | public static int SizeUInt32(int fieldIndex, uint value) 156 | { 157 | if (value == 0) 158 | return 0; 159 | 160 | return GetVarint32Size(WireFormat.MakeTag(fieldIndex, WireFormat.WireType.Varint)) + 161 | GetVarint32Size(value); 162 | } 163 | 164 | 165 | public static int SizeUInt32(int fieldIndex, List value) 166 | { 167 | if (value == null || value.Count == 0) 168 | { 169 | return 0; 170 | } 171 | 172 | int size = 0; 173 | for (int i = 0; i < value.Count; i++) 174 | { 175 | size += GetVarint32Size(value[i]); 176 | } 177 | 178 | return GetVarint32Size(WireFormat.MakeTag(fieldIndex, WireFormat.WireType.Bytes)) + 179 | GetVarint32Size((uint)size) + 180 | size; 181 | } 182 | 183 | 184 | public static int SizeInt64(int fieldIndex, long value) 185 | { 186 | if (value == 0) 187 | return 0; 188 | 189 | if (value > 0 ) 190 | return GetVarint32Size(WireFormat.MakeTag(fieldIndex, WireFormat.WireType.Varint)) + 191 | ComputeRawVarint64Size((ulong)value); 192 | 193 | return GetVarint32Size(WireFormat.MakeTag(fieldIndex, WireFormat.WireType.Fixed64)) + 8; 194 | } 195 | 196 | public static int SizeInt64(int fieldIndex, List value) 197 | { 198 | if (value == null || value.Count == 0) 199 | { 200 | return 0; 201 | } 202 | 203 | int size = 0; 204 | for (int i = 0; i < value.Count; i++) 205 | { 206 | size += ComputeRawVarint64Size((ulong)value[i]); 207 | } 208 | 209 | return GetVarint32Size(WireFormat.MakeTag(fieldIndex, WireFormat.WireType.Bytes)) + 210 | GetVarint32Size((uint)size) + 211 | size; 212 | } 213 | 214 | public static int SizeUInt64(int fieldIndex, ulong value) 215 | { 216 | if (value == 0) 217 | return 0; 218 | 219 | return GetVarint32Size(WireFormat.MakeTag(fieldIndex, WireFormat.WireType.Varint)) + 220 | ComputeRawVarint64Size(value); 221 | } 222 | 223 | public static int SizeUInt64(int fieldIndex, List value) 224 | { 225 | if (value == null || value.Count == 0) 226 | { 227 | return 0; 228 | } 229 | 230 | int size = 0; 231 | for (int i = 0; i < value.Count; i++) 232 | { 233 | size += ComputeRawVarint64Size(value[i]); 234 | } 235 | 236 | return GetVarint32Size(WireFormat.MakeTag(fieldIndex, WireFormat.WireType.Bytes)) + 237 | GetVarint32Size((uint)size) + 238 | size; 239 | } 240 | 241 | 242 | public static int SizeString(int fieldIndex, string value) 243 | { 244 | if (string.IsNullOrEmpty(value)) 245 | return 0; 246 | 247 | int strLen = Encoding.UTF8.GetByteCount(value); 248 | 249 | return GetVarint32Size(WireFormat.MakeTag(fieldIndex, WireFormat.WireType.Varint)) + 250 | GetVarint32Size((uint) strLen) + 251 | strLen; 252 | } 253 | 254 | public static int SizeString(int fieldIndex, List value) 255 | { 256 | if (value == null || value.Count == 0) 257 | { 258 | return 0; 259 | } 260 | 261 | int size = 0; 262 | for (int i = 0; i < value.Count; i++) 263 | { 264 | size += SizeString(fieldIndex,value[i]); 265 | } 266 | 267 | return size; 268 | } 269 | 270 | public static int SizeStruct(int fieldIndex, IProtoStruct value) 271 | { 272 | if (value == null) 273 | return 0; 274 | 275 | var size = value.GetSize(); 276 | if (size == 0) 277 | { 278 | return 0; 279 | } 280 | 281 | return GetVarint32Size(WireFormat.MakeTag(fieldIndex, WireFormat.WireType.Varint)) + 282 | GetVarint32Size((uint)size) + 283 | size; 284 | } 285 | 286 | public static int SizeStruct(int fieldIndex, List value) where T:IProtoStruct 287 | { 288 | if (value == null || value.Count == 0) 289 | return 0; 290 | 291 | int size = 0; 292 | for (int i = 0; i < value.Count; i++) 293 | { 294 | size += SizeStruct(fieldIndex, value[i]); 295 | } 296 | 297 | return size; 298 | } 299 | 300 | #endregion 301 | 302 | static int GetVarint32Size(uint value) 303 | { 304 | if ((value & (0xffffffff << 7)) == 0) 305 | { 306 | return 1; 307 | } 308 | if ((value & (0xffffffff << 14)) == 0) 309 | { 310 | return 2; 311 | } 312 | if ((value & (0xffffffff << 21)) == 0) 313 | { 314 | return 3; 315 | } 316 | if ((value & (0xffffffff << 28)) == 0) 317 | { 318 | return 4; 319 | } 320 | return 5; 321 | } 322 | 323 | static int ComputeRawVarint64Size(ulong value) 324 | { 325 | if ((value & (0xffffffffffffffffL << 7)) == 0) 326 | { 327 | return 1; 328 | } 329 | if ((value & (0xffffffffffffffffL << 14)) == 0) 330 | { 331 | return 2; 332 | } 333 | if ((value & (0xffffffffffffffffL << 21)) == 0) 334 | { 335 | return 3; 336 | } 337 | if ((value & (0xffffffffffffffffL << 28)) == 0) 338 | { 339 | return 4; 340 | } 341 | if ((value & (0xffffffffffffffffL << 35)) == 0) 342 | { 343 | return 5; 344 | } 345 | if ((value & (0xffffffffffffffffL << 42)) == 0) 346 | { 347 | return 6; 348 | } 349 | if ((value & (0xffffffffffffffffL << 49)) == 0) 350 | { 351 | return 7; 352 | } 353 | if ((value & (0xffffffffffffffffL << 56)) == 0) 354 | { 355 | return 8; 356 | } 357 | if ((value & (0xffffffffffffffffL << 63)) == 0) 358 | { 359 | return 9; 360 | } 361 | return 10; 362 | } 363 | 364 | 365 | 366 | 367 | 368 | } 369 | } 370 | -------------------------------------------------------------------------------- /api/csharp/ProtoPlus/WireType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ProtoPlus 4 | { 5 | public static class WireFormat 6 | { 7 | public enum WireType : uint 8 | { 9 | None = 0, 10 | Varint, 11 | Bytes, 12 | Zigzag32, 13 | Zigzag64, 14 | Fixed32, 15 | Fixed64, 16 | } 17 | 18 | const int TagTypeBits = 3; 19 | const uint TagTypeMask = (1 << TagTypeBits) - 1; 20 | 21 | public static uint MakeTag(int fieldNumber, WireType type ) 22 | { 23 | return (uint) (fieldNumber << TagTypeBits) | (uint)type; 24 | } 25 | 26 | public static void ParseWireTag(uint tag, ref int fieldNumber, ref WireType wt) 27 | { 28 | fieldNumber = (int) tag >> TagTypeBits; 29 | wt = (WireType) (tag & TagTypeMask); 30 | } 31 | 32 | const int CopyThreshold = 12; 33 | internal static void CopyBytes(byte[] src, byte[] dst, int srcOffset, int destOffset, int count) 34 | { 35 | if (count < CopyThreshold) 36 | { 37 | for (int i = 0; i < count; i++) 38 | { 39 | dst[destOffset+i] = src[srcOffset+i]; 40 | } 41 | } 42 | else 43 | { 44 | Buffer.BlockCopy(src, srcOffset, dst, destOffset, count); 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /api/golang/api.go: -------------------------------------------------------------------------------- 1 | package ppgo 2 | 3 | import ( 4 | "github.com/davyxu/protoplus/api/golang/wire" 5 | "github.com/davyxu/ulexer" 6 | ) 7 | 8 | type Struct = wire.Struct 9 | 10 | func Marshal(msg Struct) ([]byte, error) { 11 | 12 | if msg == nil { 13 | return nil, nil 14 | } 15 | 16 | l := msg.Size() 17 | 18 | data := make([]byte, 0, l) 19 | 20 | buffer := wire.NewBuffer(data) 21 | 22 | err := msg.Marshal(buffer) 23 | if err != nil { 24 | return nil, err 25 | } 26 | 27 | return buffer.Bytes(), nil 28 | 29 | } 30 | 31 | func Size(msg Struct) int { 32 | 33 | if msg == nil { 34 | return 0 35 | } 36 | 37 | return msg.Size() 38 | } 39 | 40 | func Unmarshal(data []byte, msg Struct) (err error) { 41 | 42 | buffer := wire.NewBuffer(data) 43 | 44 | return wire.UnmarshalStructObject(buffer, msg) 45 | } 46 | 47 | var ( 48 | defaultTextMarshaler = TextMarshaler{} 49 | compactTextMarshaler = TextMarshaler{Compact: true, IgnoreDefault: true, CompactBytesSize: 50} 50 | ) 51 | 52 | func MarshalTextString(obj interface{}) string { 53 | return defaultTextMarshaler.Text(obj) 54 | } 55 | 56 | func CompactTextString(obj interface{}) string { return compactTextMarshaler.Text(obj) } 57 | 58 | func UnmarshalText(s string, obj interface{}) error { 59 | 60 | vObj := safeValueOf(obj) 61 | tObj := safeTypeOf(obj) 62 | 63 | lex := ulexer.NewLexer(s) 64 | 65 | // 读之前, 清掉空白 66 | lex.SetPreHook(func(lex *ulexer.Lexer) *ulexer.Token { 67 | 68 | lex.Read(ulexer.WhiteSpace()) 69 | return nil 70 | }) 71 | 72 | err := ulexer.Try(lex, func(lex *ulexer.Lexer) { 73 | 74 | parseStruct(lex, tObj, vObj, "") 75 | 76 | }) 77 | 78 | return err 79 | } 80 | -------------------------------------------------------------------------------- /api/golang/text_marshaler.go: -------------------------------------------------------------------------------- 1 | package ppgo 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "encoding" 7 | "fmt" 8 | "io" 9 | "math" 10 | "reflect" 11 | "sort" 12 | ) 13 | 14 | // TextMarshaler is a configurable text format marshaler. 15 | type TextMarshaler struct { 16 | Compact bool // use compact text format (one line). 17 | IgnoreDefault bool // Do not output value when value equals its default value 18 | OriginalString bool // Do not output string as byte 19 | CompactBytesSize int // 将二进制在指定大小后缩减显示 20 | } 21 | 22 | func (self *TextMarshaler) Marshal(w io.Writer, obj interface{}) error { 23 | 24 | val := reflect.ValueOf(obj) 25 | 26 | if obj == nil || (val.Kind() == reflect.Ptr && val.IsNil()) { 27 | w.Write([]byte("")) 28 | return nil 29 | } 30 | 31 | var bw *bufio.Writer 32 | ww, ok := w.(writer) 33 | if !ok { 34 | bw = bufio.NewWriter(w) 35 | ww = bw 36 | } 37 | aw := &textWriter{ 38 | w: ww, 39 | complete: true, 40 | compact: self.Compact, 41 | } 42 | 43 | // Dereference the received pointer so we don't have outer < and >. 44 | v := reflect.Indirect(val) 45 | if err := self.writeStruct(aw, v); err != nil { 46 | return err 47 | } 48 | if bw != nil { 49 | return bw.Flush() 50 | } 51 | 52 | return nil 53 | } 54 | 55 | func writeName(w *textWriter, name string) error { 56 | if _, err := w.WriteString(name); err != nil { 57 | return err 58 | } 59 | 60 | return w.WriteByte(':') 61 | } 62 | 63 | func (self *TextMarshaler) ignoreField(w *textWriter, v reflect.Value) bool { 64 | 65 | if !self.IgnoreDefault { 66 | return false 67 | } 68 | 69 | v = reflect.Indirect(v) 70 | 71 | switch v.Kind() { 72 | case reflect.Float32, reflect.Float64: 73 | if v.Float() == 0 { 74 | return true 75 | } 76 | case reflect.Int32, reflect.Int64, reflect.Int: 77 | if v.Int() == 0 { 78 | return true 79 | } 80 | case reflect.Uint32, reflect.Uint64, reflect.Uint: 81 | if v.Uint() == 0 { 82 | return true 83 | } 84 | case reflect.Bool: 85 | if !v.Bool() { 86 | return true 87 | } 88 | 89 | case reflect.Slice, reflect.String: 90 | if v.Len() == 0 { 91 | return true 92 | } 93 | } 94 | 95 | return false 96 | } 97 | 98 | func (self *TextMarshaler) writeAny(w *textWriter, v reflect.Value) error { 99 | v = reflect.Indirect(v) 100 | 101 | // Floats have special cases. 102 | if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 { 103 | x := v.Float() 104 | var b []byte 105 | switch { 106 | case math.IsInf(x, 1): 107 | b = posInf 108 | case math.IsInf(x, -1): 109 | b = negInf 110 | case math.IsNaN(x): 111 | b = nan 112 | } 113 | if b != nil { 114 | _, err := w.Write(b) 115 | return err 116 | } 117 | // Other values are handled below. 118 | } 119 | 120 | // We don't attempt to serialise every possible value type; only those 121 | // that can occur in protocol buffers. 122 | 123 | switch v.Kind() { 124 | case reflect.Slice: 125 | // Should only be a []byte; repeated fields are handled in writeStruct. 126 | if err := writeString(w, string(v.Bytes())); err != nil { 127 | return err 128 | } 129 | case reflect.String: 130 | 131 | if err := writeString(w, v.String()); err != nil { 132 | return err 133 | } 134 | case reflect.Struct: 135 | // Required/optional group/message. 136 | var bra, ket byte = '{', '}' 137 | 138 | if err := w.WriteByte(bra); err != nil { 139 | return err 140 | } 141 | if !w.compact { 142 | if err := w.WriteByte('\n'); err != nil { 143 | return err 144 | } 145 | } 146 | w.indent() 147 | if etm, ok := v.Interface().(encoding.TextMarshaler); ok { 148 | text, err := etm.MarshalText() 149 | if err != nil { 150 | return err 151 | } 152 | if _, err = w.Write(text); err != nil { 153 | return err 154 | } 155 | } else if err := self.writeStruct(w, v); err != nil { 156 | return err 157 | } 158 | w.unindent() 159 | if err := w.WriteByte(ket); err != nil { 160 | return err 161 | } 162 | case reflect.Int32: 163 | // 枚举切片的值应该是输出整形 164 | if _, ok := v.Interface().(fmt.Stringer); ok { 165 | 166 | _, err := fmt.Fprint(w, v.Int()) 167 | return err 168 | 169 | } else { 170 | _, err := fmt.Fprint(w, v.Interface()) 171 | return err 172 | } 173 | 174 | default: 175 | _, err := fmt.Fprint(w, v.Interface()) 176 | return err 177 | } 178 | 179 | return nil 180 | } 181 | 182 | func (self *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { 183 | 184 | st := sv.Type() 185 | 186 | for i := 0; i < sv.NumField(); i++ { 187 | fv := sv.Field(i) 188 | 189 | stf := st.Field(i) 190 | 191 | if tag := stf.Tag.Get("text"); tag == "-" { 192 | continue 193 | } 194 | 195 | name := stf.Name 196 | 197 | if fv.Kind() == reflect.Ptr && fv.IsNil() { 198 | // Field not filled in. This could be an optional field or 199 | // a required field that wasn't filled in. Either way, there 200 | // isn't anything we can show for it. 201 | continue 202 | } 203 | 204 | if fv.Kind() == reflect.Slice { 205 | 206 | // Repeated field that is empty, or a bytes field that is unused. 207 | if fv.IsNil() { 208 | continue 209 | } 210 | 211 | // []byte 212 | if fv.Len() > 0 { 213 | 214 | if err := writeName(w, name); err != nil { 215 | return err 216 | } 217 | 218 | if err := w.WriteByte('['); err != nil { 219 | return err 220 | } 221 | } 222 | 223 | if fv.Len() > self.CompactBytesSize { 224 | w.Write([]byte(fmt.Sprintf("len: %d", fv.Len()))) 225 | 226 | } else { 227 | // Repeated field. 228 | for j := 0; j < fv.Len(); j++ { 229 | 230 | v := fv.Index(j) 231 | // 232 | //if v.Kind() != reflect.Uint8 { 233 | // if err := writeName(w, name); err != nil { 234 | // return err 235 | // } 236 | //} 237 | 238 | if !w.compact { 239 | if err := w.WriteByte(' '); err != nil { 240 | return err 241 | } 242 | } 243 | 244 | if j > 0 { 245 | if err := w.WriteByte('\n'); err != nil { 246 | return err 247 | } 248 | } 249 | 250 | if v.Kind() == reflect.Ptr && v.IsNil() { 251 | // A nil message in a repeated field is not valid, 252 | // but we can handle that more gracefully than panicking. 253 | if _, err := w.Write([]byte("\n")); err != nil { 254 | return err 255 | } 256 | continue 257 | } 258 | if err := self.writeAny(w, v); err != nil { 259 | return err 260 | } 261 | 262 | } 263 | } 264 | 265 | if fv.Len() > 0 { 266 | if _, err := w.WriteString("] "); err != nil { 267 | return err 268 | } 269 | } 270 | 271 | continue 272 | } 273 | 274 | if fv.Kind() == reflect.Map { 275 | // Map fields are rendered as a repeated struct with key/value fields. 276 | keys := fv.MapKeys() 277 | sort.Sort(mapKeys(keys)) 278 | for _, key := range keys { 279 | val := fv.MapIndex(key) 280 | if err := writeName(w, name); err != nil { 281 | return err 282 | } 283 | if !w.compact { 284 | if err := w.WriteByte(' '); err != nil { 285 | return err 286 | } 287 | } 288 | // open struct 289 | if err := w.WriteByte('{'); err != nil { 290 | return err 291 | } 292 | if !w.compact { 293 | if err := w.WriteByte('\n'); err != nil { 294 | return err 295 | } 296 | } 297 | w.indent() 298 | // key 299 | if _, err := w.WriteString("key:"); err != nil { 300 | return err 301 | } 302 | if !w.compact { 303 | if err := w.WriteByte(' '); err != nil { 304 | return err 305 | } 306 | } 307 | if err := self.writeAny(w, key); err != nil { 308 | return err 309 | } 310 | if err := w.WriteByte('\n'); err != nil { 311 | return err 312 | } 313 | // nil values aren't legal, but we can avoid panicking because of them. 314 | if val.Kind() != reflect.Ptr || !val.IsNil() { 315 | // value 316 | if _, err := w.WriteString("value:"); err != nil { 317 | return err 318 | } 319 | if !w.compact { 320 | if err := w.WriteByte(' '); err != nil { 321 | return err 322 | } 323 | } 324 | if err := self.writeAny(w, val); err != nil { 325 | return err 326 | } 327 | if err := w.WriteByte('\n'); err != nil { 328 | return err 329 | } 330 | } 331 | // close struct 332 | w.unindent() 333 | if err := w.WriteByte('}'); err != nil { 334 | return err 335 | } 336 | if err := w.WriteByte('\n'); err != nil { 337 | return err 338 | } 339 | } 340 | continue 341 | } 342 | 343 | if !self.ignoreField(w, fv) { 344 | if err := writeName(w, name); err != nil { 345 | return err 346 | } 347 | if !w.compact { 348 | if err := w.WriteByte(' '); err != nil { 349 | return err 350 | } 351 | } 352 | 353 | // Enums have a String method, so writeAny will work fine. 354 | if err := self.writeAny(w, fv); err != nil { 355 | return err 356 | } 357 | 358 | if err := w.WriteByte('\n'); err != nil { 359 | return err 360 | } 361 | 362 | } 363 | 364 | } 365 | 366 | return nil 367 | } 368 | 369 | func (self *TextMarshaler) Text(obj interface{}) string { 370 | var buf bytes.Buffer 371 | self.Marshal(&buf, obj) 372 | return buf.String() 373 | } 374 | -------------------------------------------------------------------------------- /api/golang/text_marshaler_test.go: -------------------------------------------------------------------------------- 1 | package ppgo 2 | 3 | import ( 4 | "math" 5 | "testing" 6 | ) 7 | 8 | type MyCar int32 9 | 10 | const ( 11 | MyCar_Monkey MyCar = 1 12 | MyCar_Monk MyCar = 2 13 | MyCar_Pig MyCar = 3 14 | ) 15 | 16 | type MyData struct { 17 | Stream []byte 18 | 19 | Name string 20 | 21 | Type MyCar 22 | 23 | Int32 int32 24 | 25 | Uint32 uint32 26 | 27 | Int64 int64 28 | 29 | Uint64 uint64 30 | 31 | StrList []string 32 | } 33 | 34 | type PhoneNumber struct { 35 | Number string 36 | 37 | Type int32 38 | } 39 | 40 | type Person struct { 41 | Name string 42 | 43 | Id int32 44 | 45 | Email string 46 | 47 | Phone []*PhoneNumber 48 | } 49 | 50 | type AddressBook struct { 51 | Person []*Person 52 | 53 | PersonByName map[string]*Person 54 | } 55 | 56 | func TestNumber(t *testing.T) { 57 | 58 | input := &MyData{ 59 | Stream: []byte{1, 2, 3, 4}, 60 | Name: "genji", 61 | Type: MyCar_Pig, 62 | Uint32: math.MaxUint32, 63 | Int64: math.MaxInt64, 64 | Uint64: math.MaxUint64, 65 | } 66 | 67 | t.Log(CompactTextString(input)) 68 | } 69 | 70 | func TestBytesCompatct(t *testing.T) { 71 | 72 | input := &MyData{ 73 | Stream: []byte{1, 2, 3, 4}, 74 | } 75 | 76 | t.Log(CompactTextString(input)) 77 | } 78 | 79 | func TestString(t *testing.T) { 80 | t.Log(CompactTextString(&MyData{StrList: []string{"a", "b", "c"}})) 81 | } 82 | 83 | func TestPhone(t *testing.T) { 84 | input := &AddressBook{ 85 | Person: []*Person{ 86 | { 87 | Name: "Alice", 88 | Id: int32(10000), 89 | Phone: []*PhoneNumber{ 90 | { 91 | Number: "123456789", 92 | Type: 1, 93 | }, 94 | { 95 | Number: "87654321", 96 | Type: 2, 97 | }, 98 | }, 99 | }, 100 | { 101 | Name: "Bob", 102 | Id: int32(20000), 103 | Phone: []*PhoneNumber{ 104 | { 105 | Number: "01234567890", 106 | Type: int32(3), 107 | }, 108 | }, 109 | }, 110 | }, 111 | } 112 | 113 | input.PersonByName = make(map[string]*Person) 114 | 115 | for _, v := range input.Person { 116 | 117 | input.PersonByName[v.Name] = v 118 | } 119 | 120 | t.Log(CompactTextString(input)) 121 | 122 | t.Log(MarshalTextString(input)) 123 | 124 | } 125 | -------------------------------------------------------------------------------- /api/golang/text_parser.go: -------------------------------------------------------------------------------- 1 | package ppgo 2 | 3 | import ( 4 | "github.com/davyxu/ulexer" 5 | "reflect" 6 | "strings" 7 | ) 8 | 9 | type MatchAction func(tk *ulexer.Token) 10 | 11 | func selectAction(self *ulexer.Lexer, mlist []ulexer.Matcher, alist []MatchAction) { 12 | 13 | if len(mlist) != len(alist) { 14 | panic("Matcher list should equal to Action list length") 15 | } 16 | 17 | var hit bool 18 | for index, m := range mlist { 19 | tk := self.Read(m) 20 | 21 | if tk != nil { 22 | 23 | action := alist[index] 24 | if action != nil { 25 | action(tk) 26 | } 27 | hit = true 28 | break 29 | } 30 | } 31 | 32 | if !hit { 33 | 34 | var sb strings.Builder 35 | 36 | for index, m := range mlist { 37 | if index > 0 { 38 | sb.WriteString(" ") 39 | } 40 | sb.WriteString(m.TokenType()) 41 | } 42 | 43 | self.Error("Expect %s", sb.String()) 44 | } 45 | 46 | } 47 | 48 | func detectEnd(lex *ulexer.Lexer, literal string) bool { 49 | if literal != "" { 50 | if tk := lex.Read(ulexer.Contain(literal)); tk.String() == literal { 51 | return true 52 | } 53 | } 54 | 55 | return false 56 | } 57 | 58 | func parseStruct(lex *ulexer.Lexer, tObj reflect.Type, vObj reflect.Value, endLiteral string) { 59 | for { 60 | 61 | if detectEnd(lex, endLiteral) { 62 | break 63 | } 64 | 65 | fieldTk := ulexer.Expect(lex, ulexer.Identifier()) 66 | 67 | tField, fieldExists := tObj.FieldByName(fieldTk.String()) 68 | vField := vObj.FieldByName(fieldTk.String()) 69 | 70 | ulexer.Expect(lex, ulexer.Contain(":")) 71 | 72 | parseMultiValue(lex, []ulexer.Matcher{ulexer.String(), 73 | ulexer.Numeral(), 74 | ulexer.Bool(), 75 | ulexer.Contain("["), 76 | ulexer.Contain("{"), 77 | ulexer.Identifier(), 78 | }, func(tk *ulexer.Token) { 79 | if !fieldExists { 80 | return 81 | } 82 | 83 | switch tField.Type.Kind() { 84 | case reflect.Bool: 85 | vField.SetBool(tk.Bool()) 86 | case reflect.String: 87 | vField.SetString(tk.String()) 88 | case reflect.Int32: 89 | vField.SetInt(int64(tk.Int32())) 90 | case reflect.Int64: 91 | vField.SetInt(int64(tk.Int64())) 92 | case reflect.Uint32: 93 | vField.SetUint(uint64(tk.UInt32())) 94 | case reflect.Uint64: 95 | vField.SetUint(uint64(tk.UInt64())) 96 | case reflect.Float32: 97 | vField.SetFloat(float64(tk.Float32())) 98 | case reflect.Float64: 99 | vField.SetFloat(tk.Float64()) 100 | case reflect.Slice: 101 | parseArray(lex, tField.Type, vField, "]") 102 | case reflect.Struct: 103 | parseStruct(lex, tField.Type, vField, "}") 104 | default: 105 | panic("unsupport field kind " + tField.Type.Kind().String()) 106 | } 107 | }) 108 | } 109 | } 110 | 111 | func parseMultiValue(lex *ulexer.Lexer, mlist []ulexer.Matcher, action MatchAction) { 112 | 113 | alist := make([]MatchAction, 0, len(mlist)) 114 | for i := 0; i < len(mlist); i++ { 115 | alist = append(alist, action) 116 | } 117 | 118 | selectAction(lex, 119 | mlist, 120 | alist, 121 | ) 122 | } 123 | 124 | func parseElement(lex *ulexer.Lexer, endLiteral string, m ulexer.Matcher, onValue MatchAction, onEnd func()) { 125 | for { 126 | 127 | if detectEnd(lex, endLiteral) { 128 | onEnd() 129 | break 130 | } 131 | 132 | tk := ulexer.Expect(lex, m) 133 | onValue(tk) 134 | } 135 | 136 | } 137 | 138 | func parseArray(lex *ulexer.Lexer, tField reflect.Type, vObj reflect.Value, endLiteral string) { 139 | 140 | switch tField.Elem().Kind() { 141 | case reflect.Int32: 142 | 143 | // 枚举 144 | if vObj.Kind() != reflect.Int32 { 145 | 146 | list := reflect.MakeSlice(vObj.Type(), 0, 0) 147 | 148 | parseElement(lex, endLiteral, ulexer.Integer(), func(tk *ulexer.Token) { 149 | 150 | vElm := reflect.ValueOf(tk.Int32()) 151 | 152 | list = reflect.Append(list, vElm.Convert(vObj.Type().Elem())) 153 | }, func() { 154 | 155 | vObj.Set(list) 156 | }) 157 | 158 | } else { 159 | var value []int32 160 | parseElement(lex, endLiteral, ulexer.Integer(), func(tk *ulexer.Token) { 161 | value = append(value, tk.Int32()) 162 | }, func() { 163 | 164 | vObj.Set(reflect.ValueOf(value)) 165 | }) 166 | } 167 | 168 | case reflect.Int64: 169 | var value []int64 170 | parseElement(lex, endLiteral, ulexer.Integer(), func(tk *ulexer.Token) { 171 | value = append(value, tk.Int64()) 172 | }, func() { 173 | vObj.Set(reflect.ValueOf(value)) 174 | }) 175 | case reflect.Uint64: 176 | var value []uint64 177 | parseElement(lex, endLiteral, ulexer.UInteger(), func(tk *ulexer.Token) { 178 | value = append(value, tk.UInt64()) 179 | }, func() { 180 | vObj.Set(reflect.ValueOf(value)) 181 | }) 182 | case reflect.Float32: 183 | var value []float32 184 | parseElement(lex, endLiteral, ulexer.Numeral(), func(tk *ulexer.Token) { 185 | value = append(value, tk.Float32()) 186 | }, func() { 187 | vObj.Set(reflect.ValueOf(value)) 188 | }) 189 | case reflect.Float64: 190 | var value []float64 191 | parseElement(lex, endLiteral, ulexer.Numeral(), func(tk *ulexer.Token) { 192 | value = append(value, tk.Float64()) 193 | }, func() { 194 | vObj.Set(reflect.ValueOf(value)) 195 | }) 196 | case reflect.Uint32: 197 | var value []uint32 198 | parseElement(lex, endLiteral, ulexer.UInteger(), func(tk *ulexer.Token) { 199 | value = append(value, tk.UInt32()) 200 | }, func() { 201 | vObj.Set(reflect.ValueOf(value)) 202 | }) 203 | case reflect.Bool: 204 | var value []bool 205 | parseElement(lex, endLiteral, ulexer.Bool(), func(tk *ulexer.Token) { 206 | value = append(value, tk.Bool()) 207 | }, func() { 208 | vObj.Set(reflect.ValueOf(value)) 209 | }) 210 | case reflect.String: 211 | var value []string 212 | parseElement(lex, endLiteral, ulexer.String(), func(tk *ulexer.Token) { 213 | value = append(value, tk.String()) 214 | }, func() { 215 | vObj.Set(reflect.ValueOf(value)) 216 | }) 217 | case reflect.Uint8: 218 | var value []byte 219 | parseElement(lex, endLiteral, ulexer.Numeral(), func(tk *ulexer.Token) { 220 | value = append(value, tk.UInt8()) 221 | }, func() { 222 | vObj.SetBytes(value) 223 | }) 224 | case reflect.Struct: 225 | 226 | list := reflect.MakeSlice(tField, 0, 0) 227 | for { 228 | 229 | if detectEnd(lex, endLiteral) { 230 | break 231 | } 232 | 233 | ulexer.Expect(lex, ulexer.Contain("{")) 234 | 235 | element := reflect.New(tField.Elem()).Elem() 236 | 237 | parseStruct(lex, tField.Elem(), element, "}") 238 | 239 | list = reflect.Append(list, element) 240 | 241 | vObj.Set(list) 242 | } 243 | 244 | default: 245 | panic("unsupport array element " + tField.Kind().String()) 246 | } 247 | 248 | } 249 | 250 | func safeValueOf(obj interface{}) reflect.Value { 251 | vObj := reflect.ValueOf(obj) 252 | if vObj.Kind() == reflect.Ptr { 253 | return vObj.Elem() 254 | } 255 | 256 | return vObj 257 | } 258 | 259 | func safeTypeOf(obj interface{}) reflect.Type { 260 | tObj := reflect.TypeOf(obj) 261 | if tObj.Kind() == reflect.Ptr { 262 | return tObj.Elem() 263 | } 264 | 265 | return tObj 266 | } 267 | -------------------------------------------------------------------------------- /api/golang/text_writer.go: -------------------------------------------------------------------------------- 1 | package ppgo 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "log" 8 | "reflect" 9 | "sort" 10 | "strings" 11 | ) 12 | 13 | var ( 14 | newline = []byte("\n") 15 | spaces = []byte(" ") 16 | gtNewline = []byte(">\n") 17 | endBraceNewline = []byte("}\n") 18 | backslashN = []byte{'\\', 'n'} 19 | backslashR = []byte{'\\', 'r'} 20 | backslashT = []byte{'\\', 't'} 21 | backslashDQ = []byte{'\\', '"'} 22 | backslashBS = []byte{'\\', '\\'} 23 | posInf = []byte("inf") 24 | negInf = []byte("-inf") 25 | nan = []byte("nan") 26 | ) 27 | 28 | type writer interface { 29 | io.Writer 30 | WriteByte(byte) error 31 | } 32 | 33 | // textWriter is an io.Writer that tracks its indentation level. 34 | type textWriter struct { 35 | ind int 36 | complete bool // if the current position is a complete line 37 | compact bool // whether to write out as a one-liner 38 | w writer 39 | } 40 | 41 | func (w *textWriter) WriteString(s string) (n int, err error) { 42 | if !strings.Contains(s, "\n") { 43 | if !w.compact && w.complete { 44 | w.writeIndent() 45 | } 46 | w.complete = false 47 | return io.WriteString(w.w, s) 48 | } 49 | // WriteString is typically called without newlines, so this 50 | // codepath and its copy are rare. We copy to avoid 51 | // duplicating all of BinaryWrite's logic here. 52 | return w.Write([]byte(s)) 53 | } 54 | 55 | func (w *textWriter) Write(p []byte) (n int, err error) { 56 | newlines := bytes.Count(p, newline) 57 | if newlines == 0 { 58 | if !w.compact && w.complete { 59 | w.writeIndent() 60 | } 61 | n, err = w.w.Write(p) 62 | w.complete = false 63 | return n, err 64 | } 65 | 66 | frags := bytes.SplitN(p, newline, newlines+1) 67 | if w.compact { 68 | for i, frag := range frags { 69 | if i > 0 { 70 | if err := w.w.WriteByte(' '); err != nil { 71 | return n, err 72 | } 73 | n++ 74 | } 75 | nn, err := w.w.Write(frag) 76 | n += nn 77 | if err != nil { 78 | return n, err 79 | } 80 | } 81 | return n, nil 82 | } 83 | 84 | for i, frag := range frags { 85 | if w.complete { 86 | w.writeIndent() 87 | } 88 | nn, err := w.w.Write(frag) 89 | n += nn 90 | if err != nil { 91 | return n, err 92 | } 93 | if i+1 < len(frags) { 94 | if err := w.w.WriteByte('\n'); err != nil { 95 | return n, err 96 | } 97 | n++ 98 | } 99 | } 100 | w.complete = len(frags[len(frags)-1]) == 0 101 | return n, nil 102 | } 103 | 104 | func (w *textWriter) WriteByte(c byte) error { 105 | if w.compact && c == '\n' { 106 | c = ' ' 107 | } 108 | if !w.compact && w.complete { 109 | w.writeIndent() 110 | } 111 | err := w.w.WriteByte(c) 112 | w.complete = c == '\n' 113 | return err 114 | } 115 | 116 | func (w *textWriter) writeIndent() { 117 | if !w.complete { 118 | return 119 | } 120 | remain := w.ind * 2 121 | for remain > 0 { 122 | n := remain 123 | if n > len(spaces) { 124 | n = len(spaces) 125 | } 126 | w.w.Write(spaces[:n]) 127 | remain -= n 128 | } 129 | w.complete = false 130 | } 131 | 132 | func (w *textWriter) indent() { w.ind++ } 133 | 134 | func (w *textWriter) unindent() { 135 | if w.ind == 0 { 136 | log.Print("proto: textWriter unindented too far") 137 | return 138 | } 139 | w.ind-- 140 | } 141 | 142 | // writeString writes a string in the protocol buffer text format. 143 | // It is similar to strconv.Quote except we don't use Go escape sequences, 144 | // we treat the string as a byte sequence, and we use octal escapes. 145 | // These differences are to maintain interoperability with the other 146 | // languages' implementations of the text format. 147 | 148 | func writeString(w *textWriter, s string) error { 149 | // use WriteByte here to get any needed indent 150 | if err := w.WriteByte('"'); err != nil { 151 | return err 152 | } 153 | // Loop over the bytes, not the runes. 154 | for i := 0; i < len(s); i++ { 155 | var err error 156 | // Divergence from C++: we don't escape apostrophes. 157 | // There's no need to escape them, and the C++ parser 158 | // copes with a naked apostrophe. 159 | switch c := s[i]; c { 160 | case '\n': 161 | _, err = w.w.Write(backslashN) 162 | case '\r': 163 | _, err = w.w.Write(backslashR) 164 | case '\t': 165 | _, err = w.w.Write(backslashT) 166 | case '"': 167 | _, err = w.w.Write(backslashDQ) 168 | case '\\': 169 | _, err = w.w.Write(backslashBS) 170 | default: 171 | 172 | // 这里中文会被认为是不可打印字符而不会输出 173 | err = w.w.WriteByte(c) 174 | //if isprint(c) { 175 | // err = w.w.WriteByte(c) 176 | //} else { 177 | // _, err = fmt.Fprintf(w.w, "\\%03o", c) 178 | //} 179 | } 180 | if err != nil { 181 | return err 182 | } 183 | } 184 | return w.WriteByte('"') 185 | } 186 | 187 | // equivalent to C's isprint. 188 | func isprint(c byte) bool { 189 | return c >= 0x20 && c < 0x7f 190 | } 191 | 192 | type mapKeySorter struct { 193 | vs []reflect.Value 194 | less func(a, b reflect.Value) bool 195 | } 196 | 197 | func (s mapKeySorter) Len() int { return len(s.vs) } 198 | func (s mapKeySorter) Swap(i, j int) { s.vs[i], s.vs[j] = s.vs[j], s.vs[i] } 199 | func (s mapKeySorter) Less(i, j int) bool { 200 | return s.less(s.vs[i], s.vs[j]) 201 | } 202 | 203 | // Map fields may have key types of non-float scalars, strings and enums. 204 | // The easiest way to sort them in some deterministic order is to use fmt. 205 | // If this turns out to be inefficient we can always consider other options, 206 | // such as doing a Schwartzian transform. 207 | 208 | func mapKeys(vs []reflect.Value) sort.Interface { 209 | s := mapKeySorter{ 210 | vs: vs, 211 | // default Less function: textual comparison 212 | less: func(a, b reflect.Value) bool { 213 | return fmt.Sprint(a.Interface()) < fmt.Sprint(b.Interface()) 214 | }, 215 | } 216 | 217 | // Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps; 218 | // numeric keys are sorted numerically. 219 | if len(vs) == 0 { 220 | return s 221 | } 222 | switch vs[0].Kind() { 223 | case reflect.Int32, reflect.Int64: 224 | s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() } 225 | case reflect.Uint32, reflect.Uint64: 226 | s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() } 227 | } 228 | 229 | return s 230 | } 231 | -------------------------------------------------------------------------------- /api/golang/wire/buffer.go: -------------------------------------------------------------------------------- 1 | package wire 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "io" 7 | ) 8 | 9 | // A Buffer is a buffer manager for marshaling and unmarshaling 10 | // protocol buffers. It may be reused between invocations to 11 | // reduce memory usage. It is not necessary to use a Buffer; 12 | // the global functions Marshal and Unmarshal create a 13 | // temporary Buffer and are fine for most applications. 14 | type Buffer struct { 15 | buf []byte // encode/decode byte stream 16 | index int // read point 17 | } 18 | 19 | // NewBuffer allocates a new Buffer and initializes its internal data to 20 | // the contents of the argument slice. 21 | func NewBuffer(e []byte) *Buffer { 22 | return &Buffer{buf: e} 23 | } 24 | 25 | func NewBufferBySize(size int) *Buffer { 26 | data := make([]byte, 0, size) 27 | return NewBuffer(data) 28 | } 29 | 30 | // Reset resets the Buffer, ready for marshaling a new protocol buffer. 31 | func (self *Buffer) Reset() { 32 | self.buf = self.buf[0:0] // for reading/writing 33 | self.index = 0 // for reading 34 | } 35 | 36 | // SetBuf replaces the internal buffer with the slice, 37 | // ready for unmarshaling the contents of the slice. 38 | func (self *Buffer) SetBuf(s []byte) { 39 | self.buf = s 40 | self.index = 0 41 | } 42 | 43 | // Bytes returns the contents of the Buffer. 44 | func (self *Buffer) Bytes() []byte { return self.buf } 45 | 46 | func (self *Buffer) ConsumeBytes(size int) (ret []byte) { 47 | ret = self.buf[self.index : self.index+size] 48 | 49 | self.index += size 50 | 51 | return 52 | } 53 | 54 | func (self *Buffer) BytesRemains() int { 55 | 56 | return len(self.buf) - self.index 57 | } 58 | 59 | // EncodeVarint writes a varint-encoded integer to the Buffer. 60 | // This is the format for the 61 | // int32, int64, uint32, uint64, bool, and enum 62 | // protocol buffer types. 63 | func (self *Buffer) EncodeVarint(x uint64) error { 64 | for x >= 1<<7 { 65 | self.buf = append(self.buf, uint8(x&0x7f|0x80)) 66 | x >>= 7 67 | } 68 | self.buf = append(self.buf, uint8(x)) 69 | return nil 70 | } 71 | 72 | // EncodeFixed64 writes a 64-bit integer to the Buffer. 73 | // This is the format for the 74 | // fixed64, sfixed64, and double protocol buffer types. 75 | func (self *Buffer) EncodeFixed64(x uint64) error { 76 | self.buf = append(self.buf, 77 | uint8(x), 78 | uint8(x>>8), 79 | uint8(x>>16), 80 | uint8(x>>24), 81 | uint8(x>>32), 82 | uint8(x>>40), 83 | uint8(x>>48), 84 | uint8(x>>56)) 85 | return nil 86 | } 87 | 88 | // EncodeFixed32 writes a 32-bit integer to the Buffer. 89 | // This is the format for the 90 | // fixed32, sfixed32, and float protocol buffer types. 91 | func (self *Buffer) EncodeFixed32(x uint64) error { 92 | self.buf = append(self.buf, 93 | uint8(x), 94 | uint8(x>>8), 95 | uint8(x>>16), 96 | uint8(x>>24)) 97 | return nil 98 | } 99 | 100 | // EncodeZigzag64 writes a zigzag-encoded 64-bit integer 101 | // to the Buffer. 102 | // This is the format used for the sint64 protocol buffer type. 103 | func (self *Buffer) EncodeZigzag64(x uint64) error { 104 | // use signed number to get arithmetic right shift. 105 | return self.EncodeVarint(uint64((x << 1) ^ uint64(int64(x)>>63))) 106 | } 107 | 108 | // EncodeZigzag32 writes a zigzag-encoded 32-bit integer 109 | // to the Buffer. 110 | // This is the format used for the sint32 protocol buffer type. 111 | func (self *Buffer) EncodeZigzag32(x uint64) error { 112 | // use signed number to get arithmetic right shift. 113 | return self.EncodeVarint(uint64((uint32(x) << 1) ^ uint32(int32(x)>>31))) 114 | } 115 | 116 | // EncodeRawBytes writes a count-delimited byte buffer to the Buffer. 117 | // This is the format used for the bytes protocol buffer 118 | // type and for embedded messages. 119 | func (self *Buffer) EncodeRawBytes(b []byte) error { 120 | self.EncodeVarint(uint64(len(b))) 121 | self.buf = append(self.buf, b...) 122 | return nil 123 | } 124 | 125 | // EncodeStringBytes writes an encoded string to the Buffer. 126 | // This is the format used for the proto2 string type. 127 | func (self *Buffer) EncodeStringBytes(s string) error { 128 | self.EncodeVarint(uint64(len(s))) 129 | self.buf = append(self.buf, s...) 130 | return nil 131 | } 132 | 133 | // errOverflow is returned when an integer is too large to be represented. 134 | var errOverflow = errors.New("proto: integer overflow") 135 | 136 | func (self *Buffer) decodeVarintSlow() (x uint64, err error) { 137 | i := self.index 138 | l := len(self.buf) 139 | 140 | for shift := uint(0); shift < 64; shift += 7 { 141 | if i >= l { 142 | err = io.ErrUnexpectedEOF 143 | return 144 | } 145 | b := self.buf[i] 146 | i++ 147 | x |= (uint64(b) & 0x7F) << shift 148 | if b < 0x80 { 149 | self.index = i 150 | return 151 | } 152 | } 153 | 154 | // The number is too large to represent in a 64-bit value. 155 | err = errOverflow 156 | return 157 | } 158 | 159 | // DecodeVarint reads a varint-encoded integer from the Buffer. 160 | // This is the format for the 161 | // int32, int64, uint32, uint64, bool, and enum 162 | // protocol buffer types. 163 | func (self *Buffer) DecodeVarint() (x uint64, err error) { 164 | i := self.index 165 | buf := self.buf 166 | 167 | if i >= len(buf) { 168 | return 0, io.ErrUnexpectedEOF 169 | } else if buf[i] < 0x80 { 170 | self.index++ 171 | return uint64(buf[i]), nil 172 | } else if len(buf)-i < 10 { 173 | return self.decodeVarintSlow() 174 | } 175 | 176 | var b uint64 177 | // we already checked the first byte 178 | x = uint64(buf[i]) - 0x80 179 | i++ 180 | 181 | b = uint64(buf[i]) 182 | i++ 183 | x += b << 7 184 | if b&0x80 == 0 { 185 | goto done 186 | } 187 | x -= 0x80 << 7 188 | 189 | b = uint64(buf[i]) 190 | i++ 191 | x += b << 14 192 | if b&0x80 == 0 { 193 | goto done 194 | } 195 | x -= 0x80 << 14 196 | 197 | b = uint64(buf[i]) 198 | i++ 199 | x += b << 21 200 | if b&0x80 == 0 { 201 | goto done 202 | } 203 | x -= 0x80 << 21 204 | 205 | b = uint64(buf[i]) 206 | i++ 207 | x += b << 28 208 | if b&0x80 == 0 { 209 | goto done 210 | } 211 | x -= 0x80 << 28 212 | 213 | b = uint64(buf[i]) 214 | i++ 215 | x += b << 35 216 | if b&0x80 == 0 { 217 | goto done 218 | } 219 | x -= 0x80 << 35 220 | 221 | b = uint64(buf[i]) 222 | i++ 223 | x += b << 42 224 | if b&0x80 == 0 { 225 | goto done 226 | } 227 | x -= 0x80 << 42 228 | 229 | b = uint64(buf[i]) 230 | i++ 231 | x += b << 49 232 | if b&0x80 == 0 { 233 | goto done 234 | } 235 | x -= 0x80 << 49 236 | 237 | b = uint64(buf[i]) 238 | i++ 239 | x += b << 56 240 | if b&0x80 == 0 { 241 | goto done 242 | } 243 | x -= 0x80 << 56 244 | 245 | b = uint64(buf[i]) 246 | i++ 247 | x += b << 63 248 | if b&0x80 == 0 { 249 | goto done 250 | } 251 | 252 | return 0, errOverflow 253 | 254 | done: 255 | self.index = i 256 | return x, nil 257 | } 258 | 259 | // DecodeFixed64 reads a 64-bit integer from the Buffer. 260 | // This is the format for the 261 | // fixed64, sfixed64, and double protocol buffer types. 262 | func (self *Buffer) DecodeFixed64() (x uint64, err error) { 263 | // x, err already 0 264 | i := self.index + 8 265 | if i < 0 || i > len(self.buf) { 266 | err = io.ErrUnexpectedEOF 267 | return 268 | } 269 | self.index = i 270 | 271 | x = uint64(self.buf[i-8]) 272 | x |= uint64(self.buf[i-7]) << 8 273 | x |= uint64(self.buf[i-6]) << 16 274 | x |= uint64(self.buf[i-5]) << 24 275 | x |= uint64(self.buf[i-4]) << 32 276 | x |= uint64(self.buf[i-3]) << 40 277 | x |= uint64(self.buf[i-2]) << 48 278 | x |= uint64(self.buf[i-1]) << 56 279 | return 280 | } 281 | 282 | // DecodeFixed32 reads a 32-bit integer from the Buffer. 283 | // This is the format for the 284 | // fixed32, sfixed32, and float protocol buffer types. 285 | func (self *Buffer) DecodeFixed32() (x uint64, err error) { 286 | // x, err already 0 287 | i := self.index + 4 288 | if i < 0 || i > len(self.buf) { 289 | err = io.ErrUnexpectedEOF 290 | return 291 | } 292 | self.index = i 293 | 294 | x = uint64(self.buf[i-4]) 295 | x |= uint64(self.buf[i-3]) << 8 296 | x |= uint64(self.buf[i-2]) << 16 297 | x |= uint64(self.buf[i-1]) << 24 298 | return 299 | } 300 | 301 | // DecodeZigzag64 reads a zigzag-encoded 64-bit integer 302 | // from the Buffer. 303 | // This is the format used for the sint64 protocol buffer type. 304 | func (self *Buffer) DecodeZigzag64() (x uint64, err error) { 305 | x, err = self.DecodeVarint() 306 | if err != nil { 307 | return 308 | } 309 | x = (x >> 1) ^ uint64((int64(x&1)<<63)>>63) 310 | return 311 | } 312 | 313 | // DecodeZigzag32 reads a zigzag-encoded 32-bit integer 314 | // from the Buffer. 315 | // This is the format used for the sint32 protocol buffer type. 316 | func (self *Buffer) DecodeZigzag32() (x uint64, err error) { 317 | x, err = self.DecodeVarint() 318 | if err != nil { 319 | return 320 | } 321 | x = uint64((uint32(x) >> 1) ^ uint32((int32(x&1)<<31)>>31)) 322 | return 323 | } 324 | 325 | // DecodeRawBytes reads a count-delimited byte buffer from the Buffer. 326 | // This is the format used for the bytes protocol buffer 327 | // type and for embedded messages. 328 | func (self *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err error) { 329 | n, err := self.DecodeVarint() 330 | if err != nil { 331 | return nil, err 332 | } 333 | 334 | nb := int(n) 335 | if nb < 0 { 336 | return nil, fmt.Errorf("proto: bad byte length %d", nb) 337 | } 338 | end := self.index + nb 339 | if end < self.index || end > len(self.buf) { 340 | return nil, io.ErrUnexpectedEOF 341 | } 342 | 343 | if !alloc { 344 | // todo: check if can get more uses of alloc=false 345 | buf = self.buf[self.index:end] 346 | self.index += nb 347 | return 348 | } 349 | 350 | buf = make([]byte, nb) 351 | copy(buf, self.buf[self.index:]) 352 | self.index += nb 353 | return 354 | } 355 | 356 | // DecodeStringBytes reads an encoded string from the Buffer. 357 | // This is the format used for the proto2 string type. 358 | func (self *Buffer) DecodeStringBytes() (s string, err error) { 359 | buf, err := self.DecodeRawBytes(false) 360 | if err != nil { 361 | return 362 | } 363 | return string(buf), nil 364 | } 365 | -------------------------------------------------------------------------------- /api/golang/wire/err.go: -------------------------------------------------------------------------------- 1 | package wire 2 | 3 | import "errors" 4 | 5 | var ( 6 | ErrBadWireType = errors.New("bad wire type") 7 | ErrUnknownField = errors.New("unknown field") 8 | ErrBadBoolValue = errors.New("bad bool value") 9 | ) 10 | -------------------------------------------------------------------------------- /api/golang/wire/field_marshal.go: -------------------------------------------------------------------------------- 1 | package wire 2 | 3 | import ( 4 | "math" 5 | ) 6 | 7 | func MarshalBool(b *Buffer, fieldIndex uint64, value bool) error { 8 | 9 | if !value { 10 | return nil 11 | } 12 | 13 | b.EncodeVarint(MakeTag(fieldIndex, WireVarint)) 14 | 15 | if value { 16 | b.buf = append(b.buf, 1) 17 | } else { 18 | b.buf = append(b.buf, 0) 19 | } 20 | 21 | return nil 22 | } 23 | 24 | func MarshalInt32(b *Buffer, fieldIndex uint64, value int32) error { 25 | 26 | switch { 27 | case value > 0: 28 | b.EncodeVarint(MakeTag(fieldIndex, WireVarint)) 29 | b.EncodeVarint(uint64(value)) 30 | case value < 0: 31 | b.EncodeVarint(MakeTag(fieldIndex, WireFixed32)) 32 | b.EncodeFixed32(uint64(value)) 33 | } 34 | 35 | return nil 36 | } 37 | 38 | func MarshalUInt32(b *Buffer, fieldIndex uint64, value uint32) error { 39 | 40 | if value == 0 { 41 | return nil 42 | } 43 | 44 | b.EncodeVarint(MakeTag(fieldIndex, WireVarint)) 45 | b.EncodeVarint(uint64(value)) 46 | 47 | return nil 48 | } 49 | 50 | func MarshalInt64(b *Buffer, fieldIndex uint64, value int64) error { 51 | 52 | switch { 53 | case value > 0: 54 | b.EncodeVarint(MakeTag(fieldIndex, WireVarint)) 55 | b.EncodeVarint(uint64(value)) 56 | case value < 0: 57 | b.EncodeVarint(MakeTag(fieldIndex, WireFixed64)) 58 | b.EncodeFixed64(uint64(value)) 59 | } 60 | 61 | return nil 62 | } 63 | 64 | func MarshalUInt64(b *Buffer, fieldIndex uint64, value uint64) error { 65 | 66 | if value == 0 { 67 | return nil 68 | } 69 | 70 | b.EncodeVarint(MakeTag(fieldIndex, WireVarint)) 71 | b.EncodeVarint(value) 72 | 73 | return nil 74 | } 75 | 76 | func MarshalFloat32(b *Buffer, fieldIndex uint64, value float32) error { 77 | 78 | if value == 0 { 79 | return nil 80 | } 81 | 82 | b.EncodeVarint(MakeTag(fieldIndex, WireFixed32)) 83 | b.EncodeFixed32(uint64(math.Float32bits(value))) 84 | 85 | return nil 86 | } 87 | 88 | func MarshalFloat64(b *Buffer, fieldIndex uint64, value float64) error { 89 | 90 | if value == 0 { 91 | return nil 92 | } 93 | 94 | b.EncodeVarint(MakeTag(fieldIndex, WireFixed64)) 95 | b.EncodeFixed64(uint64(math.Float64bits(value))) 96 | 97 | return nil 98 | } 99 | 100 | func MarshalString(b *Buffer, fieldIndex uint64, value string) error { 101 | 102 | if value == "" { 103 | return nil 104 | } 105 | b.EncodeVarint(MakeTag(fieldIndex, WireBytes)) 106 | 107 | b.EncodeStringBytes(value) 108 | 109 | return nil 110 | } 111 | -------------------------------------------------------------------------------- /api/golang/wire/field_size.go: -------------------------------------------------------------------------------- 1 | package wire 2 | 3 | func SizeBool(fieldIndex uint64, value bool) int { 4 | 5 | if value == false { 6 | return 0 7 | } 8 | 9 | return SizeVarint(MakeTag(fieldIndex, WireVarint)) + 1 10 | } 11 | 12 | func SizeInt32(fieldIndex uint64, value int32) int { 13 | 14 | switch { 15 | case value > 0: 16 | return SizeVarint(MakeTag(fieldIndex, WireVarint)) + SizeVarint(uint64(value)) 17 | case value < 0: 18 | return SizeVarint(MakeTag(fieldIndex, WireFixed32)) + 4 19 | default: 20 | return 0 21 | } 22 | } 23 | 24 | func SizeUInt32(fieldIndex uint64, value uint32) int { 25 | 26 | if value == 0 { 27 | return 0 28 | } 29 | 30 | return SizeVarint(MakeTag(fieldIndex, WireVarint)) + SizeVarint(uint64(value)) 31 | } 32 | 33 | func SizeInt64(fieldIndex uint64, value int64) int { 34 | 35 | switch { 36 | case value > 0: 37 | return SizeVarint(MakeTag(fieldIndex, WireVarint)) + SizeVarint(uint64(value)) 38 | case value < 0: 39 | return SizeVarint(MakeTag(fieldIndex, WireFixed64)) + 8 40 | default: 41 | return 0 42 | } 43 | } 44 | 45 | func SizeUInt64(fieldIndex uint64, value uint64) int { 46 | 47 | if value == 0 { 48 | return 0 49 | } 50 | 51 | return SizeVarint(MakeTag(fieldIndex, WireVarint)) + SizeVarint(uint64(value)) 52 | } 53 | 54 | func SizeFloat32(fieldIndex uint64, value float32) int { 55 | 56 | if value == 0 { 57 | return 0 58 | } 59 | 60 | return SizeVarint(MakeTag(fieldIndex, WireFixed32)) + 4 61 | } 62 | 63 | func SizeFloat64(fieldIndex uint64, value float64) int { 64 | 65 | if value == 0 { 66 | return 0 67 | } 68 | 69 | return SizeVarint(MakeTag(fieldIndex, WireFixed64)) + 8 70 | } 71 | 72 | func SizeString(fieldIndex uint64, value string) int { 73 | 74 | size := len(value) 75 | 76 | if size == 0 { 77 | return 0 78 | } 79 | 80 | return SizeVarint(MakeTag(fieldIndex, WireVarint)) + SizeVarint(uint64(size)) + size 81 | } 82 | -------------------------------------------------------------------------------- /api/golang/wire/field_unmarshal.go: -------------------------------------------------------------------------------- 1 | package wire 2 | 3 | import ( 4 | "io" 5 | "math" 6 | ) 7 | 8 | func UnmarshalBool(b *Buffer, wt WireType) (bool, error) { 9 | switch wt { 10 | case WireVarint: 11 | v, err := b.DecodeVarint() 12 | if err != nil { 13 | return false, err 14 | } 15 | return v != 0, nil 16 | default: 17 | return false, ErrBadWireType 18 | } 19 | } 20 | 21 | func UnmarshalInt32(b *Buffer, wt WireType) (int32, error) { 22 | 23 | switch wt { 24 | case WireVarint: 25 | v, err := b.DecodeVarint() 26 | if err != nil { 27 | return 0, err 28 | } 29 | return int32(v), nil 30 | 31 | case WireFixed32: 32 | v, err := b.DecodeFixed32() 33 | if err != nil { 34 | return 0, err 35 | } 36 | 37 | return int32(v), nil 38 | 39 | default: 40 | return 0, ErrBadWireType 41 | } 42 | } 43 | 44 | func UnmarshalUInt32(b *Buffer, wt WireType) (uint32, error) { 45 | 46 | switch wt { 47 | case WireVarint: 48 | v, err := b.DecodeVarint() 49 | if err != nil { 50 | return 0, err 51 | } 52 | 53 | return uint32(v), nil 54 | default: 55 | return 0, ErrBadWireType 56 | } 57 | } 58 | 59 | func UnmarshalInt64(b *Buffer, wt WireType) (int64, error) { 60 | 61 | switch wt { 62 | case WireVarint: 63 | v, err := b.DecodeVarint() 64 | if err != nil { 65 | return 0, err 66 | } 67 | return int64(v), nil 68 | 69 | case WireFixed64: 70 | v, err := b.DecodeFixed64() 71 | if err != nil { 72 | return 0, err 73 | } 74 | 75 | return int64(v), nil 76 | default: 77 | return 0, ErrBadWireType 78 | } 79 | } 80 | 81 | func UnmarshalUInt64(b *Buffer, wt WireType) (uint64, error) { 82 | 83 | switch wt { 84 | case WireVarint: 85 | v, err := b.DecodeVarint() 86 | if err != nil { 87 | return 0, err 88 | } 89 | return v, nil 90 | default: 91 | return 0, ErrBadWireType 92 | } 93 | } 94 | 95 | func UnmarshalFloat32(b *Buffer, wt WireType) (float32, error) { 96 | 97 | switch wt { 98 | case WireFixed32: 99 | v, err := b.DecodeFixed32() 100 | if err != nil { 101 | return 0, err 102 | } 103 | 104 | return math.Float32frombits(uint32(v)), nil 105 | default: 106 | return 0, ErrBadWireType 107 | } 108 | 109 | } 110 | 111 | func UnmarshalFloat64(b *Buffer, wt WireType) (float64, error) { 112 | 113 | switch wt { 114 | case WireFixed64: 115 | v, err := b.DecodeFixed64() 116 | if err != nil { 117 | return 0, err 118 | } 119 | 120 | return math.Float64frombits(uint64(v)), nil 121 | default: 122 | return 0, ErrBadWireType 123 | } 124 | } 125 | 126 | func UnmarshalString(b *Buffer, wt WireType) (string, error) { 127 | switch wt { 128 | case WireBytes: 129 | v, err := b.DecodeStringBytes() 130 | if err != nil { 131 | return "", err 132 | } 133 | 134 | return v, nil 135 | default: 136 | return "", ErrBadWireType 137 | } 138 | } 139 | 140 | func skipField(b *Buffer, wt WireType) error { 141 | 142 | switch wt { 143 | case WireVarint: 144 | _, err := b.DecodeVarint() 145 | return err 146 | case WireBytes: 147 | size, err := b.DecodeVarint() 148 | 149 | if b.BytesRemains() < int(size) { 150 | return io.ErrUnexpectedEOF 151 | } 152 | 153 | b.ConsumeBytes(int(size)) 154 | return err 155 | case WireZigzag32: 156 | _, err := b.DecodeZigzag32() 157 | return err 158 | case WireZigzag64: 159 | _, err := b.DecodeZigzag64() 160 | return err 161 | case WireFixed32: 162 | _, err := b.DecodeFixed32() 163 | return err 164 | case WireFixed64: 165 | _, err := b.DecodeFixed64() 166 | return err 167 | default: 168 | return ErrBadWireType 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /api/golang/wire/slice_marshal.go: -------------------------------------------------------------------------------- 1 | package wire 2 | 3 | import ( 4 | "math" 5 | ) 6 | 7 | func MarshalBytes(b *Buffer, fieldIndex uint64, value []byte) error { 8 | 9 | size := len(value) 10 | if size == 0 { 11 | return nil 12 | } 13 | 14 | b.EncodeVarint(MakeTag(fieldIndex, WireBytes)) 15 | 16 | // 因为bool每一个value都是1个字节,size=1*count 17 | b.EncodeVarint(uint64(size)) 18 | b.buf = append(b.buf, value...) 19 | 20 | return nil 21 | } 22 | 23 | func MarshalBoolSlice(b *Buffer, fieldIndex uint64, value []bool) error { 24 | 25 | size := len(value) 26 | if size == 0 { 27 | return nil 28 | } 29 | 30 | b.EncodeVarint(MakeTag(fieldIndex, WireBytes)) 31 | 32 | // 因为bool每一个value都是1个字节,size=1*count 33 | b.EncodeVarint(uint64(size)) 34 | 35 | for _, v := range value { 36 | 37 | if v { 38 | b.buf = append(b.buf, 1) 39 | } else { 40 | b.buf = append(b.buf, 0) 41 | } 42 | } 43 | 44 | return nil 45 | } 46 | 47 | func MarshalInt32Slice(b *Buffer, fieldIndex uint64, value []int32) error { 48 | 49 | if len(value) == 0 { 50 | return nil 51 | } 52 | 53 | b.EncodeVarint(MakeTag(fieldIndex, WireBytes)) 54 | 55 | // 计算变长单元大小 56 | var size int 57 | for _, v := range value { 58 | size += SizeVarint(uint64(v)) 59 | } 60 | 61 | // 写入长度 62 | b.EncodeVarint(uint64(size)) 63 | for _, v := range value { 64 | b.EncodeVarint(uint64(v)) // TODO 负数会导致编码很大 65 | } 66 | 67 | return nil 68 | } 69 | 70 | func MarshalUInt32Slice(b *Buffer, fieldIndex uint64, value []uint32) error { 71 | 72 | if len(value) == 0 { 73 | return nil 74 | } 75 | 76 | b.EncodeVarint(MakeTag(fieldIndex, WireBytes)) 77 | 78 | // 计算变长单元大小 79 | var size int 80 | for _, v := range value { 81 | size += SizeVarint(uint64(v)) 82 | } 83 | 84 | // 写入长度 85 | b.EncodeVarint(uint64(size)) 86 | for _, v := range value { 87 | b.EncodeVarint(uint64(v)) 88 | } 89 | 90 | return nil 91 | } 92 | 93 | func MarshalInt64Slice(b *Buffer, fieldIndex uint64, value []int64) error { 94 | 95 | if len(value) == 0 { 96 | return nil 97 | } 98 | 99 | b.EncodeVarint(MakeTag(fieldIndex, WireBytes)) 100 | 101 | // 计算变长单元大小 102 | var size int 103 | for _, v := range value { 104 | size += SizeVarint(uint64(v)) 105 | } 106 | 107 | // 写入长度 108 | b.EncodeVarint(uint64(size)) 109 | for _, v := range value { 110 | b.EncodeVarint(uint64(v)) 111 | } 112 | 113 | return nil 114 | } 115 | 116 | func MarshalUInt64Slice(b *Buffer, fieldIndex uint64, value []uint64) error { 117 | 118 | if len(value) == 0 { 119 | return nil 120 | } 121 | 122 | b.EncodeVarint(MakeTag(fieldIndex, WireBytes)) 123 | 124 | // 计算变长单元大小 125 | var size int 126 | for _, v := range value { 127 | size += SizeVarint(uint64(v)) 128 | } 129 | 130 | // 写入长度 131 | b.EncodeVarint(uint64(size)) 132 | for _, v := range value { 133 | b.EncodeVarint(uint64(v)) 134 | } 135 | 136 | return nil 137 | } 138 | 139 | func MarshalStringSlice(b *Buffer, fieldIndex uint64, value []string) error { 140 | 141 | if len(value) == 0 { 142 | return nil 143 | } 144 | 145 | for _, v := range value { 146 | b.EncodeVarint(MakeTag(fieldIndex, WireBytes)) 147 | b.EncodeStringBytes(v) 148 | } 149 | 150 | return nil 151 | } 152 | 153 | func MarshalFloat32Slice(b *Buffer, fieldIndex uint64, value []float32) error { 154 | 155 | count := len(value) 156 | if count == 0 { 157 | return nil 158 | } 159 | 160 | b.EncodeVarint(MakeTag(fieldIndex, WireBytes)) 161 | 162 | // 写入长度 163 | b.EncodeVarint(uint64(count * 4)) 164 | 165 | for _, v := range value { 166 | b.EncodeFixed32(uint64(math.Float32bits(v))) 167 | } 168 | 169 | return nil 170 | } 171 | 172 | func MarshalFloat64Slice(b *Buffer, fieldIndex uint64, value []float64) error { 173 | 174 | count := len(value) 175 | if count == 0 { 176 | return nil 177 | } 178 | 179 | b.EncodeVarint(MakeTag(fieldIndex, WireBytes)) 180 | 181 | // 写入长度 182 | b.EncodeVarint(uint64(count * 8)) 183 | 184 | for _, v := range value { 185 | b.EncodeFixed64(uint64(math.Float64bits(v))) 186 | } 187 | 188 | return nil 189 | } 190 | -------------------------------------------------------------------------------- /api/golang/wire/slice_size.go: -------------------------------------------------------------------------------- 1 | package wire 2 | 3 | func SizeBytes(fieldIndex uint64, value []byte) int { 4 | 5 | count := len(value) 6 | if count == 0 { 7 | return 0 8 | } 9 | 10 | size := count * 1 11 | 12 | return SizeVarint(MakeTag(fieldIndex, WireBytes)) + SizeVarint(uint64(size)) + size 13 | } 14 | 15 | func SizeBoolSlice(fieldIndex uint64, value []bool) int { 16 | 17 | count := len(value) 18 | if count == 0 { 19 | return 0 20 | } 21 | 22 | size := count * 1 23 | 24 | return SizeVarint(MakeTag(fieldIndex, WireBytes)) + SizeVarint(uint64(size)) + size 25 | } 26 | 27 | func SizeInt32Slice(fieldIndex uint64, value []int32) (ret int) { 28 | 29 | count := len(value) 30 | if count == 0 { 31 | return 0 32 | } 33 | 34 | ret = SizeVarint(MakeTag(fieldIndex, WireBytes)) 35 | 36 | // 后部分的长度 37 | size := 0 38 | for _, v := range value { 39 | size += SizeVarint(uint64(v)) 40 | } 41 | 42 | ret += SizeVarint(uint64(size)) 43 | 44 | ret += size 45 | 46 | return 47 | } 48 | 49 | func SizeUInt32Slice(fieldIndex uint64, value []uint32) (ret int) { 50 | 51 | count := len(value) 52 | if count == 0 { 53 | return 0 54 | } 55 | 56 | ret = SizeVarint(MakeTag(fieldIndex, WireBytes)) 57 | 58 | // 后部分的长度 59 | size := 0 60 | for _, v := range value { 61 | size += SizeVarint(uint64(v)) 62 | } 63 | 64 | ret += SizeVarint(uint64(size)) 65 | 66 | ret += size 67 | 68 | return 69 | } 70 | 71 | func SizeInt64Slice(fieldIndex uint64, value []int64) (ret int) { 72 | 73 | count := len(value) 74 | if count == 0 { 75 | return 0 76 | } 77 | 78 | ret = SizeVarint(MakeTag(fieldIndex, WireBytes)) 79 | 80 | // 后部分的长度 81 | size := 0 82 | for _, v := range value { 83 | size += SizeVarint(uint64(v)) 84 | } 85 | 86 | ret += SizeVarint(uint64(size)) 87 | 88 | ret += size 89 | 90 | return 91 | } 92 | 93 | func SizeUInt64Slice(fieldIndex uint64, value []uint64) (ret int) { 94 | 95 | count := len(value) 96 | if count == 0 { 97 | return 0 98 | } 99 | 100 | ret = SizeVarint(MakeTag(fieldIndex, WireBytes)) 101 | 102 | // 后部分的长度 103 | size := 0 104 | for _, v := range value { 105 | size += SizeVarint(uint64(v)) 106 | } 107 | 108 | ret += SizeVarint(uint64(size)) 109 | 110 | ret += size 111 | 112 | return 113 | } 114 | 115 | func SizeStringSlice(fieldIndex uint64, value []string) (ret int) { 116 | 117 | if len(value) == 0 { 118 | return 0 119 | } 120 | 121 | for _, v := range value { 122 | ret += SizeString(fieldIndex, v) 123 | } 124 | 125 | return 126 | } 127 | 128 | func SizeFloat32Slice(fieldIndex uint64, value []float32) (ret int) { 129 | 130 | count := len(value) 131 | if count == 0 { 132 | return 0 133 | } 134 | 135 | ret = SizeVarint(MakeTag(fieldIndex, WireBytes)) 136 | 137 | size := count * 4 138 | 139 | ret += SizeVarint(uint64(size)) 140 | 141 | ret += size 142 | 143 | return 144 | } 145 | 146 | func SizeFloat64Slice(fieldIndex uint64, value []float64) (ret int) { 147 | 148 | count := len(value) 149 | if count == 0 { 150 | return 0 151 | } 152 | 153 | ret = SizeVarint(MakeTag(fieldIndex, WireBytes)) 154 | 155 | size := count * 8 156 | 157 | ret += SizeVarint(uint64(size)) 158 | 159 | ret += size 160 | 161 | return 162 | } 163 | -------------------------------------------------------------------------------- /api/golang/wire/slice_unmarshal.go: -------------------------------------------------------------------------------- 1 | package wire 2 | 3 | import ( 4 | "io" 5 | ) 6 | 7 | func UnmarshalBytes(b *Buffer, wt WireType) ([]byte, error) { 8 | 9 | switch wt { 10 | case WireBytes: 11 | size, err := b.DecodeVarint() 12 | if err != nil { 13 | return nil, err 14 | } 15 | 16 | if b.BytesRemains() < int(size) { 17 | return nil, io.ErrUnexpectedEOF 18 | } 19 | 20 | return b.ConsumeBytes(int(size)), nil 21 | 22 | default: 23 | return nil, ErrBadWireType 24 | } 25 | } 26 | 27 | func UnmarshalBoolSlice(b *Buffer, wt WireType) ([]bool, error) { 28 | switch wt { 29 | case WireBytes: 30 | count, err := b.DecodeVarint() 31 | if err != nil { 32 | return nil, err 33 | } 34 | 35 | if b.BytesRemains() < int(int(count)) { 36 | return nil, io.ErrUnexpectedEOF 37 | } 38 | 39 | var ret []bool 40 | for _, element := range b.ConsumeBytes(int(count)) { 41 | 42 | switch element { 43 | case 0: 44 | ret = append(ret, false) 45 | case 1: 46 | ret = append(ret, true) 47 | default: 48 | return nil, ErrBadBoolValue 49 | } 50 | } 51 | 52 | return ret, nil 53 | 54 | default: 55 | return nil, ErrBadWireType 56 | } 57 | } 58 | 59 | func UnmarshalInt32Slice(b *Buffer, wt WireType) ([]int32, error) { 60 | 61 | switch wt { 62 | case WireBytes: 63 | size, err := b.DecodeVarint() 64 | if err != nil { 65 | return nil, err 66 | } 67 | 68 | if b.BytesRemains() < int(size) { 69 | return nil, io.ErrUnexpectedEOF 70 | } 71 | 72 | limitBuffer := NewBuffer(b.ConsumeBytes(int(size))) 73 | 74 | var ret []int32 75 | for limitBuffer.BytesRemains() > 0 { 76 | var element int32 77 | element, err = UnmarshalInt32(limitBuffer, WireVarint) 78 | if err != nil { 79 | return nil, err 80 | } 81 | 82 | ret = append(ret, element) 83 | } 84 | 85 | return ret, nil 86 | 87 | default: 88 | return nil, ErrBadWireType 89 | } 90 | } 91 | 92 | func UnmarshalUInt32Slice(b *Buffer, wt WireType) ([]uint32, error) { 93 | 94 | switch wt { 95 | case WireBytes: 96 | size, err := b.DecodeVarint() 97 | if err != nil { 98 | return nil, err 99 | } 100 | 101 | if b.BytesRemains() < int(size) { 102 | return nil, io.ErrUnexpectedEOF 103 | } 104 | 105 | limitBuffer := NewBuffer(b.ConsumeBytes(int(size))) 106 | 107 | var ret []uint32 108 | for limitBuffer.BytesRemains() > 0 { 109 | var element uint32 110 | element, err = UnmarshalUInt32(limitBuffer, WireVarint) 111 | if err != nil { 112 | return nil, err 113 | } 114 | 115 | ret = append(ret, element) 116 | } 117 | 118 | return ret, nil 119 | 120 | default: 121 | return nil, ErrBadWireType 122 | } 123 | } 124 | 125 | func UnmarshalInt64Slice(b *Buffer, wt WireType) ([]int64, error) { 126 | 127 | switch wt { 128 | case WireBytes: 129 | size, err := b.DecodeVarint() 130 | if err != nil { 131 | return nil, err 132 | } 133 | 134 | if b.BytesRemains() < int(size) { 135 | return nil, io.ErrUnexpectedEOF 136 | } 137 | 138 | limitBuffer := NewBuffer(b.ConsumeBytes(int(size))) 139 | 140 | var ret []int64 141 | for limitBuffer.BytesRemains() > 0 { 142 | var element int64 143 | element, err = UnmarshalInt64(limitBuffer, WireVarint) 144 | if err != nil { 145 | return nil, err 146 | } 147 | 148 | ret = append(ret, element) 149 | } 150 | return ret, nil 151 | 152 | default: 153 | return nil, ErrBadWireType 154 | } 155 | } 156 | 157 | func UnmarshalUInt64Slice(b *Buffer, wt WireType) ([]uint64, error) { 158 | 159 | switch wt { 160 | case WireBytes: 161 | size, err := b.DecodeVarint() 162 | if err != nil { 163 | return nil, err 164 | } 165 | 166 | if b.BytesRemains() < int(size) { 167 | return nil, io.ErrUnexpectedEOF 168 | } 169 | 170 | limitBuffer := NewBuffer(b.ConsumeBytes(int(size))) 171 | 172 | var ret []uint64 173 | for limitBuffer.BytesRemains() > 0 { 174 | var element uint64 175 | element, err = UnmarshalUInt64(limitBuffer, WireVarint) 176 | if err != nil { 177 | return nil, err 178 | } 179 | 180 | ret = append(ret, element) 181 | } 182 | 183 | return ret, nil 184 | 185 | default: 186 | return nil, ErrBadWireType 187 | } 188 | } 189 | 190 | func UnmarshalStringSlice(b *Buffer, wt WireType) ([]string, error) { 191 | switch wt { 192 | case WireBytes: 193 | v, err := b.DecodeStringBytes() 194 | if err != nil { 195 | return nil, err 196 | } 197 | 198 | return []string{v}, nil 199 | default: 200 | return nil, ErrBadWireType 201 | } 202 | } 203 | 204 | func UnmarshalFloat32Slice(b *Buffer, wt WireType) ([]float32, error) { 205 | 206 | switch wt { 207 | case WireBytes: 208 | size, err := b.DecodeVarint() 209 | if err != nil { 210 | return nil, err 211 | } 212 | 213 | if b.BytesRemains() < int(size) { 214 | return nil, io.ErrUnexpectedEOF 215 | } 216 | 217 | limitBuffer := NewBuffer(b.ConsumeBytes(int(size))) 218 | 219 | var ret []float32 220 | for limitBuffer.BytesRemains() > 0 { 221 | var element float32 222 | element, err = UnmarshalFloat32(limitBuffer, WireFixed32) 223 | if err != nil { 224 | return nil, err 225 | } 226 | 227 | ret = append(ret, element) 228 | } 229 | 230 | return ret, nil 231 | 232 | default: 233 | return nil, ErrBadWireType 234 | } 235 | } 236 | 237 | func UnmarshalFloat64Slice(b *Buffer, wt WireType) ([]float64, error) { 238 | 239 | switch wt { 240 | case WireBytes: 241 | size, err := b.DecodeVarint() 242 | if err != nil { 243 | return nil, err 244 | } 245 | 246 | if b.BytesRemains() < int(size) { 247 | return nil, io.ErrUnexpectedEOF 248 | } 249 | 250 | limitBuffer := NewBuffer(b.ConsumeBytes(int(size))) 251 | 252 | var ret []float64 253 | for limitBuffer.BytesRemains() > 0 { 254 | var element float64 255 | element, err = UnmarshalFloat64(limitBuffer, WireFixed64) 256 | if err != nil { 257 | return nil, err 258 | } 259 | 260 | ret = append(ret, element) 261 | } 262 | 263 | return ret, nil 264 | 265 | default: 266 | return nil, ErrBadWireType 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /api/golang/wire/struct.go: -------------------------------------------------------------------------------- 1 | package wire 2 | 3 | import ( 4 | "io" 5 | "reflect" 6 | ) 7 | 8 | type Struct interface { 9 | Marshal(buffer *Buffer) error 10 | 11 | Unmarshal(buffer *Buffer, fieldIndex uint64, wt WireType) error 12 | 13 | Size() int 14 | } 15 | 16 | func MarshalStruct(b *Buffer, fieldIndex uint64, msg Struct) error { 17 | 18 | structValue := reflect.ValueOf(msg) 19 | 20 | // *MyType被Message包裹后,判断不为nil 21 | if structValue.IsNil() { 22 | return nil 23 | } 24 | 25 | size := msg.Size() 26 | if size == 0 { 27 | return nil 28 | } 29 | 30 | b.EncodeVarint(MakeTag(fieldIndex, WireBytes)) 31 | 32 | b.EncodeVarint(uint64(size)) 33 | 34 | return msg.Marshal(b) 35 | } 36 | 37 | func SizeStruct(fieldIndex uint64, msg Struct) int { 38 | 39 | structValue := reflect.ValueOf(msg) 40 | 41 | // *MyType被Message包裹后,判断不为nil 42 | if structValue.IsNil() { 43 | return 0 44 | } 45 | 46 | size := msg.Size() 47 | 48 | if size == 0 { 49 | return 0 50 | } 51 | 52 | return SizeVarint(MakeTag(fieldIndex, WireVarint)) + SizeVarint(uint64(size)) + size 53 | } 54 | 55 | func UnmarshalStructObject(b *Buffer, msg Struct) error { 56 | 57 | for b.BytesRemains() > 0 { 58 | wireTag, err := b.DecodeVarint() 59 | 60 | if err != nil { 61 | return err 62 | } 63 | 64 | fieldIndex, wt := ParseTag(wireTag) 65 | 66 | err = msg.Unmarshal(b, fieldIndex, wt) 67 | 68 | if err == ErrUnknownField { 69 | err = skipField(b, wt) 70 | } 71 | 72 | if err != nil { 73 | return err 74 | } 75 | } 76 | 77 | return nil 78 | } 79 | 80 | func UnmarshalStruct(b *Buffer, wt WireType, msgPtr Struct) error { 81 | switch wt { 82 | case WireBytes: 83 | size, err := b.DecodeVarint() 84 | if err != nil { 85 | return err 86 | } 87 | 88 | if b.BytesRemains() < int(size) { 89 | return io.ErrUnexpectedEOF 90 | } 91 | 92 | limitBuffer := NewBuffer(b.ConsumeBytes(int(size))) 93 | 94 | return UnmarshalStructObject(limitBuffer, msgPtr) 95 | 96 | default: 97 | return ErrBadWireType 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /api/golang/wire/variant.go: -------------------------------------------------------------------------------- 1 | package wire 2 | 3 | const maxVarintBytes = 10 // maximum length of a varint 4 | 5 | // EncodeVarint returns the varint encoding of x. 6 | // This is the format for the 7 | // int32, int64, uint32, uint64, bool, and enum 8 | // protocol buffer types. 9 | // Not used by the package itself, but helpful to clients 10 | // wishing to use the same encoding. 11 | func EncodeVarint(x uint64) []byte { 12 | var buf [maxVarintBytes]byte 13 | var n int 14 | for n = 0; x > 127; n++ { 15 | buf[n] = 0x80 | uint8(x&0x7F) 16 | x >>= 7 17 | } 18 | buf[n] = uint8(x) 19 | n++ 20 | return buf[0:n] 21 | } 22 | 23 | func DecodeVarint(buf []byte) (x uint64, n int) { 24 | for shift := uint(0); shift < 64; shift += 7 { 25 | if n >= len(buf) { 26 | return 0, 0 27 | } 28 | b := uint64(buf[n]) 29 | n++ 30 | x |= (b & 0x7F) << shift 31 | if (b & 0x80) == 0 { 32 | return x, n 33 | } 34 | } 35 | 36 | // The number is too large to represent in a 64-bit value. 37 | return 0, 0 38 | } 39 | 40 | // SizeVarint returns the varint encoding size of an integer. 41 | func SizeVarint(x uint64) int { 42 | switch { 43 | case x < 1<<7: 44 | return 1 45 | case x < 1<<14: 46 | return 2 47 | case x < 1<<21: 48 | return 3 49 | case x < 1<<28: 50 | return 4 51 | case x < 1<<35: 52 | return 5 53 | case x < 1<<42: 54 | return 6 55 | case x < 1<<49: 56 | return 7 57 | case x < 1<<56: 58 | return 8 59 | case x < 1<<63: 60 | return 9 61 | } 62 | return 10 63 | } 64 | 65 | func Zigzag32(x uint64) uint64 { 66 | 67 | return uint64((uint32(x) << 1) ^ uint32(int32(x)>>31)) 68 | } 69 | 70 | func Zigzag64(x uint64) uint64 { 71 | return uint64((x << 1) ^ uint64(int64(x)>>63)) 72 | } 73 | -------------------------------------------------------------------------------- /api/golang/wire/wiretype.go: -------------------------------------------------------------------------------- 1 | package wire 2 | 3 | type WireType = uint64 4 | 5 | const ( 6 | WireVarint WireType = iota + 1 // int32, int64, uint32, uint64, bool, enum 7 | WireBytes // Length-delimited string, bytes, slice, struct 8 | WireZigzag32 // 32位负数 9 | WireZigzag64 // 64位负数 10 | WireFixed32 // 32位定长 float32 11 | WireFixed64 // 64位定长 float64 12 | ) 13 | 14 | func MakeTag(tag uint64, wt WireType) WireType { 15 | return uint64(tag)<<3 | uint64(wt) 16 | } 17 | 18 | func ParseTag(wireTag WireType) (tag uint64, wt WireType) { 19 | tag = wireTag >> 3 20 | wt = WireType(wireTag & 7) 21 | return 22 | } 23 | -------------------------------------------------------------------------------- /build/build.go: -------------------------------------------------------------------------------- 1 | package build 2 | 3 | import "fmt" 4 | 5 | var ( 6 | Version string 7 | GitCommit string 8 | BuildTime string 9 | ) 10 | 11 | func Print() { 12 | fmt.Println("Version: ", Version) 13 | fmt.Println("GitCommit: ", GitCommit) 14 | fmt.Println("BuildTime: ", BuildTime) 15 | } 16 | -------------------------------------------------------------------------------- /cmd/protoplus/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "github.com/davyxu/protoplus/build" 7 | _ "github.com/davyxu/protoplus/codegen" 8 | "github.com/davyxu/protoplus/gen" 9 | "github.com/davyxu/protoplus/gen/pbscheme" 10 | "github.com/davyxu/protoplus/gen/ppcpp" 11 | "github.com/davyxu/protoplus/gen/ppcs" 12 | "github.com/davyxu/protoplus/gen/ppgo" 13 | "github.com/davyxu/protoplus/gen/ppscheme" 14 | _ "github.com/davyxu/protoplus/gen/ppscheme" 15 | "github.com/davyxu/protoplus/gen/route" 16 | "github.com/davyxu/protoplus/model" 17 | "github.com/davyxu/protoplus/util" 18 | "os" 19 | ) 20 | 21 | var ( 22 | flagVersion = flag.Bool("version", false, "show version") 23 | 24 | flagPackage = flag.String("package", "", "package name in source files") 25 | flagClassBase = flag.String("classbase", "IProtoStruct", "struct inherite class type name in c#") 26 | flagCodec = flag.String("codec", "protoplus", "default codec in register entry") 27 | ) 28 | 29 | type GenEntry struct { 30 | name string 31 | usage string 32 | flagOutFile *string 33 | flagExecute *bool 34 | 35 | outfile func(ctx *gen.Context) error 36 | execute func(ctx *gen.Context) error 37 | } 38 | 39 | var ( 40 | genEntryList = []*GenEntry{ 41 | // 单文件生成 42 | //{name: "ppgo_out", usage: "output protoplus message serialize golang source file", outfile: ppgo.GenGo}, 43 | //{name: "ppcs_out", usage: "output protoplus message serialize csharp source file", outfile: ppcs.GenCS}, 44 | 45 | {name: "ppgoreg_out", usage: "output protoplus message register entry in golang", outfile: ppgo.GenGoReg}, 46 | {name: "ppcppreg_out", usage: "output protoplus message register entry in c++", outfile: ppcpp.GenCppReg}, 47 | {name: "ppcsreg_out", usage: "output protoplus message register entry in c#", outfile: ppcs.GenCSReg}, 48 | {name: "pbscheme_out", usage: "output google protobuf schema file as single file", outfile: pbscheme.GenProto}, 49 | 50 | // 文件夹输出 使用例子: protoc $(cat filelist.txt) 51 | {name: "pbscheme_dir", usage: "output google protobuf schema files into dir", outfile: pbscheme.GenProtoDir}, 52 | {name: "ppscheme_out", usage: "output protoplus scheme json file", outfile: ppscheme.GenJson}, 53 | {name: "route_out", usage: "output route table json file", outfile: route.GenJson}, 54 | 55 | // 输出类型描述 56 | {name: "ppscheme", usage: "output protoplus scheme json to std out", execute: ppscheme.OutputJson}, 57 | 58 | // 输出路由 59 | {name: "route", usage: "output route table json to std out", execute: route.OutputJson}, 60 | } 61 | ) 62 | 63 | func defineEntryFlag() { 64 | for _, entry := range genEntryList { 65 | if entry.outfile != nil { 66 | entry.flagOutFile = flag.String(entry.name, "", entry.usage) 67 | } 68 | if entry.execute != nil { 69 | entry.flagExecute = flag.Bool(entry.name, false, entry.usage) 70 | } 71 | 72 | } 73 | } 74 | 75 | func runEntry(ctx *gen.Context) error { 76 | for _, entry := range genEntryList { 77 | if entry.flagOutFile != nil && *entry.flagOutFile != "" { 78 | ctx.OutputFileName = *entry.flagOutFile 79 | 80 | fmt.Printf("[%s] %s\n", entry.name, ctx.OutputFileName) 81 | err := entry.outfile(ctx) 82 | if err != nil { 83 | return err 84 | } 85 | } 86 | 87 | if entry.flagExecute != nil && *entry.flagExecute { 88 | err := entry.execute(ctx) 89 | if err != nil { 90 | return err 91 | } 92 | } 93 | } 94 | 95 | return nil 96 | } 97 | 98 | func main() { 99 | 100 | defineEntryFlag() 101 | 102 | flag.Parse() 103 | 104 | // 版本 105 | if *flagVersion { 106 | build.Print() 107 | return 108 | } 109 | 110 | var err error 111 | var ctx gen.Context 112 | ctx.DescriptorSet = new(model.DescriptorSet) 113 | ctx.PackageName = *flagPackage 114 | ctx.ClassBase = *flagClassBase 115 | ctx.Codec = *flagCodec 116 | 117 | err = util.ParseFileList(ctx.DescriptorSet) 118 | 119 | if err != nil { 120 | fmt.Println(err) 121 | os.Exit(1) 122 | } 123 | 124 | err = runEntry(&ctx) 125 | if err != nil { 126 | fmt.Println(err) 127 | os.Exit(1) 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /codegen/codegen.go: -------------------------------------------------------------------------------- 1 | package codegen 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "fmt" 7 | "go/parser" 8 | "go/printer" 9 | "go/token" 10 | "io/ioutil" 11 | "os" 12 | "path/filepath" 13 | "strings" 14 | "text/template" 15 | ) 16 | 17 | type CodeGen struct { 18 | name string 19 | 20 | buffer bytes.Buffer 21 | 22 | err error 23 | 24 | tpl *template.Template 25 | } 26 | 27 | func (self *CodeGen) Data() []byte { 28 | return self.buffer.Bytes() 29 | } 30 | 31 | func (self *CodeGen) Error() error { 32 | return self.err 33 | } 34 | 35 | func (self *CodeGen) ParseTemplate(textTemplate string, modelData interface{}) *CodeGen { 36 | 37 | if self.err != nil { 38 | return self 39 | } 40 | 41 | _, self.err = self.tpl.Parse(textTemplate) 42 | if self.err != nil { 43 | return self 44 | } 45 | 46 | self.err = self.tpl.Execute(&self.buffer, modelData) 47 | if self.err != nil { 48 | return self 49 | } 50 | 51 | return self 52 | } 53 | 54 | func (self *CodeGen) RegisterTemplateFunc(funcMap template.FuncMap) *CodeGen { 55 | if self.err != nil { 56 | return self 57 | } 58 | 59 | self.tpl.Funcs(funcMap) 60 | return self 61 | } 62 | 63 | func (self *CodeGen) FormatGoCode() *CodeGen { 64 | 65 | if self.err != nil { 66 | return self 67 | } 68 | 69 | fset := token.NewFileSet() 70 | 71 | ast, err := parser.ParseFile(fset, "", self.buffer.Bytes(), parser.ParseComments) 72 | if err != nil { 73 | self.err = err 74 | return self 75 | } 76 | 77 | self.buffer.Reset() 78 | 79 | err = (&printer.Config{Mode: printer.TabIndent | printer.UseSpaces, Tabwidth: 8}).Fprint(&self.buffer, fset, ast) 80 | if err != nil { 81 | self.err = err 82 | return self 83 | } 84 | 85 | return self 86 | } 87 | 88 | func (self *CodeGen) Code() string { 89 | 90 | reader := bufio.NewReader(strings.NewReader(string(self.Data()))) 91 | 92 | var sb strings.Builder 93 | line := 0 94 | for { 95 | lineStr, err := reader.ReadString('\n') 96 | if err != nil { 97 | break 98 | } 99 | 100 | line++ 101 | sb.WriteString(fmt.Sprintf("%d: %s", line, lineStr)) 102 | } 103 | 104 | return sb.String() 105 | 106 | } 107 | 108 | func (self *CodeGen) WriteBytes(data *[]byte) *CodeGen { 109 | if self.err != nil { 110 | return self 111 | } 112 | 113 | *data = self.buffer.Bytes() 114 | 115 | return self 116 | } 117 | 118 | func (self *CodeGen) WriteOutputFile(outputFileName string) *CodeGen { 119 | 120 | if self.err != nil { 121 | return self 122 | } 123 | 124 | os.MkdirAll(filepath.Dir(outputFileName), 0755) 125 | 126 | self.err = ioutil.WriteFile(outputFileName, self.buffer.Bytes(), 0666) 127 | 128 | if self.err != nil { 129 | return self 130 | } 131 | 132 | return self 133 | 134 | } 135 | 136 | func NewCodeGen(name string) *CodeGen { 137 | 138 | self := &CodeGen{ 139 | tpl: template.New(name), 140 | } 141 | 142 | return self 143 | } 144 | -------------------------------------------------------------------------------- /codegen/funcmap.go: -------------------------------------------------------------------------------- 1 | package codegen 2 | 3 | import ( 4 | "github.com/davyxu/protoplus/model" 5 | "reflect" 6 | "strings" 7 | "text/template" 8 | ) 9 | 10 | var UsefulFunc = template.FuncMap{} 11 | 12 | func TagNumber(d *model.Descriptor, fd *model.FieldDescriptor) (tag int) { 13 | tag = -1 14 | for _, libfd := range d.Fields { 15 | 16 | if libfd.Tag != 0 { 17 | tag = libfd.Tag 18 | } else { 19 | tag++ 20 | } 21 | 22 | if libfd == fd { 23 | return tag 24 | } 25 | } 26 | 27 | return 0 28 | } 29 | 30 | func init() { 31 | UsefulFunc["ObjectLeadingComment"] = func(raw interface{}) (ret string) { 32 | 33 | d := raw.(*model.Descriptor) 34 | 35 | if d.Leading != "" { 36 | 37 | for index, line := range strings.Split(d.Leading, "\n") { 38 | if index > 0 { 39 | ret += "\n" 40 | } 41 | ret += "// " + line 42 | } 43 | 44 | return 45 | } 46 | 47 | return 48 | } 49 | 50 | UsefulFunc["FieldTrailingComment"] = func(raw interface{}) string { 51 | 52 | fd := raw.(*model.FieldDescriptor) 53 | 54 | if fd.Trailing != "" { 55 | return "// " + fd.Trailing 56 | } 57 | 58 | return "" 59 | } 60 | 61 | UsefulFunc["TagNumber"] = func(rawD, rawFD interface{}) (tag int) { 62 | d := rawD.(*model.Descriptor) 63 | fd := rawFD.(*model.FieldDescriptor) 64 | 65 | return TagNumber(d, fd) 66 | } 67 | 68 | // 类pb的协议都使用这个Tag生成 69 | UsefulFunc["PbTagNumber"] = func(rawD, rawFD interface{}) (tag int) { 70 | d := rawD.(*model.Descriptor) 71 | fd := rawFD.(*model.FieldDescriptor) 72 | 73 | // 枚举从0自动生成 74 | if d.Kind == model.Kind_Enum { 75 | return TagNumber(d, fd) 76 | } else { 77 | // 自动从1开始, pb不允许字段tag为0 78 | return TagNumber(d, fd) + 1 79 | } 80 | 81 | } 82 | 83 | UsefulFunc["IsMessage"] = IsMessage 84 | 85 | // 生成Json尾巴的逗号,rawIdx为当前遍历索引,rawSlice传切片 86 | UsefulFunc["GenJsonTailComma"] = func(rawIdx, rawSlice interface{}) string { 87 | 88 | index := rawIdx.(int) 89 | 90 | total := reflect.Indirect(reflect.ValueOf(rawSlice)).Len() 91 | 92 | if index < total-1 { 93 | return "," 94 | } 95 | 96 | return "" 97 | } 98 | 99 | } 100 | 101 | func IsMessage(d *model.Descriptor) bool { 102 | return d.TagValueInt("MsgID") > 0 || d.TagExists("AutoMsgID") 103 | } 104 | -------------------------------------------------------------------------------- /codegen/helper_cs.go: -------------------------------------------------------------------------------- 1 | package codegen 2 | 3 | import ( 4 | "github.com/davyxu/protoplus/model" 5 | ) 6 | 7 | func CSTypeName(fd *model.FieldDescriptor) string { 8 | switch fd.Type { 9 | case "int8": 10 | return "sbyte" 11 | case "int16": 12 | return "short" 13 | case "int32": 14 | return "int" 15 | case "int64": 16 | return "long" 17 | case "uint8": 18 | return "byte" 19 | case "uint16": 20 | return "ushort" 21 | case "uint32": 22 | return "uint" 23 | case "uint64": 24 | return "ulong" 25 | case "float32": 26 | return "float" 27 | case "float64": 28 | return "double" 29 | case "string": 30 | return "string" 31 | case "bool": 32 | return "bool" 33 | case "bytes": 34 | return "byte[]" 35 | default: 36 | return fd.Type 37 | } 38 | } 39 | 40 | func CSTypeNameFull(fd *model.FieldDescriptor) (ret string) { 41 | 42 | ret += CSTypeName(fd) 43 | 44 | if fd.Repeatd { 45 | ret += "[]" 46 | } 47 | 48 | return 49 | } 50 | 51 | func init() { 52 | UsefulFunc["CSTypeName"] = func(raw interface{}) (ret string) { 53 | 54 | fd := raw.(*model.FieldDescriptor) 55 | 56 | return CSTypeNameFull(fd) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /codegen/helper_go.go: -------------------------------------------------------------------------------- 1 | package codegen 2 | 3 | import ( 4 | "github.com/davyxu/protoplus/model" 5 | "strings" 6 | ) 7 | 8 | func ExportSymbolName(name string) string { 9 | return strings.ToUpper(string(name[0])) + name[1:] 10 | } 11 | 12 | func GoTypeName(fd *model.FieldDescriptor) string { 13 | switch fd.Type { 14 | case "bytes": 15 | return "[]byte" 16 | default: 17 | return fd.Type 18 | } 19 | } 20 | 21 | func init() { 22 | UsefulFunc["GoTypeName"] = func(raw interface{}) (ret string) { 23 | 24 | fd := raw.(*model.FieldDescriptor) 25 | 26 | if fd.Repeatd { 27 | ret += "[]" 28 | } 29 | 30 | ret += GoTypeName(fd) 31 | return 32 | } 33 | 34 | UsefulFunc["ExportSymbolName"] = ExportSymbolName 35 | 36 | UsefulFunc["GoFieldName"] = func(raw interface{}) string { 37 | 38 | fd := raw.(*model.FieldDescriptor) 39 | 40 | return ExportSymbolName(fd.Name) 41 | } 42 | 43 | UsefulFunc["GoStructTag"] = func(raw interface{}) string { 44 | 45 | fd := raw.(*model.FieldDescriptor) 46 | return fd.TagValueString("GoStructTag") 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /codegen/msgid.go: -------------------------------------------------------------------------------- 1 | package codegen 2 | 3 | import ( 4 | "github.com/davyxu/protoplus/model" 5 | "strings" 6 | ) 7 | 8 | // 字符串转为16位整形值 9 | func stringHash(s string) (hash uint16) { 10 | 11 | for _, c := range s { 12 | ch := uint16(c) 13 | hash = hash + ((hash) << 5) + ch + (ch << 7) 14 | } 15 | 16 | return 17 | } 18 | 19 | func StructMsgID(d *model.Descriptor) (msgid int) { 20 | if !IsMessage(d) { 21 | return 0 22 | } 23 | 24 | if d.Kind == model.Kind_Struct { 25 | msgid = d.TagValueInt("MsgID") 26 | } 27 | 28 | if msgid == 0 { 29 | // 这里不能引入packageName, 不同语言的package设置为不同, 造成消息id不一致 30 | msgid = int(stringHash(strings.ToLower(d.Name))) 31 | } 32 | 33 | return 34 | } 35 | 36 | func init() { 37 | UsefulFunc["StructMsgID"] = StructMsgID 38 | } 39 | -------------------------------------------------------------------------------- /csharp/Example/ProtoGen.cs: -------------------------------------------------------------------------------- 1 | // Generated by github.com/davyxu/protoplus 2 | // DO NOT EDIT! 3 | using System; 4 | using System.Collections.Generic; 5 | using ProtoPlus; 6 | 7 | namespace Proto 8 | { 9 | 10 | public enum MyEnum 11 | { 12 | 13 | Zero = 0, 14 | One = 1, 15 | Two = 2, 16 | } 17 | 18 | 19 | public partial class MyTypeMini : IProtoStruct 20 | { 21 | public string Str; 22 | public bool Bool; 23 | 24 | #region Serialize Code 25 | public void Init( ) 26 | { 27 | 28 | } 29 | 30 | public void Marshal(OutputStream stream) 31 | { 32 | stream.WriteString(1, Str ); 33 | stream.WriteBool(2, Bool ); 34 | } 35 | 36 | public int GetSize() 37 | { 38 | int size = 0; 39 | size += OutputStream.SizeString(1, Str); 40 | size += OutputStream.SizeBool(2, Bool); 41 | return size; 42 | } 43 | 44 | public bool Unmarshal(InputStream stream, int fieldNumber, WireFormat.WireType wt) 45 | { 46 | switch (fieldNumber) 47 | { 48 | case 1: 49 | stream.ReadString(wt, ref Str); 50 | break; 51 | case 2: 52 | stream.ReadBool(wt, ref Bool); 53 | break; 54 | default: 55 | return true; 56 | } 57 | 58 | return false; 59 | } 60 | #endregion 61 | } 62 | 63 | 64 | public partial class MySubType : IProtoStruct 65 | { 66 | public bool Bool; 67 | public int Int32; 68 | public uint UInt32; 69 | public long Int64; 70 | public ulong UInt64; 71 | public float Float32; 72 | public double Float64; 73 | public string Str; 74 | public byte[] BytesSlice; 75 | public List BoolSlice; 76 | public List Int32Slice; 77 | public List UInt32Slice; 78 | public List Int64Slice; 79 | public List UInt64Slice; 80 | public List Float32Slice; 81 | public List Float64Slice; 82 | public List StrSlice; 83 | public MyEnum Enum; 84 | public List EnumSlice; 85 | 86 | #region Serialize Code 87 | public void Init( ) 88 | { 89 | BoolSlice = new List(); 90 | Int32Slice = new List(); 91 | UInt32Slice = new List(); 92 | Int64Slice = new List(); 93 | UInt64Slice = new List(); 94 | Float32Slice = new List(); 95 | Float64Slice = new List(); 96 | StrSlice = new List(); 97 | EnumSlice = new List(); 98 | 99 | } 100 | 101 | public void Marshal(OutputStream stream) 102 | { 103 | stream.WriteBool(1, Bool ); 104 | stream.WriteInt32(2, Int32 ); 105 | stream.WriteUInt32(3, UInt32 ); 106 | stream.WriteInt64(4, Int64 ); 107 | stream.WriteUInt64(5, UInt64 ); 108 | stream.WriteFloat(6, Float32 ); 109 | stream.WriteDouble(7, Float64 ); 110 | stream.WriteString(8, Str ); 111 | stream.WriteBytes(9, BytesSlice ); 112 | stream.WriteBool(10, BoolSlice ); 113 | stream.WriteInt32(11, Int32Slice ); 114 | stream.WriteUInt32(12, UInt32Slice ); 115 | stream.WriteInt64(13, Int64Slice ); 116 | stream.WriteUInt64(14, UInt64Slice ); 117 | stream.WriteFloat(15, Float32Slice ); 118 | stream.WriteDouble(16, Float64Slice ); 119 | stream.WriteString(17, StrSlice ); 120 | stream.WriteEnum(18, Enum ); 121 | stream.WriteEnum(19, EnumSlice ); 122 | } 123 | 124 | public int GetSize() 125 | { 126 | int size = 0; 127 | size += OutputStream.SizeBool(1, Bool); 128 | size += OutputStream.SizeInt32(2, Int32); 129 | size += OutputStream.SizeUInt32(3, UInt32); 130 | size += OutputStream.SizeInt64(4, Int64); 131 | size += OutputStream.SizeUInt64(5, UInt64); 132 | size += OutputStream.SizeFloat(6, Float32); 133 | size += OutputStream.SizeDouble(7, Float64); 134 | size += OutputStream.SizeString(8, Str); 135 | size += OutputStream.SizeBytes(9, BytesSlice); 136 | size += OutputStream.SizeBool(10, BoolSlice); 137 | size += OutputStream.SizeInt32(11, Int32Slice); 138 | size += OutputStream.SizeUInt32(12, UInt32Slice); 139 | size += OutputStream.SizeInt64(13, Int64Slice); 140 | size += OutputStream.SizeUInt64(14, UInt64Slice); 141 | size += OutputStream.SizeFloat(15, Float32Slice); 142 | size += OutputStream.SizeDouble(16, Float64Slice); 143 | size += OutputStream.SizeString(17, StrSlice); 144 | size += OutputStream.SizeEnum(18, Enum); 145 | size += OutputStream.SizeEnum(19, EnumSlice); 146 | return size; 147 | } 148 | 149 | public bool Unmarshal(InputStream stream, int fieldNumber, WireFormat.WireType wt) 150 | { 151 | switch (fieldNumber) 152 | { 153 | case 1: 154 | stream.ReadBool(wt, ref Bool); 155 | break; 156 | case 2: 157 | stream.ReadInt32(wt, ref Int32); 158 | break; 159 | case 3: 160 | stream.ReadUInt32(wt, ref UInt32); 161 | break; 162 | case 4: 163 | stream.ReadInt64(wt, ref Int64); 164 | break; 165 | case 5: 166 | stream.ReadUInt64(wt, ref UInt64); 167 | break; 168 | case 6: 169 | stream.ReadFloat(wt, ref Float32); 170 | break; 171 | case 7: 172 | stream.ReadDouble(wt, ref Float64); 173 | break; 174 | case 8: 175 | stream.ReadString(wt, ref Str); 176 | break; 177 | case 9: 178 | stream.ReadBytes(wt, ref BytesSlice); 179 | break; 180 | case 10: 181 | stream.ReadBool(wt, ref BoolSlice); 182 | break; 183 | case 11: 184 | stream.ReadInt32(wt, ref Int32Slice); 185 | break; 186 | case 12: 187 | stream.ReadUInt32(wt, ref UInt32Slice); 188 | break; 189 | case 13: 190 | stream.ReadInt64(wt, ref Int64Slice); 191 | break; 192 | case 14: 193 | stream.ReadUInt64(wt, ref UInt64Slice); 194 | break; 195 | case 15: 196 | stream.ReadFloat(wt, ref Float32Slice); 197 | break; 198 | case 16: 199 | stream.ReadDouble(wt, ref Float64Slice); 200 | break; 201 | case 17: 202 | stream.ReadString(wt, ref StrSlice); 203 | break; 204 | case 18: 205 | stream.ReadEnum(wt, ref Enum); 206 | break; 207 | case 19: 208 | stream.ReadEnum(wt, ref EnumSlice); 209 | break; 210 | default: 211 | return true; 212 | } 213 | 214 | return false; 215 | } 216 | #endregion 217 | } 218 | 219 | 220 | public partial class MyType : IProtoStruct 221 | { 222 | public bool Bool; 223 | public int Int32; 224 | public uint UInt32; 225 | public long Int64; 226 | public ulong UInt64; 227 | public float Float32; 228 | public double Float64; 229 | public string Str; 230 | public MySubType Struct; 231 | public byte[] BytesSlice; 232 | public List BoolSlice; 233 | public List Int32Slice; 234 | public List UInt32Slice; 235 | public List Int64Slice; 236 | public List UInt64Slice; 237 | public List Float32Slice; 238 | public List Float64Slice; 239 | public List StrSlice; 240 | public List StructSlice; 241 | public MyEnum Enum; 242 | public List EnumSlice; 243 | 244 | #region Serialize Code 245 | public void Init( ) 246 | { 247 | BoolSlice = new List(); 248 | Int32Slice = new List(); 249 | UInt32Slice = new List(); 250 | Int64Slice = new List(); 251 | UInt64Slice = new List(); 252 | Float32Slice = new List(); 253 | Float64Slice = new List(); 254 | StrSlice = new List(); 255 | EnumSlice = new List(); 256 | 257 | Struct = (MySubType) InputStream.CreateStruct(typeof(MySubType)); 258 | } 259 | 260 | public void Marshal(OutputStream stream) 261 | { 262 | stream.WriteBool(1, Bool ); 263 | stream.WriteInt32(2, Int32 ); 264 | stream.WriteUInt32(3, UInt32 ); 265 | stream.WriteInt64(4, Int64 ); 266 | stream.WriteUInt64(5, UInt64 ); 267 | stream.WriteFloat(6, Float32 ); 268 | stream.WriteDouble(7, Float64 ); 269 | stream.WriteString(8, Str ); 270 | stream.WriteStruct(9, Struct ); 271 | stream.WriteBytes(10, BytesSlice ); 272 | stream.WriteBool(11, BoolSlice ); 273 | stream.WriteInt32(12, Int32Slice ); 274 | stream.WriteUInt32(13, UInt32Slice ); 275 | stream.WriteInt64(14, Int64Slice ); 276 | stream.WriteUInt64(15, UInt64Slice ); 277 | stream.WriteFloat(16, Float32Slice ); 278 | stream.WriteDouble(17, Float64Slice ); 279 | stream.WriteString(18, StrSlice ); 280 | stream.WriteStruct(19, StructSlice ); 281 | stream.WriteEnum(20, Enum ); 282 | stream.WriteEnum(21, EnumSlice ); 283 | } 284 | 285 | public int GetSize() 286 | { 287 | int size = 0; 288 | size += OutputStream.SizeBool(1, Bool); 289 | size += OutputStream.SizeInt32(2, Int32); 290 | size += OutputStream.SizeUInt32(3, UInt32); 291 | size += OutputStream.SizeInt64(4, Int64); 292 | size += OutputStream.SizeUInt64(5, UInt64); 293 | size += OutputStream.SizeFloat(6, Float32); 294 | size += OutputStream.SizeDouble(7, Float64); 295 | size += OutputStream.SizeString(8, Str); 296 | size += OutputStream.SizeStruct(9, Struct); 297 | size += OutputStream.SizeBytes(10, BytesSlice); 298 | size += OutputStream.SizeBool(11, BoolSlice); 299 | size += OutputStream.SizeInt32(12, Int32Slice); 300 | size += OutputStream.SizeUInt32(13, UInt32Slice); 301 | size += OutputStream.SizeInt64(14, Int64Slice); 302 | size += OutputStream.SizeUInt64(15, UInt64Slice); 303 | size += OutputStream.SizeFloat(16, Float32Slice); 304 | size += OutputStream.SizeDouble(17, Float64Slice); 305 | size += OutputStream.SizeString(18, StrSlice); 306 | size += OutputStream.SizeStruct(19, StructSlice); 307 | size += OutputStream.SizeEnum(20, Enum); 308 | size += OutputStream.SizeEnum(21, EnumSlice); 309 | return size; 310 | } 311 | 312 | public bool Unmarshal(InputStream stream, int fieldNumber, WireFormat.WireType wt) 313 | { 314 | switch (fieldNumber) 315 | { 316 | case 1: 317 | stream.ReadBool(wt, ref Bool); 318 | break; 319 | case 2: 320 | stream.ReadInt32(wt, ref Int32); 321 | break; 322 | case 3: 323 | stream.ReadUInt32(wt, ref UInt32); 324 | break; 325 | case 4: 326 | stream.ReadInt64(wt, ref Int64); 327 | break; 328 | case 5: 329 | stream.ReadUInt64(wt, ref UInt64); 330 | break; 331 | case 6: 332 | stream.ReadFloat(wt, ref Float32); 333 | break; 334 | case 7: 335 | stream.ReadDouble(wt, ref Float64); 336 | break; 337 | case 8: 338 | stream.ReadString(wt, ref Str); 339 | break; 340 | case 9: 341 | stream.ReadStruct(wt, ref Struct); 342 | break; 343 | case 10: 344 | stream.ReadBytes(wt, ref BytesSlice); 345 | break; 346 | case 11: 347 | stream.ReadBool(wt, ref BoolSlice); 348 | break; 349 | case 12: 350 | stream.ReadInt32(wt, ref Int32Slice); 351 | break; 352 | case 13: 353 | stream.ReadUInt32(wt, ref UInt32Slice); 354 | break; 355 | case 14: 356 | stream.ReadInt64(wt, ref Int64Slice); 357 | break; 358 | case 15: 359 | stream.ReadUInt64(wt, ref UInt64Slice); 360 | break; 361 | case 16: 362 | stream.ReadFloat(wt, ref Float32Slice); 363 | break; 364 | case 17: 365 | stream.ReadDouble(wt, ref Float64Slice); 366 | break; 367 | case 18: 368 | stream.ReadString(wt, ref StrSlice); 369 | break; 370 | case 19: 371 | stream.ReadStruct(wt, ref StructSlice); 372 | break; 373 | case 20: 374 | stream.ReadEnum(wt, ref Enum); 375 | break; 376 | case 21: 377 | stream.ReadEnum(wt, ref EnumSlice); 378 | break; 379 | default: 380 | return true; 381 | } 382 | 383 | return false; 384 | } 385 | #endregion 386 | } 387 | 388 | 389 | public partial class LoginREQ : IProtoStruct 390 | { 391 | 392 | #region Serialize Code 393 | public void Init( ) 394 | { 395 | 396 | } 397 | 398 | public void Marshal(OutputStream stream) 399 | { 400 | } 401 | 402 | public int GetSize() 403 | { 404 | int size = 0; 405 | return size; 406 | } 407 | 408 | public bool Unmarshal(InputStream stream, int fieldNumber, WireFormat.WireType wt) 409 | { 410 | switch (fieldNumber) 411 | { 412 | default: 413 | return true; 414 | } 415 | 416 | return false; 417 | } 418 | #endregion 419 | } 420 | 421 | 422 | public partial class LoginACK : IProtoStruct 423 | { 424 | 425 | #region Serialize Code 426 | public void Init( ) 427 | { 428 | 429 | } 430 | 431 | public void Marshal(OutputStream stream) 432 | { 433 | } 434 | 435 | public int GetSize() 436 | { 437 | int size = 0; 438 | return size; 439 | } 440 | 441 | public bool Unmarshal(InputStream stream, int fieldNumber, WireFormat.WireType wt) 442 | { 443 | switch (fieldNumber) 444 | { 445 | default: 446 | return true; 447 | } 448 | 449 | return false; 450 | } 451 | #endregion 452 | } 453 | 454 | 455 | public partial class S1 : IProtoStruct 456 | { 457 | public int V; 458 | 459 | #region Serialize Code 460 | public void Init( ) 461 | { 462 | 463 | } 464 | 465 | public void Marshal(OutputStream stream) 466 | { 467 | stream.WriteInt32(1, V ); 468 | } 469 | 470 | public int GetSize() 471 | { 472 | int size = 0; 473 | size += OutputStream.SizeInt32(1, V); 474 | return size; 475 | } 476 | 477 | public bool Unmarshal(InputStream stream, int fieldNumber, WireFormat.WireType wt) 478 | { 479 | switch (fieldNumber) 480 | { 481 | case 1: 482 | stream.ReadInt32(wt, ref V); 483 | break; 484 | default: 485 | return true; 486 | } 487 | 488 | return false; 489 | } 490 | #endregion 491 | } 492 | 493 | 494 | public partial class S2 : IProtoStruct 495 | { 496 | public int V; 497 | public string S; 498 | 499 | #region Serialize Code 500 | public void Init( ) 501 | { 502 | 503 | } 504 | 505 | public void Marshal(OutputStream stream) 506 | { 507 | stream.WriteInt32(1, V ); 508 | stream.WriteString(2, S ); 509 | } 510 | 511 | public int GetSize() 512 | { 513 | int size = 0; 514 | size += OutputStream.SizeInt32(1, V); 515 | size += OutputStream.SizeString(2, S); 516 | return size; 517 | } 518 | 519 | public bool Unmarshal(InputStream stream, int fieldNumber, WireFormat.WireType wt) 520 | { 521 | switch (fieldNumber) 522 | { 523 | case 1: 524 | stream.ReadInt32(wt, ref V); 525 | break; 526 | case 2: 527 | stream.ReadString(wt, ref S); 528 | break; 529 | default: 530 | return true; 531 | } 532 | 533 | return false; 534 | } 535 | #endregion 536 | } 537 | 538 | 539 | 540 | public static class MessageMetaRegister 541 | { 542 | public static void RegisterGeneratedMeta(MessageMeta meta) 543 | { 544 | meta.RegisterMeta(new MetaInfo 545 | { 546 | Type = typeof(MySubType), 547 | ID = 33606, 548 | SourcePeer = "client", 549 | TargetPeer = "game", 550 | }); 551 | meta.RegisterMeta(new MetaInfo 552 | { 553 | Type = typeof(MyType), 554 | ID = 9980, 555 | SourcePeer = "", 556 | TargetPeer = "", 557 | }); 558 | } 559 | } 560 | 561 | } 562 | -------------------------------------------------------------------------------- /example/csharp/Example.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28010.2046 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example", "Example\Example.csproj", "{660CB175-1256-4A1C-B76C-08B45E9F0159}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtoPlus", "..\..\api\csharp\ProtoPlus\ProtoPlus.csproj", "{1E171D88-E6CB-4493-98D1-5C7A36CA422B}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {660CB175-1256-4A1C-B76C-08B45E9F0159}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {660CB175-1256-4A1C-B76C-08B45E9F0159}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {660CB175-1256-4A1C-B76C-08B45E9F0159}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {660CB175-1256-4A1C-B76C-08B45E9F0159}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {1E171D88-E6CB-4493-98D1-5C7A36CA422B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {1E171D88-E6CB-4493-98D1-5C7A36CA422B}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {1E171D88-E6CB-4493-98D1-5C7A36CA422B}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {1E171D88-E6CB-4493-98D1-5C7A36CA422B}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {206E7DF1-9C5D-48F8-B927-873B65237346} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /example/csharp/Example/Example.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.0 6 | Example.Program 7 | 8 | 9 | 10 | TRACE;DEBUG;NETCOREAPP2_0 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/csharp/Example/ProtoGen.cs: -------------------------------------------------------------------------------- 1 | // Generated by github.com/davyxu/protoplus 2 | // DO NOT EDIT! 3 | using System; 4 | using System.Collections.Generic; 5 | using ProtoPlus; 6 | #pragma warning disable 162 7 | 8 | namespace Proto 9 | { 10 | 11 | 12 | 13 | public partial class LoginREQ : IProtoStruct 14 | { 15 | 16 | #region Serialize Code 17 | public void Init( ) 18 | { 19 | } 20 | 21 | public void Marshal(OutputStream stream) 22 | { 23 | } 24 | 25 | public int GetSize() 26 | { 27 | int size = 0; 28 | return size; 29 | } 30 | 31 | public bool Unmarshal(InputStream stream, int fieldNumber, WireFormat.WireType wt) 32 | { 33 | switch (fieldNumber) 34 | { 35 | default: 36 | return true; 37 | } 38 | 39 | return false; 40 | } 41 | #endregion 42 | } 43 | 44 | 45 | public partial class LoginACK : IProtoStruct 46 | { 47 | 48 | #region Serialize Code 49 | public void Init( ) 50 | { 51 | } 52 | 53 | public void Marshal(OutputStream stream) 54 | { 55 | } 56 | 57 | public int GetSize() 58 | { 59 | int size = 0; 60 | return size; 61 | } 62 | 63 | public bool Unmarshal(InputStream stream, int fieldNumber, WireFormat.WireType wt) 64 | { 65 | switch (fieldNumber) 66 | { 67 | default: 68 | return true; 69 | } 70 | 71 | return false; 72 | } 73 | #endregion 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /example/csharp/Example/ProtoGenReg.cs: -------------------------------------------------------------------------------- 1 | // Generated by github.com/davyxu/protoplus 2 | // DO NOT EDIT! 3 | using System; 4 | using System.Collections.Generic; 5 | #pragma warning disable 162 6 | 7 | namespace Proto 8 | { 9 | public class MetaInfo 10 | { 11 | public ushort ID; // 消息ID 12 | public Type Type; // 消息类型 13 | 14 | // 消息方向 15 | // 在proto中添加[MsgDir: "client -> game" ], 左边为源, 右边为目标 16 | public string SourcePeer; // 消息发起的源 17 | public string TargetPeer; // 消息的目标 18 | 19 | public string Name; 20 | } 21 | 22 | public static class MessageVisitor 23 | { 24 | public static void Visit(Action callback) 25 | { 26 | callback(new MetaInfo 27 | { 28 | Type = typeof(MyTypeMini), 29 | ID = 0, 30 | SourcePeer = "", 31 | TargetPeer = "", 32 | }); 33 | callback(new MetaInfo 34 | { 35 | Type = typeof(MySubType), 36 | ID = 0, 37 | SourcePeer = "", 38 | TargetPeer = "", 39 | }); 40 | callback(new MetaInfo 41 | { 42 | Type = typeof(MyType), 43 | ID = 0, 44 | SourcePeer = "", 45 | TargetPeer = "", 46 | }); 47 | callback(new MetaInfo 48 | { 49 | Type = typeof(LoginREQ), 50 | ID = 225, 51 | SourcePeer = "client", 52 | TargetPeer = "game", 53 | }); 54 | callback(new MetaInfo 55 | { 56 | Type = typeof(LoginACK), 57 | ID = 27592, 58 | SourcePeer = "", 59 | TargetPeer = "", 60 | }); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /example/csharp/Example/Test.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using Proto; 5 | using ProtoPlus; 6 | 7 | namespace Proto 8 | { 9 | public partial class MySubType : IProtoStruct 10 | { 11 | public override bool Equals(object obj) 12 | { 13 | if (!(obj is MySubType o)) 14 | return false; 15 | 16 | return EqualsType(o); 17 | } 18 | 19 | public bool EqualsType(MySubType other) 20 | { 21 | return Bool == other.Bool && 22 | Int32 == other.Int32 && 23 | UInt32 == other.UInt32 && 24 | Int64 == other.Int64 && 25 | UInt64 == other.UInt64 && 26 | Float32.Equals(other.Float32) && 27 | Float64.Equals(other.Float64) && 28 | Enum == other.Enum && 29 | string.Equals(Str, other.Str); 30 | } 31 | 32 | } 33 | 34 | public partial class MyType : IProtoStruct 35 | { 36 | public override bool Equals(object obj) 37 | { 38 | if (!(obj is MyType o)) 39 | return false; 40 | 41 | return EqualsType(o); 42 | } 43 | 44 | protected bool EqualsType(MyType other) 45 | { 46 | return Bool == other.Bool && 47 | Int32 == other.Int32 && 48 | UInt32 == other.UInt32 && 49 | Int64 == other.Int64 && 50 | UInt64 == other.UInt64 && 51 | Float32.Equals(other.Float32) && 52 | Float64.Equals(other.Float64) && 53 | string.Equals(Str, other.Str) && 54 | Enum == other.Enum && 55 | Equals(Struct, other.Struct); 56 | } 57 | 58 | } 59 | } 60 | 61 | namespace Example 62 | { 63 | class Program 64 | { 65 | static MyType MakeMyType() 66 | { 67 | return new MyType 68 | { 69 | Bool = true, 70 | Int32 = 200, 71 | UInt32 = UInt32.MaxValue - 100, 72 | Int64 = -789, 73 | UInt64 = 1234567890123456, 74 | Str = "hello", 75 | Float32 = 3.14f, 76 | Float64 = double.MaxValue, 77 | Enum = MyEnum.Two, 78 | BoolSlice = new List{ true, false, true }, 79 | Int32Slice = new List{ 1, 2, 3, 4}, 80 | UInt32Slice = new List { 100, 200, 300, 400 }, 81 | Int64Slice = new List { 10, 20, 30, 40 }, 82 | UInt64Slice = new List { 100, 200, 300, 400 }, 83 | StrSlice = new List { "genji", "dva", "bastion" }, 84 | Float32Slice = new List { 1.1f, 2.1f, 3.2f, 4.5f }, 85 | Float64Slice= new List { 1.1, 2.1, 3.2, 4.5 }, 86 | BytesSlice = new byte[]{ 61, 234, 7 }, 87 | EnumSlice = new List{MyEnum.Two, MyEnum.Zero, MyEnum.One}, 88 | 89 | Struct = new MySubType() 90 | { 91 | Bool = true, 92 | Int32 = 128, 93 | }, 94 | StructSlice = new List 95 | { 96 | new MySubType 97 | { 98 | Int32 = 100, 99 | Str = "x100", 100 | }, 101 | new MySubType 102 | { 103 | Int32 = 200, 104 | Str = "x200", 105 | } 106 | 107 | } 108 | 109 | 110 | }; 111 | } 112 | 113 | static void TestSkipField() 114 | { 115 | byte[] data = new byte[256]; 116 | var s = new OutputStream(data); 117 | 118 | var myType = MakeMyType(); 119 | 120 | s.Marshal(myType); 121 | 122 | var s2 = new InputStream(); 123 | s2.Init(data, 0, s.Position); 124 | 125 | var myType2 = InputStream.CreateStruct(); 126 | 127 | s2.Unmarshal(myType2); 128 | 129 | Debug.Assert(myType2.Bool == myType2.Bool && myType2.Float32 == myType.Float32 && 130 | myType2.Int32 == myType.Int32 && myType2.Int64 == myType.Int64 131 | && myType2.UInt64 == myType.UInt64 && myType2.UInt32 == myType.UInt32 132 | && myType2.Str == myType.Str); 133 | } 134 | 135 | static void TestFull() 136 | { 137 | byte[] data = new byte[256]; 138 | var s = new OutputStream(data); 139 | 140 | var myType = MakeMyType(); 141 | 142 | s.Marshal(myType); 143 | 144 | var s2 = new InputStream(); 145 | s2.Init(data, 0, s.Position); 146 | 147 | var myType2 = InputStream.CreateStruct(); 148 | 149 | s2.Unmarshal(myType2); 150 | 151 | Debug.Assert(myType.Equals(myType2)); 152 | } 153 | 154 | 155 | static void Main(string[] args) 156 | { 157 | TestFull(); 158 | TestSkipField(); 159 | } 160 | } 161 | 162 | } 163 | 164 | -------------------------------------------------------------------------------- /gen/gen.go: -------------------------------------------------------------------------------- 1 | package gen 2 | 3 | import ( 4 | "github.com/davyxu/protoplus/model" 5 | ) 6 | 7 | type Context struct { 8 | *model.DescriptorSet 9 | OutputFileName string 10 | ClassBase string 11 | } 12 | -------------------------------------------------------------------------------- /gen/pbscheme/func.go: -------------------------------------------------------------------------------- 1 | package pbscheme 2 | 3 | import ( 4 | "fmt" 5 | "github.com/davyxu/protoplus/model" 6 | "text/template" 7 | ) 8 | 9 | var UsefulFunc = template.FuncMap{} 10 | 11 | func PrimitiveToPbType(primitiveType string) string { 12 | switch primitiveType { 13 | case "uint16": 14 | return "uint32" 15 | case "int16": 16 | return "int32" 17 | case "float32": 18 | return "float" 19 | case "float64": 20 | return "double" 21 | default: 22 | return primitiveType 23 | } 24 | } 25 | 26 | func init() { 27 | UsefulFunc["PbTypeName"] = func(raw interface{}) (ret string) { 28 | 29 | fd := raw.(*model.FieldDescriptor) 30 | 31 | switch { 32 | case fd.IsMap(): 33 | ret = fmt.Sprintf("map<%s,%s>", PrimitiveToPbType(fd.MapKey), PrimitiveToPbType(fd.MapValue)) 34 | case fd.Repeatd: 35 | ret += "repeated " 36 | ret += PrimitiveToPbType(fd.Type) 37 | default: 38 | ret = PrimitiveToPbType(fd.Type) 39 | } 40 | 41 | return 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /gen/pbscheme/gen_dir.go: -------------------------------------------------------------------------------- 1 | package pbscheme 2 | 3 | import ( 4 | "fmt" 5 | "github.com/davyxu/protoplus/codegen" 6 | "github.com/davyxu/protoplus/gen" 7 | "github.com/davyxu/protoplus/model" 8 | "io/ioutil" 9 | "path/filepath" 10 | "sort" 11 | "strings" 12 | ) 13 | 14 | const protoDirCodeTemplate = `// Generated by github.com/davyxu/protoplus 15 | // DO NOT EDIT! 16 | syntax = "proto3"; 17 | 18 | option go_package= "./;{{.PackageName}}"; 19 | 20 | package {{.PackageName}}; 21 | 22 | {{range $a, $enumobj := .DependentSource}} 23 | import "{{.}}"; {{end}} 24 | 25 | {{range $a, $enumobj := .Enums}} 26 | enum {{.Name}} { {{range .Fields}} 27 | {{.Name}} = {{PbTagNumber $enumobj .}}; {{end}} 28 | }{{end}} 29 | 30 | {{range $a, $obj := .Structs}} 31 | {{ObjectLeadingComment .}} 32 | message {{.Name}} { {{range .Fields}} 33 | {{PbTypeName .}} {{GoFieldName .}} = {{PbTagNumber $obj .}};{{FieldTrailingComment .}} {{end}} 34 | } 35 | {{end}} 36 | ` 37 | 38 | func GenProtoDir(ctx *gen.Context) error { 39 | 40 | rootDS := &model.PBDescriptorSet{DescriptorSet: *ctx.DescriptorSet} 41 | 42 | var sb strings.Builder 43 | 44 | var srcNameList []string 45 | for srcName, ds := range rootDS.DescriptorSetBySource() { 46 | 47 | srcNameList = append(srcNameList, srcName) 48 | 49 | generator := codegen.NewCodeGen("dirproto"). 50 | RegisterTemplateFunc(codegen.UsefulFunc). 51 | RegisterTemplateFunc(UsefulFunc). 52 | ParseTemplate(protoDirCodeTemplate, ds) 53 | 54 | if generator.Error() != nil { 55 | fmt.Println(string(generator.Data())) 56 | return generator.Error() 57 | } 58 | 59 | fullPathName := filepath.Join(ctx.OutputFileName, srcName) 60 | 61 | err := generator.WriteOutputFile(fullPathName).Error() 62 | if err != nil { 63 | return err 64 | } 65 | } 66 | 67 | sort.Strings(srcNameList) 68 | 69 | for _, d := range srcNameList { 70 | fmt.Fprintf(&sb, "%s ", d) 71 | } 72 | 73 | err := ioutil.WriteFile(filepath.Join(ctx.OutputFileName, "filelist.txt"), []byte(sb.String()), 0666) 74 | 75 | return err 76 | } 77 | -------------------------------------------------------------------------------- /gen/pbscheme/gen_proto.go: -------------------------------------------------------------------------------- 1 | package pbscheme 2 | 3 | import ( 4 | "fmt" 5 | "github.com/davyxu/protoplus/codegen" 6 | "github.com/davyxu/protoplus/gen" 7 | ) 8 | 9 | // 报错行号+7 10 | const protoCodeTemplate = `// Generated by github.com/davyxu/protoplus 11 | // DO NOT EDIT! 12 | syntax = "proto3"; 13 | 14 | option go_package= "./;{{.PackageName}}"; 15 | 16 | package {{.PackageName}}; 17 | 18 | {{range $a, $enumobj := .Enums}} 19 | enum {{.Name}} { {{range .Fields}} 20 | {{.Name}} = {{PbTagNumber $enumobj .}}; {{end}} 21 | }{{end}} 22 | 23 | {{range $a, $obj := .Structs}} 24 | {{ObjectLeadingComment .}} 25 | message {{.Name}} { {{range .Fields}} 26 | {{PbTypeName .}} {{GoFieldName .}} = {{PbTagNumber $obj .}};{{FieldTrailingComment .}} {{end}} 27 | } 28 | {{end}} 29 | ` 30 | 31 | func GenProto(ctx *gen.Context) error { 32 | 33 | gen := codegen.NewCodeGen("proto"). 34 | RegisterTemplateFunc(codegen.UsefulFunc). 35 | RegisterTemplateFunc(UsefulFunc). 36 | ParseTemplate(protoCodeTemplate, ctx) 37 | 38 | if gen.Error() != nil { 39 | fmt.Println(string(gen.Data())) 40 | return gen.Error() 41 | } 42 | 43 | return gen.WriteOutputFile(ctx.OutputFileName).Error() 44 | } 45 | -------------------------------------------------------------------------------- /gen/ppcpp/func.go: -------------------------------------------------------------------------------- 1 | package ppcpp 2 | 3 | import ( 4 | "github.com/davyxu/protoplus/gen" 5 | "github.com/davyxu/protoplus/model" 6 | "path" 7 | "path/filepath" 8 | "strings" 9 | "text/template" 10 | ) 11 | 12 | var UsefulFunc = template.FuncMap{} 13 | 14 | func ChangeExtension(filename, newExt string) string { 15 | 16 | file := filepath.Base(filename) 17 | 18 | return strings.TrimSuffix(file, path.Ext(file)) + newExt 19 | } 20 | 21 | func SourceList(ctx *gen.Context) (ret []string) { 22 | 23 | rootDS := &model.PBDescriptorSet{DescriptorSet: *ctx.DescriptorSet} 24 | for _, protoFile := range rootDS.SourceList() { 25 | ret = append(ret, ChangeExtension(protoFile, ".pb.h")) 26 | } 27 | 28 | return 29 | } 30 | 31 | func init() { 32 | UsefulFunc["SourceList"] = SourceList 33 | } 34 | -------------------------------------------------------------------------------- /gen/ppcpp/gen_cpp.go: -------------------------------------------------------------------------------- 1 | package ppcpp 2 | 3 | import ( 4 | "fmt" 5 | "github.com/davyxu/protoplus/codegen" 6 | "github.com/davyxu/protoplus/gen" 7 | ) 8 | 9 | func GenCppReg(ctx *gen.Context) error { 10 | 11 | codeGen := codegen.NewCodeGen("cppreg"). 12 | RegisterTemplateFunc(codegen.UsefulFunc). 13 | RegisterTemplateFunc(UsefulFunc). 14 | ParseTemplate(RegTemplateText, ctx) 15 | 16 | if codeGen.Error() != nil { 17 | fmt.Println(codeGen.Code()) 18 | return codeGen.Error() 19 | } 20 | 21 | return codeGen.WriteOutputFile(ctx.OutputFileName).Error() 22 | } 23 | -------------------------------------------------------------------------------- /gen/ppcpp/text.go: -------------------------------------------------------------------------------- 1 | package ppcpp 2 | 3 | const RegTemplateText = `// Generated by github.com/davyxu/protoplus 4 | #pragma once 5 | #include "MessageRegistry.h" 6 | {{range SourceList $}} 7 | #include "{{.}}"{{end}} 8 | 9 | {{range .Structs}} 10 | class {{.Name}}Meta : public MessageMeta 11 | { 12 | public: 13 | static const int32 Id = {{StructMsgID .}}; 14 | virtual const char* GetMessageName( ) const override{ return "{{$.PackageName}}.{{.Name}}"; } 15 | virtual int32 GetMessageId( ) const override{ return {{StructMsgID .}}; } 16 | virtual google::protobuf::Message* NewMessage() override { return {{$.PackageName}}::{{.Name}}::default_instance().New(); } 17 | virtual const google::protobuf::Descriptor* GetMessageType() const override{ return {{$.PackageName}}::{{.Name}}::GetDescriptor(); } 18 | }; {{end}} 19 | 20 | void StaticRegisterMeta( ) 21 | { {{range .Structs}} 22 | MessageRegistry::Register(new {{.Name}}Meta); {{end}} 23 | } 24 | 25 | ` 26 | -------------------------------------------------------------------------------- /gen/ppcs/func.go: -------------------------------------------------------------------------------- 1 | package ppcs 2 | 3 | import ( 4 | "fmt" 5 | "github.com/davyxu/protoplus/codegen" 6 | "github.com/davyxu/protoplus/model" 7 | "strings" 8 | "text/template" 9 | ) 10 | 11 | var UsefulFunc = template.FuncMap{} 12 | 13 | func CSTypeNameFull(fd *model.FieldDescriptor) (ret string) { 14 | 15 | if fd.Repeatd { 16 | return fmt.Sprintf("List<%s>", codegen.CSTypeName(fd)) 17 | } 18 | 19 | return codegen.CSTypeName(fd) 20 | } 21 | 22 | func getEndPointPair(d *model.Descriptor) (from, to string) { 23 | 24 | msgdir := d.TagValueString("MsgDir") 25 | endPoints := strings.Split(msgdir, "->") 26 | if len(endPoints) >= 2 { 27 | 28 | from = strings.TrimSpace(endPoints[0]) 29 | 30 | to = strings.TrimSpace(endPoints[1]) 31 | } 32 | 33 | return 34 | } 35 | 36 | func init() { 37 | 38 | UsefulFunc["CSTypeNameFull"] = func(raw interface{}) (ret string) { 39 | 40 | fd := raw.(*model.FieldDescriptor) 41 | 42 | return CSTypeNameFull(fd) 43 | } 44 | 45 | // 原生类型/结构体 | 数组 | 导出方式 46 | // 原生类型 无初始化 47 | // 原生类型 是 new Type[]() 48 | // 结构体 MessageMeta.NewStruct() 49 | // 结构体 是 new Type[]() 50 | 51 | UsefulFunc["NoneStructCanInit"] = func(raw interface{}) bool { 52 | 53 | fd := raw.(*model.FieldDescriptor) 54 | 55 | if fd.Kind == model.Kind_Primitive && fd.Type == "string" { 56 | return false 57 | } 58 | 59 | return !fd.TagExists("NoInit") && fd.Repeatd 60 | } 61 | 62 | UsefulFunc["StructCanInit"] = func(raw interface{}) bool { 63 | 64 | fd := raw.(*model.FieldDescriptor) 65 | 66 | return !fd.TagExists("NoInit") && !fd.Repeatd && fd.Kind == model.Kind_Struct 67 | } 68 | 69 | UsefulFunc["IsStructSlice"] = func(raw interface{}) bool { 70 | 71 | fd := raw.(*model.FieldDescriptor) 72 | 73 | return fd.Repeatd && fd.Kind == model.Kind_Struct 74 | } 75 | 76 | UsefulFunc["IsStruct"] = func(raw interface{}) bool { 77 | 78 | fd := raw.(*model.FieldDescriptor) 79 | 80 | return !fd.Repeatd && fd.Kind == model.Kind_Struct 81 | } 82 | 83 | UsefulFunc["IsEnum"] = func(raw interface{}) bool { 84 | 85 | fd := raw.(*model.FieldDescriptor) 86 | 87 | return !fd.Repeatd && fd.Kind == model.Kind_Enum 88 | } 89 | 90 | UsefulFunc["IsEnumSlice"] = func(raw interface{}) bool { 91 | 92 | fd := raw.(*model.FieldDescriptor) 93 | 94 | return fd.Repeatd && fd.Kind == model.Kind_Enum 95 | } 96 | 97 | UsefulFunc["GetSourcePeer"] = func(raw interface{}) string { 98 | 99 | d := raw.(*model.Descriptor) 100 | 101 | from, _ := getEndPointPair(d) 102 | 103 | return from 104 | } 105 | 106 | UsefulFunc["GetTargetPeer"] = func(raw interface{}) string { 107 | 108 | d := raw.(*model.Descriptor) 109 | 110 | _, to := getEndPointPair(d) 111 | 112 | return to 113 | } 114 | 115 | UsefulFunc["CodecName"] = func(raw interface{}) (ret string) { 116 | 117 | fd := raw.(*model.FieldDescriptor) 118 | 119 | switch fd.Type { 120 | case "bool": 121 | ret += "Bool" 122 | case "int32": 123 | ret += "Int32" 124 | case "uint32": 125 | ret += "UInt32" 126 | case "int64": 127 | ret += "Int64" 128 | case "uint64": 129 | ret += "UInt64" 130 | case "float32": 131 | ret += "Float" 132 | case "float64": 133 | ret += "Double" 134 | case "string": 135 | ret += "String" 136 | case "struct": 137 | case "bytes": 138 | ret += "Bytes" 139 | 140 | default: 141 | if fd.Kind == model.Kind_Struct { 142 | ret += "Struct" 143 | } else if fd.Kind == model.Kind_Enum { 144 | ret += "Enum" 145 | } else { 146 | panic("unknown Type " + fd.Type) 147 | } 148 | 149 | } 150 | 151 | return 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /gen/ppcs/gen_cs.go: -------------------------------------------------------------------------------- 1 | package ppcs 2 | 3 | import ( 4 | "fmt" 5 | "github.com/davyxu/protoplus/codegen" 6 | "github.com/davyxu/protoplus/gen" 7 | ) 8 | 9 | func GenCS(ctx *gen.Context) error { 10 | 11 | gen := codegen.NewCodeGen("cs"). 12 | RegisterTemplateFunc(codegen.UsefulFunc). 13 | RegisterTemplateFunc(UsefulFunc). 14 | ParseTemplate(TemplateText, ctx) 15 | 16 | if gen.Error() != nil { 17 | fmt.Println(string(gen.Code())) 18 | return gen.Error() 19 | } 20 | 21 | return gen.WriteOutputFile(ctx.OutputFileName).Error() 22 | } 23 | 24 | func GenCSReg(ctx *gen.Context) error { 25 | 26 | gen := codegen.NewCodeGen("csreg"). 27 | RegisterTemplateFunc(codegen.UsefulFunc). 28 | RegisterTemplateFunc(UsefulFunc). 29 | ParseTemplate(RegTemplateText, ctx) 30 | 31 | if gen.Error() != nil { 32 | fmt.Println(string(gen.Code())) 33 | return gen.Error() 34 | } 35 | 36 | return gen.WriteOutputFile(ctx.OutputFileName).Error() 37 | } 38 | -------------------------------------------------------------------------------- /gen/ppcs/text.go: -------------------------------------------------------------------------------- 1 | package ppcs 2 | 3 | // 报错行号+7 4 | const TemplateText = `// Generated by github.com/davyxu/protoplus 5 | // DO NOT EDIT! 6 | using System; 7 | using System.Collections.Generic; 8 | using ProtoPlus; 9 | #pragma warning disable 162 10 | 11 | namespace {{.PackageName}} 12 | { 13 | {{range $a, $enumobj := .Enums}} 14 | public enum {{.Name}} 15 | { 16 | {{range .Fields}} 17 | {{.Name}} = {{PbTagNumber $enumobj .}}, {{end}} 18 | } {{end}} 19 | {{range $a, $obj := .Structs}} 20 | {{ObjectLeadingComment .}} 21 | public partial class {{$obj.Name}} : {{$.ClassBase}} 22 | { 23 | {{range .Fields}}public {{CSTypeNameFull .}} {{.Name}}; 24 | {{end}} 25 | #region Serialize Code 26 | public void Init( ) 27 | { {{range .Fields}}{{if NoneStructCanInit . }} 28 | {{.Name}} = new {{CSTypeNameFull .}}(); {{end}}{{end}}{{range .Fields}}{{if StructCanInit .}} 29 | {{.Name}} = ({{CSTypeNameFull .}}) MessageMeta.NewStruct(typeof({{CSTypeNameFull .}})); {{end}} {{end}} 30 | } 31 | 32 | public void Marshal(OutputStream stream) 33 | { {{range .Fields}} 34 | stream.Write{{CodecName .}}({{PbTagNumber $obj .}}, {{.Name}}); {{end}} 35 | } 36 | 37 | public int GetSize() 38 | { 39 | int size = 0; {{range .Fields}} 40 | size += OutputStream.Size{{CodecName .}}({{PbTagNumber $obj .}}, {{.Name}}); {{end}} 41 | return size; 42 | } 43 | 44 | public bool Unmarshal(InputStream stream, int fieldNumber, WireFormat.WireType wt) 45 | { 46 | switch (fieldNumber) 47 | { {{range .Fields}} 48 | case {{PbTagNumber $obj .}}: 49 | stream.Read{{CodecName .}}(wt, ref {{.Name}}); 50 | break; {{end}} 51 | default: 52 | return true; 53 | } 54 | 55 | return false; 56 | } 57 | #endregion 58 | } 59 | {{end}} 60 | } 61 | ` 62 | 63 | const RegTemplateText = `// Generated by github.com/davyxu/protoplus 64 | // DO NOT EDIT! 65 | using System; 66 | using System.Collections.Generic; 67 | #pragma warning disable 162 68 | 69 | namespace {{.PackageName}} 70 | { 71 | public class MetaInfo 72 | { 73 | public ushort ID; // 消息ID 74 | public Type Type; // 消息类型 75 | 76 | // 消息方向 77 | // 在proto中添加[MsgDir: "client -> game" ], 左边为源, 右边为目标 78 | public string SourcePeer; // 消息发起的源 79 | public string TargetPeer; // 消息的目标 80 | 81 | public string Name; 82 | } 83 | 84 | public static class MessageVisitor 85 | { 86 | public static void Visit(Action callback) 87 | { {{range .Structs}} 88 | callback(new MetaInfo 89 | { 90 | Type = typeof({{.Name}}), 91 | ID = {{StructMsgID .}}, 92 | SourcePeer = "{{GetSourcePeer .}}", 93 | TargetPeer = "{{GetTargetPeer .}}", 94 | });{{end}} 95 | } 96 | } 97 | } 98 | ` 99 | -------------------------------------------------------------------------------- /gen/ppgo/func.go: -------------------------------------------------------------------------------- 1 | package ppgo 2 | 3 | import ( 4 | "github.com/davyxu/protoplus/codegen" 5 | "github.com/davyxu/protoplus/model" 6 | "text/template" 7 | ) 8 | 9 | var UsefulFunc = template.FuncMap{} 10 | 11 | func init() { 12 | 13 | // 所有结构生成Entry 14 | UsefulFunc["GenEntry"] = func(d *model.Descriptor) bool { 15 | return true 16 | } 17 | 18 | UsefulFunc["StructCodec"] = func(d *model.Descriptor) string { 19 | codecName := d.TagValueString("Codec") 20 | if codecName == "" { 21 | return d.DescriptorSet.Codec 22 | } 23 | 24 | return codecName 25 | } 26 | UsefulFunc["ProtoTypeName"] = func(raw interface{}) (ret string) { 27 | 28 | fd := raw.(*model.FieldDescriptor) 29 | 30 | if fd.Repeatd { 31 | ret += "[]" 32 | } 33 | 34 | // 默认指针 35 | if fd.Kind == model.Kind_Struct { 36 | ret += "*" 37 | } 38 | 39 | ret += codegen.GoTypeName(fd) 40 | return 41 | } 42 | 43 | UsefulFunc["ProtoElementTypeName"] = func(raw interface{}) (ret string) { 44 | 45 | fd := raw.(*model.FieldDescriptor) 46 | 47 | ret += codegen.GoTypeName(fd) 48 | return 49 | } 50 | 51 | UsefulFunc["IsStructSlice"] = func(raw interface{}) bool { 52 | 53 | fd := raw.(*model.FieldDescriptor) 54 | 55 | return fd.Repeatd && fd.Kind == model.Kind_Struct 56 | } 57 | 58 | UsefulFunc["IsStruct"] = func(raw interface{}) bool { 59 | 60 | fd := raw.(*model.FieldDescriptor) 61 | 62 | return !fd.Repeatd && fd.Kind == model.Kind_Struct 63 | } 64 | 65 | UsefulFunc["IsSlice"] = func(raw interface{}) bool { 66 | 67 | fd := raw.(*model.FieldDescriptor) 68 | 69 | return fd.Repeatd 70 | } 71 | 72 | UsefulFunc["IsEnum"] = func(raw interface{}) bool { 73 | 74 | fd := raw.(*model.FieldDescriptor) 75 | 76 | return !fd.Repeatd && fd.Kind == model.Kind_Enum 77 | } 78 | 79 | UsefulFunc["IsEnumSlice"] = func(raw interface{}) bool { 80 | 81 | fd := raw.(*model.FieldDescriptor) 82 | 83 | return fd.Repeatd && fd.Kind == model.Kind_Enum 84 | } 85 | 86 | UsefulFunc["CodecName"] = func(raw interface{}) (ret string) { 87 | 88 | fd := raw.(*model.FieldDescriptor) 89 | 90 | switch fd.Type { 91 | case "bool": 92 | ret += "Bool" 93 | case "int32": 94 | ret += "Int32" 95 | case "uint32": 96 | ret += "UInt32" 97 | case "int64": 98 | ret += "Int64" 99 | case "uint64": 100 | ret += "UInt64" 101 | case "float32": 102 | ret += "Float32" 103 | case "float64": 104 | ret += "Float64" 105 | case "string": 106 | ret += "String" 107 | case "struct": 108 | case "bytes": 109 | ret += "Bytes" 110 | 111 | default: 112 | if fd.Kind == model.Kind_Struct { 113 | ret += "Struct" 114 | } else if fd.Kind == model.Kind_Enum { 115 | ret += "Int32" 116 | } else { 117 | panic("unknown Type " + fd.Type) 118 | } 119 | 120 | } 121 | 122 | if fd.Repeatd { 123 | ret += "Slice" 124 | } 125 | 126 | return 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /gen/ppgo/gen_go.go: -------------------------------------------------------------------------------- 1 | package ppgo 2 | 3 | import ( 4 | "fmt" 5 | "github.com/davyxu/protoplus/codegen" 6 | "github.com/davyxu/protoplus/gen" 7 | ) 8 | 9 | func GenGo(ctx *gen.Context) error { 10 | 11 | codeGen := codegen.NewCodeGen("go"). 12 | RegisterTemplateFunc(codegen.UsefulFunc). 13 | RegisterTemplateFunc(UsefulFunc). 14 | ParseTemplate(TemplateText, ctx). 15 | FormatGoCode() 16 | 17 | if codeGen.Error() != nil { 18 | fmt.Println(string(codeGen.Code())) 19 | return codeGen.Error() 20 | } 21 | 22 | return codeGen.WriteOutputFile(ctx.OutputFileName).Error() 23 | } 24 | 25 | func GenGoReg(ctx *gen.Context) error { 26 | 27 | codeGen := codegen.NewCodeGen("goreg"). 28 | RegisterTemplateFunc(codegen.UsefulFunc). 29 | RegisterTemplateFunc(UsefulFunc). 30 | ParseTemplate(RegTemplateText, ctx). 31 | FormatGoCode() 32 | 33 | if codeGen.Error() != nil { 34 | fmt.Println(codeGen.Code()) 35 | return codeGen.Error() 36 | } 37 | 38 | return codeGen.WriteOutputFile(ctx.OutputFileName).Error() 39 | } 40 | -------------------------------------------------------------------------------- /gen/ppgo/text.go: -------------------------------------------------------------------------------- 1 | package ppgo 2 | 3 | // 报错行号+7 4 | const TemplateText = `// Generated by github.com/davyxu/protoplus 5 | // DO NOT EDIT! 6 | package {{.PackageName}} 7 | 8 | import ( 9 | "github.com/davyxu/protoplus/api/golang" 10 | "github.com/davyxu/protoplus/api/golang/wire" 11 | "unsafe" 12 | ) 13 | var ( 14 | _ *wire.Buffer 15 | _ = ppgo.Marshal 16 | _ unsafe.Pointer 17 | ) 18 | 19 | {{range $a, $enumobj := .Enums}} 20 | type {{.Name}} int32 21 | const ( {{range .Fields}} 22 | {{$enumobj.Name}}_{{.Name}} {{$enumobj.Name}} = {{PbTagNumber $enumobj .}} {{end}} 23 | ) 24 | 25 | var ( 26 | {{$enumobj.Name}}MapperValueByName = map[string]int32{ {{range .Fields}} 27 | "{{.Name}}": {{PbTagNumber $enumobj .}}, {{end}} 28 | } 29 | 30 | {{$enumobj.Name}}MapperNameByValue = map[int32]string{ {{range .Fields}} 31 | {{PbTagNumber $enumobj .}}: "{{.Name}}" , {{end}} 32 | } 33 | ) 34 | 35 | func (self {{$enumobj.Name}}) String() string { 36 | return {{$enumobj.Name}}MapperNameByValue[int32(self)] 37 | } 38 | {{end}} 39 | 40 | {{range $a, $obj := .Structs}} 41 | {{ObjectLeadingComment .}} 42 | type {{.Name}} struct{ {{range .Fields}} 43 | {{GoFieldName .}} {{ProtoTypeName .}} {{GoStructTag .}}{{FieldTrailingComment .}} {{end}} 44 | } 45 | 46 | func (self *{{.Name}}) String() string { return ppgo.CompactTextString(self) } 47 | 48 | func (self *{{.Name}}) Size() (ret int) { 49 | {{range .Fields}} 50 | {{if IsStructSlice .}} 51 | if len(self.{{GoFieldName .}}) > 0 { 52 | for _, elm := range self.{{GoFieldName .}} { 53 | ret += wire.SizeStruct({{PbTagNumber $obj .}}, elm) 54 | } 55 | } 56 | {{else if IsStruct .}} 57 | ret += wire.Size{{CodecName .}}({{PbTagNumber $obj .}}, self.{{GoFieldName .}}) 58 | {{else if IsEnum .}} 59 | ret += wire.Size{{CodecName .}}({{PbTagNumber $obj .}}, int32(self.{{GoFieldName .}})) 60 | {{else if IsEnumSlice .}} 61 | ret += wire.Size{{CodecName .}}({{PbTagNumber $obj .}}, *(*[]int32)(unsafe.Pointer(&self.{{GoFieldName .}}))) 62 | {{else}} 63 | ret += wire.Size{{CodecName .}}({{PbTagNumber $obj .}}, self.{{GoFieldName .}}) 64 | {{end}} 65 | {{end}} 66 | return 67 | } 68 | 69 | func (self *{{.Name}}) Marshal(buffer *wire.Buffer) error { 70 | {{range .Fields}} 71 | {{if IsStructSlice .}} 72 | for _, elm := range self.{{GoFieldName .}} { 73 | wire.MarshalStruct(buffer, {{PbTagNumber $obj .}}, elm) 74 | } 75 | {{else if IsStruct .}} 76 | wire.Marshal{{CodecName .}}(buffer, {{PbTagNumber $obj .}}, self.{{GoFieldName .}}) 77 | {{else if IsEnum .}} 78 | wire.Marshal{{CodecName .}}(buffer, {{PbTagNumber $obj .}}, int32(self.{{GoFieldName .}})) 79 | {{else if IsEnumSlice .}} 80 | wire.Marshal{{CodecName .}}(buffer, {{PbTagNumber $obj .}}, *(*[]int32)(unsafe.Pointer(&self.{{GoFieldName .}}))) 81 | {{else}} 82 | wire.Marshal{{CodecName .}}(buffer, {{PbTagNumber $obj .}}, self.{{GoFieldName .}}) 83 | {{end}} 84 | {{end}} 85 | return nil 86 | } 87 | 88 | func (self *{{.Name}}) Unmarshal(buffer *wire.Buffer, fieldIndex uint64, wt wire.WireType) error { 89 | switch fieldIndex { 90 | {{range .Fields}} case {{PbTagNumber $obj .}}: {{if IsStructSlice .}} 91 | var elm {{.Type}} 92 | if err := wire.UnmarshalStruct(buffer, wt, &elm); err != nil { 93 | return err 94 | } else { 95 | self.{{GoFieldName .}} = append(self.{{GoFieldName .}}, &elm) 96 | return nil 97 | }{{else if IsEnum .}} 98 | v, err := wire.Unmarshal{{CodecName .}}(buffer, wt) 99 | self.{{GoFieldName .}} = {{ProtoTypeName .}}(v) 100 | return err {{else if IsStruct .}} 101 | var elm {{.Type}} 102 | self.{{GoFieldName .}} = &elm 103 | return wire.Unmarshal{{CodecName .}}(buffer, wt, self.{{GoFieldName .}}) {{else if IsEnumSlice .}} 104 | v, err := wire.Unmarshal{{CodecName .}}(buffer, wt) 105 | for _, vv := range v { 106 | self.{{GoFieldName .}} = append(self.{{GoFieldName .}}, {{ProtoElementTypeName .}}(vv)) 107 | } 108 | return err {{else if IsSlice .}} 109 | v, err := wire.Unmarshal{{CodecName .}}(buffer, wt) 110 | self.{{GoFieldName .}} = append(self.{{GoFieldName .}}, v...) 111 | return err {{else}} 112 | v, err := wire.Unmarshal{{CodecName .}}(buffer, wt) 113 | self.{{GoFieldName .}} = v 114 | return err{{end}} 115 | {{end}} 116 | } 117 | 118 | return wire.ErrUnknownField 119 | } 120 | {{end}} 121 | ` 122 | 123 | const RegTemplateText = `// Generated by github.com/davyxu/protoplus 124 | package {{.PackageName}} 125 | 126 | import ( 127 | "github.com/davyxu/cellnet/codec" 128 | "github.com/davyxu/cellnet/meta" 129 | "reflect" 130 | ) 131 | 132 | 133 | var ( 134 | _ cellmeta.Meta 135 | _ cellcodec.CodecRecycler 136 | _ reflect.Kind 137 | ) 138 | 139 | func init() { 140 | {{range .Structs}} 141 | cellmeta.Register(&cellmeta.Meta{ 142 | FullName: "{{$.PackageName}}.{{.Name}}", 143 | Id: {{StructMsgID .}}, 144 | New: func() interface{} { return &{{.Name}}{} }, 145 | Type: reflect.TypeOf((*{{.Name}})(nil)).Elem(), 146 | Codec: cellcodec.MustGetByName("{{StructCodec .}}"), 147 | }) {{end}} 148 | } 149 | ` 150 | -------------------------------------------------------------------------------- /gen/ppscheme/json.go: -------------------------------------------------------------------------------- 1 | package ppscheme 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/davyxu/protoplus/codegen" 7 | "github.com/davyxu/protoplus/gen" 8 | "io/ioutil" 9 | "strconv" 10 | ) 11 | 12 | func genJsonData(ctx *gen.Context) (error, []byte) { 13 | 14 | for _, obj := range ctx.DescriptorSet.Objects { 15 | if obj.TagExists("AutoMsgID") { 16 | obj.SetTagValue("AutoMsgID", strconv.Itoa(codegen.StructMsgID(obj))) 17 | } 18 | 19 | } 20 | 21 | data, err := json.MarshalIndent(ctx.DescriptorSet, "", "\t") 22 | 23 | if err != nil { 24 | return err, nil 25 | } 26 | 27 | return nil, data 28 | } 29 | 30 | // 输出到文件 31 | func GenJson(ctx *gen.Context) error { 32 | 33 | err, data := genJsonData(ctx) 34 | 35 | if err != nil { 36 | return err 37 | } 38 | 39 | return ioutil.WriteFile(ctx.OutputFileName, data, 0666) 40 | } 41 | 42 | // 将json输出到标准输出 43 | func OutputJson(ctx *gen.Context) error { 44 | 45 | err, data := genJsonData(ctx) 46 | 47 | if err != nil { 48 | return err 49 | } 50 | 51 | fmt.Println(string(data)) 52 | return nil 53 | } 54 | -------------------------------------------------------------------------------- /gen/route/msgdir.go: -------------------------------------------------------------------------------- 1 | package route 2 | 3 | import ( 4 | "fmt" 5 | "github.com/davyxu/protoplus/model" 6 | "strings" 7 | ) 8 | 9 | type MsgDir struct { 10 | From, Mid, To string 11 | Name string 12 | } 13 | 14 | func (self *MsgDir) Valid() bool { 15 | return self.From != "" && self.To != "" 16 | } 17 | 18 | func (self *MsgDir) HasStar() bool { 19 | if self.From == "*" { 20 | return true 21 | } 22 | 23 | if self.Mid == "*" { 24 | return true 25 | } 26 | 27 | if self.To == "*" { 28 | return true 29 | } 30 | 31 | return false 32 | } 33 | 34 | func (self *MsgDir) Less(Other MsgDir) bool { 35 | 36 | if self.From != Other.From { 37 | return self.From < Other.From 38 | } 39 | 40 | if self.Mid != Other.Mid { 41 | return self.Mid < Other.Mid 42 | } 43 | 44 | if self.To != Other.To { 45 | return self.To < Other.To 46 | } 47 | 48 | return self.Name < Other.Name 49 | } 50 | 51 | func parseMessage(d *model.Descriptor) (rm MsgDir) { 52 | 53 | msgdir := d.TagValueString("MsgDir") 54 | if msgdir == "" { 55 | return 56 | } 57 | 58 | // 上行 59 | if strings.Contains(msgdir, "->") { 60 | endPoints := strings.Split(msgdir, "->") 61 | rm.Name = d.Name 62 | 63 | switch len(endPoints) { 64 | case 3: 65 | rm.From = strings.TrimSpace(endPoints[0]) 66 | 67 | rm.Mid = strings.TrimSpace(endPoints[1]) 68 | 69 | rm.To = strings.TrimSpace(endPoints[2]) 70 | return 71 | case 2: 72 | rm.From = strings.TrimSpace(endPoints[0]) 73 | 74 | rm.To = strings.TrimSpace(endPoints[1]) 75 | return 76 | } 77 | } else if strings.Contains(msgdir, "<-") { // 下行 78 | endPoints := strings.Split(msgdir, "<-") 79 | rm.Name = d.Name 80 | 81 | switch len(endPoints) { 82 | case 3: 83 | rm.From = strings.TrimSpace(endPoints[2]) 84 | 85 | rm.Mid = strings.TrimSpace(endPoints[1]) 86 | 87 | rm.To = strings.TrimSpace(endPoints[0]) 88 | return 89 | case 2: 90 | rm.From = strings.TrimSpace(endPoints[1]) 91 | 92 | rm.To = strings.TrimSpace(endPoints[0]) 93 | return 94 | } 95 | } else { 96 | fmt.Println("unknown msg dir", d.Name, msgdir) 97 | } 98 | 99 | return 100 | } 101 | -------------------------------------------------------------------------------- /gen/route/route.go: -------------------------------------------------------------------------------- 1 | package route 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/davyxu/protoplus/codegen" 7 | "github.com/davyxu/protoplus/gen" 8 | "github.com/davyxu/protoplus/model" 9 | "io/ioutil" 10 | ) 11 | 12 | // 输出到文件 13 | func GenJson(ctx *gen.Context) error { 14 | 15 | data, err := genJsonData(ctx) 16 | 17 | if err != nil { 18 | return err 19 | } 20 | 21 | return ioutil.WriteFile(ctx.OutputFileName, data, 0666) 22 | } 23 | 24 | // 将json输出到标准输出 25 | func OutputJson(ctx *gen.Context) error { 26 | 27 | data, err := genJsonData(ctx) 28 | 29 | if err != nil { 30 | return err 31 | } 32 | 33 | fmt.Println(string(data)) 34 | return nil 35 | } 36 | 37 | func genJsonData(ctx *gen.Context) ([]byte, error) { 38 | 39 | var rt model.RouteTable 40 | 41 | for _, d := range ctx.Structs() { 42 | 43 | msgDir := parseMessage(d) 44 | msgID := codegen.StructMsgID(d) 45 | 46 | if msgDir.Valid() { 47 | 48 | rt.Rule = append(rt.Rule, &model.RouteRule{ 49 | MsgName: ctx.PackageName + "." + d.Name, 50 | SvcType: msgDir.To, 51 | Router: msgDir.Mid, 52 | MsgID: msgID, 53 | }) 54 | } 55 | } 56 | 57 | data, err := json.MarshalIndent(&rt, "", "\t") 58 | 59 | if err != nil { 60 | return nil, err 61 | } 62 | 63 | return data, nil 64 | } 65 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/davyxu/protoplus 2 | 3 | go 1.12 4 | 5 | require ( 6 | // 测试用 7 | github.com/davyxu/golexer v0.1.1-0.20200202091144-a15ddde83f6a 8 | github.com/davyxu/ulexer v0.0.0-20200713054812-c9bb8db3521f 9 | github.com/golang/protobuf v1.5.2 // indirect 10 | github.com/pkg/errors v0.9.1 // indirect 11 | github.com/stretchr/testify v1.7.0 12 | google.golang.org/protobuf v1.28.1 // indirect 13 | ) 14 | 15 | replace github.com/davyxu/ulexer => ../ulexer 16 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/davyxu/golexer v0.1.1-0.20200202091144-a15ddde83f6a h1:VYps2zwgBJPNuLGLiPrR4w6ud6cJpwlBA1OOytrCpx4= 4 | github.com/davyxu/golexer v0.1.1-0.20200202091144-a15ddde83f6a/go.mod h1:dCUDBJcBQ9/AOzz6++KvSetGgVf5zXphevt6LQvKy0A= 5 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 6 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 7 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 8 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 9 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 10 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 11 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 12 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 13 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 14 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 15 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 16 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 17 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 18 | google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= 19 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 20 | google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= 21 | google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 22 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 23 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 24 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 25 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 26 | -------------------------------------------------------------------------------- /model/comment.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | // 注释 4 | type Comment struct { 5 | // 头注释 6 | Leading string `json:",omitempty"` 7 | 8 | // 尾注释 9 | Trailing string `json:",omitempty"` 10 | } 11 | -------------------------------------------------------------------------------- /model/descriptor.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | // 结构体或枚举 9 | type Descriptor struct { 10 | Comment 11 | TagSet 12 | 13 | Name string 14 | 15 | // 枚举或结构体 16 | Kind Kind 17 | 18 | // 归属的文件名 19 | SrcName string 20 | 21 | // 结构体和枚举 22 | Fields []*FieldDescriptor `json:",omitempty"` 23 | 24 | // 服务调用 25 | SvcCall []*ServiceCall `json:",omitempty"` 26 | 27 | DescriptorSet *DescriptorSet `json:"-"` 28 | } 29 | 30 | func (self *Descriptor) FieldByName(name string) *FieldDescriptor { 31 | 32 | for _, o := range self.Fields { 33 | if o.Name == name { 34 | return o 35 | } 36 | } 37 | 38 | return nil 39 | } 40 | 41 | func (self *Descriptor) FieldNameExists(name string) bool { 42 | 43 | for _, o := range self.Fields { 44 | if o.Name == name { 45 | return true 46 | } 47 | } 48 | 49 | return false 50 | } 51 | 52 | func (self *Descriptor) CallNameExists(name string) bool { 53 | 54 | for _, o := range self.SvcCall { 55 | if o.Name == name { 56 | return true 57 | } 58 | } 59 | 60 | return false 61 | } 62 | 63 | func (self *Descriptor) FieldTagExists(tag int) bool { 64 | 65 | // 没填不会重复 66 | if tag == 0 { 67 | return false 68 | } 69 | 70 | for _, o := range self.Fields { 71 | if o.Tag == tag { 72 | return true 73 | } 74 | } 75 | 76 | return false 77 | } 78 | 79 | func (self *Descriptor) AddField(fd *FieldDescriptor) { 80 | self.Fields = append(self.Fields, fd) 81 | } 82 | 83 | func (self *Descriptor) AddSvcCall(sc *ServiceCall) { 84 | self.SvcCall = append(self.SvcCall, sc) 85 | } 86 | 87 | func (self *Descriptor) Size() (size int32) { 88 | 89 | for _, f := range self.Fields { 90 | 91 | if f.Repeatd { 92 | panic(errors.New("Nonsupport repeated")) 93 | } 94 | 95 | switch f.Kind { 96 | case Kind_Primitive: 97 | cs := TypeSize(f.Type) 98 | if cs == 0 { 99 | panic(errors.New(fmt.Sprintf("Nonsupport %s", f.Type))) 100 | } 101 | size += cs 102 | case Kind_Enum: 103 | size += 4 104 | case Kind_Struct: 105 | if cd := self.DescriptorSet.ObjectByName(f.Type); cd != nil { 106 | size += cd.Size() 107 | } 108 | } 109 | } 110 | 111 | return 112 | } 113 | -------------------------------------------------------------------------------- /model/descriptorset.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type DescriptorSet struct { 4 | Objects []*Descriptor `json:",omitempty"` 5 | PackageName string 6 | Codec string 7 | } 8 | 9 | func (self *DescriptorSet) Structs() (ret []*Descriptor) { 10 | 11 | for _, o := range self.Objects { 12 | if o.Kind == Kind_Struct { 13 | ret = append(ret, o) 14 | } 15 | } 16 | 17 | return 18 | } 19 | 20 | func (self *DescriptorSet) Enums() (ret []*Descriptor) { 21 | 22 | for _, o := range self.Objects { 23 | if o.Kind == Kind_Enum { 24 | ret = append(ret, o) 25 | } 26 | } 27 | 28 | return 29 | } 30 | 31 | func (self *DescriptorSet) ObjectNameExists(name string) bool { 32 | 33 | for _, o := range self.Objects { 34 | if o.Name == name { 35 | return true 36 | } 37 | } 38 | 39 | return false 40 | } 41 | 42 | func (self *DescriptorSet) ObjectByName(name string) *Descriptor { 43 | 44 | for _, o := range self.Objects { 45 | if o.Name == name { 46 | return o 47 | } 48 | } 49 | 50 | return nil 51 | } 52 | 53 | func (self *DescriptorSet) AddObject(d *Descriptor) { 54 | self.Objects = append(self.Objects, d) 55 | } 56 | -------------------------------------------------------------------------------- /model/field.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "strings" 4 | 5 | type FieldDescriptor struct { 6 | Comment 7 | TagSet 8 | 9 | Name string 10 | Type string 11 | 12 | Kind Kind // 原始类型/结构体/枚举 13 | 14 | Tag int `json:",omitempty"` 15 | Repeatd bool `json:",omitempty"` 16 | 17 | MapKey string 18 | MapValue string 19 | 20 | Descriptor *Descriptor `json:"-"` // 字段归属的父级描述符 21 | } 22 | 23 | func (self *FieldDescriptor) IsMap() bool { 24 | return self.MapKey != "" && self.MapValue != "" 25 | } 26 | 27 | func (self *FieldDescriptor) ParseType(str string) { 28 | 29 | if strings.Contains(str, "map") { 30 | println(str) 31 | } 32 | 33 | self.Type = SchemeType2Type[str] 34 | if self.Type != "" { 35 | self.Kind = Kind_Primitive 36 | } else { 37 | // 复杂类型 38 | self.Type = str 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /model/pbdescset.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "sort" 4 | 5 | type PBDescriptorSet struct { 6 | DescriptorSet 7 | 8 | // pb生成文件依赖时, 使用以下字段 9 | DependentSource []string // 按文件管理的描述符取出时, 这个字段有效. 本文件依赖的其他source的symbiol 10 | SourceName string // 按文件管理的描述符取出时, 这个字段有效. 表示本DescriptorSet的文件名 11 | dsBySource map[string]*PBDescriptorSet // 按文件名管理的描述符集合 12 | } 13 | 14 | func (self *PBDescriptorSet) addDependentSource(name string) { 15 | 16 | if self.SourceName == name { 17 | return 18 | } 19 | 20 | for _, n := range self.DependentSource { 21 | if n == name { 22 | return 23 | } 24 | } 25 | 26 | self.DependentSource = append(self.DependentSource, name) 27 | } 28 | 29 | func (self *PBDescriptorSet) SourceList() (ret []string) { 30 | for sourceName := range self.DescriptorSetBySource() { 31 | ret = append(ret, sourceName) 32 | } 33 | 34 | sort.Strings(ret) 35 | return 36 | } 37 | 38 | func (self *PBDescriptorSet) DescriptorSetBySource() map[string]*PBDescriptorSet { 39 | if self.dsBySource != nil { 40 | return self.dsBySource 41 | } 42 | 43 | self.dsBySource = map[string]*PBDescriptorSet{} 44 | 45 | for _, obj := range self.Objects { 46 | ds := self.dsBySource[obj.SrcName] 47 | if ds == nil { 48 | ds = &PBDescriptorSet{} 49 | 50 | ds.PackageName = self.PackageName 51 | ds.Codec = self.Codec 52 | ds.SourceName = obj.SrcName 53 | 54 | self.dsBySource[obj.SrcName] = ds 55 | } 56 | 57 | ds.AddObject(obj) 58 | } 59 | 60 | for _, file := range self.dsBySource { 61 | for _, st := range file.Structs() { 62 | 63 | for _, fd := range st.Fields { 64 | 65 | switch fd.Kind { 66 | case Kind_Struct, Kind_Enum: 67 | refTarget := self.ObjectByName(fd.Type) 68 | if refTarget != nil { 69 | file.addDependentSource(refTarget.SrcName) 70 | } 71 | } 72 | } 73 | } 74 | } 75 | 76 | return self.dsBySource 77 | } 78 | -------------------------------------------------------------------------------- /model/route.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | // 路由规则 4 | type RouteRule struct { 5 | MsgName string 6 | MsgID int 7 | 8 | SvcType string 9 | Router string `json:",omitempty"` 10 | } 11 | 12 | // 路由表,包含多条路由规则 13 | type RouteTable struct { 14 | Rule []*RouteRule 15 | } 16 | -------------------------------------------------------------------------------- /model/service.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type ServiceCall struct { 4 | Comment 5 | TagSet 6 | 7 | IsRPC bool 8 | 9 | Name string // 函数名 10 | RequestName string // 请求消息名 11 | RespondName string // 回应消息名 12 | } 13 | -------------------------------------------------------------------------------- /model/tag.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "strconv" 4 | 5 | // 标记 6 | type Tag struct { 7 | Key string 8 | Value string 9 | } 10 | 11 | // 标记集合 12 | type TagSet struct { 13 | Tags []Tag `json:",omitempty"` 14 | } 15 | 16 | func (self *TagSet) TagValueByKey(key string) (string, bool) { 17 | for _, tag := range self.Tags { 18 | if tag.Key == key { 19 | return tag.Value, true 20 | } 21 | } 22 | 23 | return "", false 24 | } 25 | 26 | func (self *TagSet) SetTagValue(key, value string) { 27 | 28 | for index, tag := range self.Tags { 29 | if tag.Key == key { 30 | self.Tags[index].Value = value 31 | break 32 | } 33 | } 34 | } 35 | 36 | func (self *TagSet) TagExists(key string) bool { 37 | for _, tag := range self.Tags { 38 | if tag.Key == key { 39 | return true 40 | } 41 | } 42 | return false 43 | } 44 | 45 | func (self *TagSet) TagValueInt(key string) int { 46 | if v, ok := self.TagValueByKey(key); ok { 47 | if r, err := strconv.Atoi(v); err == nil { 48 | return r 49 | } 50 | } 51 | 52 | return 0 53 | } 54 | 55 | func (self *TagSet) TagValueString(key string) string { 56 | v, _ := self.TagValueByKey(key) 57 | return v 58 | } 59 | 60 | func (self *TagSet) TagValueBool(key string) bool { 61 | if v, ok := self.TagValueByKey(key); ok { 62 | if r, err := strconv.ParseBool(v); err == nil { 63 | return r 64 | } 65 | } 66 | 67 | return false 68 | } 69 | 70 | func (self *TagSet) AddTag(tag Tag) { 71 | self.Tags = append(self.Tags, tag) 72 | } 73 | -------------------------------------------------------------------------------- /model/type.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Kind string 4 | 5 | const ( 6 | Kind_None Kind = "" 7 | Kind_Primitive = "primitive" 8 | Kind_Struct = "struct" 9 | Kind_Enum = "enum" 10 | ) 11 | 12 | var SchemeType2Type = map[string]string{ 13 | "int8": "int8", 14 | "int16": "int16", 15 | "int32": "int32", 16 | "int64": "int64", 17 | "uint8": "uint8", 18 | "uint16": "uint16", 19 | "uint32": "uint32", 20 | "uint64": "uint64", 21 | "float32": "float32", 22 | "float64": "float64", 23 | "bool": "bool", 24 | "string": "string", 25 | "bytes": "bytes", 26 | } 27 | 28 | func TypeSize(t string) int32 { 29 | switch t { 30 | case "int8": 31 | return 1 32 | case "int16": 33 | return 2 34 | case "int32": 35 | return 4 36 | case "int64": 37 | return 8 38 | case "uint8": 39 | return 1 40 | case "uint16": 41 | return 2 42 | case "uint32": 43 | return 4 44 | case "uint64": 45 | return 8 46 | case "float32": 47 | return 4 48 | case "float64": 49 | return 8 50 | case "bool": 51 | return 1 52 | default: 53 | return 0 54 | 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /parser/context.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "github.com/davyxu/golexer" 5 | "github.com/davyxu/protoplus/model" 6 | "strings" 7 | ) 8 | 9 | type Context struct { 10 | 11 | // 每个文件对应的属性 12 | SourceName string 13 | 14 | *protoParser 15 | 16 | *model.DescriptorSet 17 | 18 | // 全局属性 19 | symbolPos map[interface{}]golexer.TokenPos 20 | 21 | sourceByName map[string]struct{} 22 | } 23 | 24 | func (self *Context) AddSource(sourceName string) bool { 25 | lowerName := strings.ToLower(sourceName) 26 | if _, ok := self.sourceByName[lowerName]; ok { 27 | return false 28 | } 29 | 30 | self.sourceByName[lowerName] = struct{}{} 31 | 32 | return true 33 | } 34 | 35 | func (self *Context) QuerySymbolPosString(v interface{}) string { 36 | 37 | if s, ok := self.symbolPos[v]; ok { 38 | return s.String() 39 | } 40 | 41 | return "" 42 | } 43 | 44 | func (self *Context) AddSymbol(v interface{}, pos golexer.TokenPos) { 45 | self.symbolPos[v] = pos 46 | } 47 | 48 | func (self *Context) Clone(srcName string) *Context { 49 | 50 | return &Context{ 51 | SourceName: srcName, 52 | symbolPos: self.symbolPos, 53 | sourceByName: self.sourceByName, 54 | DescriptorSet: self.DescriptorSet, 55 | } 56 | } 57 | 58 | func newContext() *Context { 59 | 60 | return &Context{ 61 | symbolPos: map[interface{}]golexer.TokenPos{}, 62 | sourceByName: map[string]struct{}{}, 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /parser/entry.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "github.com/davyxu/protoplus/model" 5 | "strings" 6 | ) 7 | 8 | func ParseFile(fileName string) (*model.DescriptorSet, error) { 9 | 10 | var dset model.DescriptorSet 11 | 12 | return &dset, ParseFileList(&dset, fileName) 13 | } 14 | 15 | func ParseString(script string) (*model.DescriptorSet, error) { 16 | 17 | ctx := newContext() 18 | ctx.SourceName = "string" 19 | ctx.DescriptorSet = new(model.DescriptorSet) 20 | 21 | if err := rawParse(ctx, strings.NewReader(script)); err != nil { 22 | return nil, err 23 | } 24 | 25 | return ctx.DescriptorSet, checkAndFix(ctx) 26 | } 27 | 28 | func ParseFileList(dset *model.DescriptorSet, filelist ...string) error { 29 | 30 | ctx := newContext() 31 | ctx.DescriptorSet = dset 32 | 33 | for _, filename := range filelist { 34 | err := parseFile(ctx, filename) 35 | if err != nil { 36 | return err 37 | } 38 | } 39 | 40 | return checkAndFix(ctx) 41 | } 42 | -------------------------------------------------------------------------------- /parser/enumfield.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "errors" 5 | "github.com/davyxu/protoplus/model" 6 | ) 7 | 8 | func parseEnumField(ctx *Context, fd *model.FieldDescriptor) { 9 | 10 | // 注释 11 | nameToken := ctx.RawToken() 12 | 13 | // 字段名 14 | fd.Name = ctx.Expect(Token_Identifier).Value() 15 | 16 | if fd.Descriptor.FieldNameExists(fd.Name) { 17 | panic(errors.New("Duplicate field name: " + fd.Name)) 18 | } 19 | 20 | // 有等号 21 | if ctx.TokenID() == Token_Assign { 22 | ctx.NextToken() 23 | 24 | // tag 25 | fd.Tag = ctx.Expect(Token_Numeral).ToInt() 26 | 27 | } else { // 没等号自动生成枚举序号 28 | 29 | //if len(ctx.Fields) == 0 { 30 | // //fd.AutoTag = 0 31 | //} else { 32 | // 33 | // // 按前面的序号+1 34 | // //fd.AutoTag = d.MaxTag() + 1 35 | //} 36 | 37 | } 38 | 39 | fd.Comment = ctx.CommentGroupByLine(nameToken.Line()) 40 | 41 | // 枚举值类型,始终为int32 42 | fd.ParseType("int32") 43 | 44 | fd.Descriptor.AddField(fd) 45 | 46 | return 47 | } 48 | -------------------------------------------------------------------------------- /parser/parse_descriptor.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "errors" 5 | "github.com/davyxu/protoplus/model" 6 | ) 7 | 8 | func parseObject(ctx *Context, d *model.Descriptor) { 9 | 10 | keywordToken := ctx.RawToken() 11 | 12 | ctx.NextToken() 13 | 14 | // 名字 15 | d.Name = ctx.Expect(Token_Identifier).Value() 16 | 17 | // 名字上面的注释 18 | 19 | // { 20 | ctx.Expect(Token_CurlyBraceL) 21 | 22 | for ctx.TokenID() != Token_CurlyBraceR { 23 | 24 | var fd model.FieldDescriptor 25 | fd.Descriptor = d 26 | 27 | switch d.Kind { 28 | case model.Kind_Struct: 29 | parseStructField(ctx, &fd) 30 | case model.Kind_Enum: 31 | parseEnumField(ctx, &fd) 32 | } 33 | 34 | // 读取字段后面的[Tag项] 35 | if ctx.TokenID() == Token_BracketL { 36 | fd.TagSet = parseTagSet(ctx) 37 | } 38 | 39 | } 40 | 41 | ctx.Expect(Token_CurlyBraceR) 42 | 43 | // } 44 | 45 | d.Comment = ctx.CommentGroupByLine(keywordToken.Line()) 46 | 47 | // 名字重复检查 48 | 49 | if ctx.DescriptorSet.ObjectNameExists(d.Name) { 50 | panic(errors.New("Duplicate name: " + d.Name)) 51 | } 52 | 53 | ctx.AddObject(d) 54 | 55 | } 56 | -------------------------------------------------------------------------------- /parser/parse_descriptorset.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "github.com/davyxu/golexer" 7 | "github.com/davyxu/protoplus/model" 8 | "io" 9 | "io/ioutil" 10 | "strings" 11 | ) 12 | 13 | // 解析字符串 14 | func rawParse(ctx *Context, reader io.Reader) (retErr error) { 15 | 16 | data, err := ioutil.ReadAll(reader) 17 | 18 | if err != nil { 19 | return retErr 20 | } 21 | 22 | ctx.protoParser = newProtoParser(ctx.SourceName) 23 | 24 | defer golexer.ErrorCatcher(func(err error) { 25 | 26 | retErr = fmt.Errorf("%s %s", ctx.PreTokenPos().String(), err.Error()) 27 | 28 | }) 29 | 30 | ctx.Lexer().Start(string(data)) 31 | 32 | ctx.NextToken() 33 | 34 | for ctx.TokenID() != Token_EOF { 35 | 36 | var d model.Descriptor 37 | d.SrcName = ctx.SourceName 38 | 39 | if ctx.TokenID() == Token_BracketL { 40 | d.TagSet = parseTagSet(ctx) 41 | } 42 | 43 | switch ctx.TokenID() { 44 | case Token_Struct: 45 | d.Kind = model.Kind_Struct 46 | parseObject(ctx, &d) 47 | case Token_Enum: 48 | d.Kind = model.Kind_Enum 49 | parseObject(ctx, &d) 50 | case Token_Import: 51 | retErr = parseImport(ctx) 52 | if retErr != nil { 53 | return retErr 54 | } 55 | default: 56 | panic(errors.New("Unknown token: " + ctx.TokenValue())) 57 | } 58 | 59 | } 60 | 61 | return 62 | } 63 | 64 | func checkAndFix(ctx *Context) error { 65 | 66 | for _, d := range ctx.Objects { 67 | 68 | d.DescriptorSet = ctx.DescriptorSet 69 | 70 | for _, fd := range d.Fields { 71 | fd.Descriptor = d 72 | 73 | if fd.Kind == "" { 74 | 75 | if fd.IsMap() { 76 | 77 | } else { 78 | // 将字段中使用的结构体的Kind确认为struct 79 | findD := ctx.ObjectByName(fd.Type) 80 | if findD == nil { 81 | return errors.New(fmt.Sprintf("type not found: %s at %s", fd.Type, ctx.QuerySymbolPosString(fd))) 82 | } 83 | fd.Kind = findD.Kind 84 | } 85 | 86 | } 87 | } 88 | 89 | for _, sc := range d.SvcCall { 90 | findREQ := ctx.ObjectByName(sc.RequestName) 91 | if findREQ == nil { 92 | return errors.New(fmt.Sprintf("type not found: %s at %s", sc.RequestName, ctx.QuerySymbolPosString(sc))) 93 | } 94 | 95 | findACK := ctx.ObjectByName(sc.RespondName) 96 | if findACK == nil { 97 | return errors.New(fmt.Sprintf("type not found: %s at %s", sc.RespondName, ctx.QuerySymbolPosString(sc))) 98 | } 99 | } 100 | 101 | if !d.TagExists("AutoMsgID") && !d.TagExists("MsgID") && (strings.HasSuffix(d.Name, "REQ") || strings.HasSuffix(d.Name, "ACK")) { 102 | return fmt.Errorf("struct like message but not gen msgid: %s", d.Name) 103 | } 104 | 105 | if d.Kind == model.Kind_Struct && (d.TagExists("AutoMsgID") || d.TagExists("MsgID")) && (!strings.HasSuffix(d.Name, "REQ") && !strings.HasSuffix(d.Name, "ACK")) { 106 | return fmt.Errorf("struct gen msgid, but not like a message(REQ/ACK) : %s", d.Name) 107 | } 108 | } 109 | 110 | return nil 111 | 112 | } 113 | -------------------------------------------------------------------------------- /parser/parse_import.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "os" 5 | ) 6 | 7 | func parseImport(ctx *Context) error { 8 | 9 | ctx.NextToken() 10 | 11 | fileName := ctx.Expect(Token_String).Value() 12 | 13 | return parseFile(ctx, fileName) 14 | } 15 | 16 | func parseFile(ctx *Context, fileName string) error { 17 | if !ctx.AddSource(fileName) { 18 | return nil 19 | } 20 | 21 | file, err := os.Open(fileName) 22 | 23 | if err != nil { 24 | return err 25 | } 26 | 27 | defer file.Close() 28 | 29 | newCtx := ctx.Clone(fileName) 30 | 31 | return rawParse(newCtx, file) 32 | } 33 | -------------------------------------------------------------------------------- /parser/parse_tag.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import "github.com/davyxu/protoplus/model" 4 | 5 | func parseTagSet(ctx *Context) (ts model.TagSet) { 6 | 7 | // [ 8 | if ctx.TokenID() != Token_BracketL { 9 | return 10 | } 11 | 12 | ctx.NextToken() 13 | 14 | for ctx.TokenID() != Token_BracketR { 15 | 16 | var tag model.Tag 17 | tag.Key = ctx.Expect(Token_Identifier).Value() 18 | 19 | if ctx.TokenID() == Token_Colon { 20 | 21 | ctx.Expect(Token_Colon).Value() 22 | 23 | tag.Value = ctx.TokenValue() 24 | 25 | ctx.NextToken() 26 | } 27 | 28 | ts.AddTag(tag) 29 | 30 | } 31 | 32 | ctx.Expect(Token_BracketR) 33 | 34 | return 35 | } 36 | -------------------------------------------------------------------------------- /parser/parse_test.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/davyxu/golexer" 6 | "github.com/davyxu/protoplus/model" 7 | "strings" 8 | "testing" 9 | ) 10 | 11 | func checkString(t *testing.T, script string) *model.DescriptorSet { 12 | 13 | if ds, err := ParseString(script); err != nil { 14 | t.Error(err) 15 | t.FailNow() 16 | } else { 17 | if data, err := json.MarshalIndent(ds, "", "\t"); err != nil { 18 | t.Error(err) 19 | t.FailNow() 20 | } else { 21 | t.Log(string(data)) 22 | } 23 | 24 | return ds 25 | } 26 | 27 | return nil 28 | } 29 | 30 | func mustError(t *testing.T, script string, expectErrStr string) { 31 | 32 | if _, err := ParseString(script); err == nil || !strings.Contains(err.Error(), expectErrStr) { 33 | t.Log("[error not match]", err) 34 | t.FailNow() 35 | } 36 | } 37 | 38 | func TestDuplicateName(t *testing.T) { 39 | 40 | mustError(t, ` 41 | enum Vocation { 42 | 43 | } 44 | enum Vocation { 45 | 46 | } 47 | `, "Duplicate name: Vocation") 48 | 49 | mustError(t, ` 50 | struct Vocation { 51 | 52 | } 53 | struct Vocation { 54 | 55 | } 56 | `, "Duplicate name: Vocation") 57 | 58 | } 59 | 60 | func TestFieldTypeNotFound(t *testing.T) { 61 | 62 | mustError(t, ` 63 | struct Vocation { 64 | n Node 65 | } 66 | 67 | `, "type not found: Vocation") 68 | 69 | } 70 | 71 | func TestComment(t *testing.T) { 72 | 73 | ds := checkString(t, ` 74 | 75 | // 枚举头注释 76 | enum Enum{ 77 | 78 | // 枚举字段注释 79 | A // 枚举字段尾注释 80 | } 81 | 82 | `) 83 | 84 | if ds.ObjectByName("Enum").Leading != "枚举头注释" { 85 | t.FailNow() 86 | } 87 | 88 | fd := ds.ObjectByName("Enum").FieldByName("A") 89 | if fd.Leading != "枚举字段注释" { 90 | t.FailNow() 91 | } 92 | 93 | if fd.Trailing != "枚举字段尾注释" { 94 | t.FailNow() 95 | } 96 | } 97 | 98 | func TestTags(t *testing.T) { 99 | 100 | ds := checkString(t, ` 101 | 102 | [MsgID:201 CSRequestOnce:true Dir:"client->game"] 103 | struct s1 { 104 | 105 | } 106 | 107 | struct s2{ 108 | [x: 1 y :2] 109 | f int32 110 | } 111 | `) 112 | 113 | if ds.ObjectByName("s1").TagValueInt("MsgID") != 201 { 114 | t.FailNow() 115 | } 116 | 117 | if ds.ObjectByName("s1").TagValueBool("CSRequestOnce") != true { 118 | t.FailNow() 119 | } 120 | 121 | if ds.ObjectByName("s1").TagValueString("Dir") != "client->game" { 122 | t.FailNow() 123 | } 124 | 125 | fd := ds.ObjectByName("s2").FieldByName("f") 126 | 127 | if fd.TagValueInt("x") != 1 { 128 | t.FailNow() 129 | } 130 | 131 | if fd.TagValueInt("y") != 2 { 132 | t.FailNow() 133 | } 134 | } 135 | 136 | func TestParseString(t *testing.T) { 137 | 138 | checkString(t, ` 139 | 140 | enum Vocation { 141 | Monkey 142 | Monk 143 | Pig 144 | } 145 | 146 | struct PhoneNumber { 147 | 148 | number string 149 | 150 | type int32 151 | } 152 | 153 | 154 | struct Person { 155 | 156 | name string 157 | 158 | id int32 159 | 160 | email string 161 | 162 | phone PhoneNumber 163 | 164 | voc Vocation 165 | } 166 | 167 | struct AddressBook { 168 | 169 | person []Person 170 | } 171 | 172 | struct Node{ 173 | node []Node 174 | } 175 | 176 | `) 177 | 178 | } 179 | 180 | func TestTagsNoColon(t *testing.T) { 181 | 182 | ds := checkString(t, ` 183 | 184 | [MsgID:201 AutoMsgID CSRequestOnce Dir:"client->game"] 185 | struct s1 { 186 | 187 | } 188 | 189 | `) 190 | 191 | if ds.ObjectByName("s1").TagValueInt("MsgID") != 201 { 192 | t.FailNow() 193 | } 194 | 195 | if _, exists := ds.ObjectByName("s1").TagValueByKey("AutoMsgID"); exists != true { 196 | t.FailNow() 197 | } 198 | 199 | if _, exists := ds.ObjectByName("s1").TagValueByKey("CSRequestOnce"); exists != true { 200 | t.FailNow() 201 | } 202 | 203 | if ds.ObjectByName("s1").TagValueString("Dir") != "client->game" { 204 | t.FailNow() 205 | } 206 | 207 | } 208 | 209 | func sizeOfMustError(t *testing.T, script, name string, expectErrStr string) { 210 | 211 | ds := checkString(t, script) 212 | 213 | defer golexer.ErrorCatcher(func(err error) { 214 | 215 | if err == nil || !strings.Contains(err.Error(), expectErrStr) { 216 | t.Log("[error not match]", err) 217 | t.FailNow() 218 | } 219 | 220 | }) 221 | 222 | ds.ObjectByName(name).Size() 223 | 224 | } 225 | 226 | func TestSizeOfNonsupport(t *testing.T) { 227 | 228 | sizeOfMustError(t, ` 229 | 230 | struct PhoneNumber { 231 | 232 | number string 233 | 234 | type int32 235 | } 236 | `, "PhoneNumber", "Nonsupport string") 237 | 238 | sizeOfMustError(t, ` 239 | 240 | struct PhoneNumber { 241 | 242 | number []int64 243 | 244 | type int32 245 | } 246 | `, "PhoneNumber", "Nonsupport repeated") 247 | 248 | } 249 | 250 | func TestSizeOf(t *testing.T) { 251 | 252 | ds := checkString(t, ` 253 | 254 | enum Sex 255 | { 256 | Man 257 | Woman 258 | } 259 | 260 | struct PhoneNumber { 261 | 262 | number int64 263 | 264 | type int32 265 | } 266 | 267 | 268 | struct Person { 269 | 270 | id int32 271 | 272 | phone PhoneNumber 273 | 274 | phone2 PhoneNumber 275 | 276 | sex Sex 277 | 278 | } 279 | 280 | `) 281 | 282 | if size := ds.ObjectByName("Person").Size(); size != 32 { 283 | t.FailNow() 284 | } 285 | 286 | } 287 | 288 | func TestMap(t *testing.T) { 289 | ds := checkString(t, ` 290 | struct Data { 291 | 292 | idList []int32 293 | Mapper map[int32]string 294 | } 295 | `) 296 | 297 | ds.ObjectByName("Data") 298 | } 299 | -------------------------------------------------------------------------------- /parser/parser.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | 7 | "github.com/davyxu/golexer" 8 | "github.com/davyxu/protoplus/model" 9 | "strings" 10 | ) 11 | 12 | // 自定义的token id 13 | const ( 14 | Token_EOF = iota 15 | Token_Unknown 16 | Token_LineEnd 17 | Token_Numeral 18 | Token_String 19 | Token_WhiteSpace 20 | Token_Identifier 21 | Token_UnixComment 22 | Token_CStyleComment 23 | Token_Colon // : 24 | Token_ParenL // ( 25 | Token_ParenR // ) 26 | Token_CurlyBraceL // { 27 | Token_CurlyBraceR // } 28 | Token_BracketL // [ 29 | Token_BracketR // ] 30 | Token_Dot // . 31 | Token_Enum // enum 32 | Token_Struct // struct 33 | Token_Assign // = 34 | Token_Service // service 35 | Token_RPC // rpc 36 | Token_Import // import 37 | Token_Map // map 38 | ) 39 | 40 | type protoParser struct { 41 | *golexer.Parser 42 | 43 | commentsByLine map[int]string 44 | } 45 | 46 | func (self *protoParser) Expect(id int) golexer.Token { 47 | 48 | if self.Parser.TokenID() != id { 49 | panic(errors.New("Expect " + self.Lexer().MatcherString(id))) 50 | } 51 | 52 | t := self.RawToken() 53 | 54 | self.NextToken() 55 | 56 | return t 57 | } 58 | 59 | func (self *protoParser) NextToken() { 60 | 61 | for { 62 | self.Parser.NextToken() 63 | 64 | switch self.TokenID() { 65 | 66 | case Token_UnixComment, 67 | Token_CStyleComment: 68 | self.commentsByLine[self.RawToken().Line()] = self.TokenValue() 69 | default: 70 | return 71 | } 72 | } 73 | 74 | } 75 | 76 | func (self *protoParser) CommentGroupByLine(line int) model.Comment { 77 | 78 | var comment model.Comment 79 | 80 | if commentStr, ok := self.commentsByLine[line]; ok { 81 | comment.Trailing = strings.TrimSpace(commentStr) 82 | } 83 | 84 | var buff bytes.Buffer 85 | 86 | start := line - 1 87 | var end int 88 | 89 | // 从当前行往上找连在一起的注释 90 | for i := line - 1; i >= 1; i-- { 91 | 92 | if _, ok := self.commentsByLine[i]; !ok { 93 | end = i 94 | break 95 | } 96 | 97 | } 98 | 99 | for i := end; i <= start; i++ { 100 | 101 | comment, _ := self.commentsByLine[i] 102 | 103 | if buff.Len() > 0 { 104 | buff.WriteString("\n") 105 | } 106 | 107 | buff.WriteString(strings.TrimSpace(comment)) 108 | } 109 | 110 | comment.Leading = buff.String() 111 | 112 | return comment 113 | } 114 | 115 | func newProtoParser(srcName string) *protoParser { 116 | 117 | l := golexer.NewLexer() 118 | 119 | // 匹配顺序从高到低 120 | 121 | l.AddMatcher(golexer.NewNumeralMatcher(Token_Numeral)) 122 | l.AddMatcher(golexer.NewStringMatcher(Token_String)) 123 | 124 | l.AddIgnoreMatcher(golexer.NewWhiteSpaceMatcher(Token_WhiteSpace)) 125 | l.AddIgnoreMatcher(golexer.NewLineEndMatcher(Token_LineEnd)) 126 | l.AddMatcher(golexer.NewUnixStyleCommentMatcher(Token_UnixComment)) 127 | l.AddMatcher(golexer.NewCStyleCommentMatcher(Token_CStyleComment)) 128 | 129 | l.AddMatcher(golexer.NewSignMatcher(Token_CurlyBraceL, "{")) 130 | l.AddMatcher(golexer.NewSignMatcher(Token_CurlyBraceR, "}")) 131 | l.AddMatcher(golexer.NewSignMatcher(Token_ParenL, "(")) 132 | l.AddMatcher(golexer.NewSignMatcher(Token_ParenR, ")")) 133 | l.AddMatcher(golexer.NewSignMatcher(Token_BracketL, "[")) 134 | l.AddMatcher(golexer.NewSignMatcher(Token_BracketR, "]")) 135 | l.AddMatcher(golexer.NewSignMatcher(Token_Dot, ".")) 136 | l.AddMatcher(golexer.NewSignMatcher(Token_Assign, "=")) 137 | l.AddMatcher(golexer.NewSignMatcher(Token_Colon, ":")) 138 | l.AddMatcher(golexer.NewKeywordMatcher(Token_Enum, "enum")) 139 | l.AddMatcher(golexer.NewKeywordMatcher(Token_Struct, "struct")) 140 | l.AddMatcher(golexer.NewKeywordMatcher(Token_Service, "service")) 141 | l.AddMatcher(golexer.NewKeywordMatcher(Token_RPC, "rpc")) 142 | l.AddMatcher(golexer.NewKeywordMatcher(Token_Import, "import")) 143 | l.AddMatcher(golexer.NewKeywordMatcher(Token_Map, "map")) 144 | 145 | l.AddMatcher(golexer.NewIdentifierMatcher(Token_Identifier)) 146 | 147 | l.AddMatcher(golexer.NewUnknownMatcher(Token_Unknown)) 148 | 149 | return &protoParser{ 150 | Parser: golexer.NewParser(l, srcName), 151 | commentsByLine: make(map[int]string), 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /parser/structfield.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "errors" 5 | "github.com/davyxu/protoplus/model" 6 | ) 7 | 8 | func parseStructField(ctx *Context, fd *model.FieldDescriptor) { 9 | 10 | // 注释 11 | nameToken := ctx.RawToken() 12 | 13 | // 字段名 14 | fd.Name = ctx.Expect(Token_Identifier).Value() 15 | 16 | if fd.Descriptor.FieldNameExists(fd.Name) { 17 | panic(errors.New("Duplicate field name: " + fd.Name)) 18 | } 19 | 20 | tp := ctx.TokenPos() 21 | 22 | switch ctx.TokenID() { 23 | case Token_BracketL: // [ 数组类型 24 | ctx.NextToken() 25 | ctx.Expect(Token_BracketR) 26 | fd.Repeatd = true 27 | // 延后在所有解析完后,检查TypeName是否合法,通过symbol还原位置并报错 28 | fd.ParseType(ctx.Expect(Token_Identifier).Value()) 29 | case Token_Map: 30 | ctx.NextToken() 31 | ctx.Expect(Token_BracketL) 32 | fd.MapKey = ctx.Expect(Token_Identifier).Value() 33 | ctx.Expect(Token_BracketR) 34 | fd.MapValue = ctx.Expect(Token_Identifier).Value() 35 | default: 36 | // 延后在所有解析完后,检查TypeName是否合法,通过symbol还原位置并报错 37 | fd.ParseType(ctx.Expect(Token_Identifier).Value()) 38 | } 39 | 40 | fd.Comment = ctx.CommentGroupByLine(nameToken.Line()) 41 | 42 | ctx.AddSymbol(fd, tp) 43 | 44 | fd.Descriptor.AddField(fd) 45 | 46 | return 47 | } 48 | -------------------------------------------------------------------------------- /tests/Make.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | go build -v -o=${GOPATH}/bin/protoplus github.com/davyxu/protoplus/cmd/protoplus 6 | 7 | # code.proto为输入文件 8 | ProtoPlusBin=${GOPATH}/bin/protoplus 9 | 10 | # 原生输出请使用pb 11 | #${ProtoPlusBin} -ppgo_out=code_gen.go -package=tests filelist.proto 12 | #${ProtoPlusBin} -ppcs_out=../example/csharp/Example/ProtoGen.cs -package=Proto filelist.proto 13 | 14 | ${ProtoPlusBin} -ppgoreg_out=reg_gen.go -package=tests filelist.proto 15 | ${ProtoPlusBin} -ppcsreg_out=../example/csharp/Example/ProtoGenReg.cs -package=Proto filelist.proto 16 | ${ProtoPlusBin} -pbscheme_out=pb_gen.proto -package=proto filelist.proto 17 | ${ProtoPlusBin} -route_out=route.json -package=proto filelist.proto -------------------------------------------------------------------------------- /tests/code_gen.go: -------------------------------------------------------------------------------- 1 | // Generated by github.com/davyxu/protoplus 2 | // DO NOT EDIT! 3 | package tests 4 | 5 | import ( 6 | "github.com/davyxu/protoplus/api/golang" 7 | "github.com/davyxu/protoplus/api/golang/wire" 8 | "unsafe" 9 | ) 10 | 11 | var ( 12 | _ *wire.Buffer 13 | _ = ppgo.Marshal 14 | _ unsafe.Pointer 15 | ) 16 | 17 | type LoginREQ struct { 18 | } 19 | 20 | func (self *LoginREQ) String() string { return ppgo.CompactTextString(self) } 21 | 22 | func (self *LoginREQ) Size() (ret int) { 23 | 24 | return 25 | } 26 | 27 | func (self *LoginREQ) Marshal(buffer *wire.Buffer) error { 28 | 29 | return nil 30 | } 31 | 32 | func (self *LoginREQ) Unmarshal(buffer *wire.Buffer, fieldIndex uint64, wt wire.WireType) error { 33 | switch fieldIndex { 34 | 35 | } 36 | 37 | return wire.ErrUnknownField 38 | } 39 | 40 | type LoginACK struct { 41 | } 42 | 43 | func (self *LoginACK) String() string { return ppgo.CompactTextString(self) } 44 | 45 | func (self *LoginACK) Size() (ret int) { 46 | 47 | return 48 | } 49 | 50 | func (self *LoginACK) Marshal(buffer *wire.Buffer) error { 51 | 52 | return nil 53 | } 54 | 55 | func (self *LoginACK) Unmarshal(buffer *wire.Buffer, fieldIndex uint64, wt wire.WireType) error { 56 | switch fieldIndex { 57 | 58 | } 59 | 60 | return wire.ErrUnknownField 61 | } 62 | -------------------------------------------------------------------------------- /tests/code_test.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/stretchr/testify/assert" 6 | //_ "github.com/davyxu/cellnet/codec/protoplus" 7 | "github.com/davyxu/protoplus/api/golang" 8 | //"github.com/stretchr/testify/assert" 9 | "math" 10 | "reflect" 11 | "testing" 12 | ) 13 | 14 | func TestOptional(t *testing.T) { 15 | bigData := makeMyType() 16 | data, err := ppgo.Marshal(&bigData) 17 | assert.Equal(t, err, nil) 18 | var output MyTypeMini 19 | assert.Equal(t, ppgo.Unmarshal(data, &output), nil) 20 | 21 | //t.Logf("%+v", output) 22 | //assert.Equal(t, bigData, output) 23 | 24 | } 25 | 26 | func makeMyType() (input MyType) { 27 | 28 | input.Bool = true 29 | input.Int32 = 200 30 | input.UInt32 = math.MaxUint32 - 100 31 | input.Int64 = -789 32 | input.UInt64 = 1234567890123456 33 | input.Str = "hello" 34 | input.Float32 = 3.14 35 | input.Float64 = math.MaxFloat64 36 | 37 | input.BoolSlice = []bool{true, false, true} 38 | input.Int32Slice = []int32{1, 2, 3, 4} 39 | input.UInt32Slice = []uint32{100, 200, 300, 400} 40 | input.Int64Slice = []int64{1, 2, 3, 4} 41 | input.UInt64Slice = []uint64{100, 200, 300, 400} 42 | input.StrSlice = []string{"genji", "dva", "bastion"} 43 | input.Float32Slice = []float32{1.1, 2.1, 3.2, 4.5} 44 | input.Float64Slice = []float64{1.1, 2.1, 3.2, 4.5} 45 | input.BytesSlice = []byte("bytes") 46 | input.Enum = MyEnum_Two 47 | input.EnumSlice = []MyEnum{MyEnum_Two, MyEnum_One, MyEnum_Zero} 48 | 49 | input.Struct = &MySubType{ 50 | Str: "world", 51 | } 52 | 53 | input.StructSlice = []*MySubType{ 54 | {Int32: 100}, 55 | {Str: "200"}, 56 | } 57 | 58 | return 59 | } 60 | 61 | func verifyWire(t *testing.T, raw ppgo.Struct) { 62 | data, err := ppgo.Marshal(raw) 63 | assert.Equal(t, err, nil) 64 | 65 | t.Log("proto+:", len(data), data) 66 | 67 | newType := reflect.New(reflect.TypeOf(raw).Elem()).Interface().(ppgo.Struct) 68 | 69 | assert.Equal(t, ppgo.Unmarshal(data, newType), nil) 70 | 71 | assert.Equal(t, raw, newType) 72 | } 73 | 74 | func verifyText(t *testing.T, raw interface{}) { 75 | 76 | tRaw := reflect.TypeOf(raw) 77 | 78 | if tRaw.Kind() != reflect.Ptr { 79 | panic("expect ptr") 80 | } 81 | 82 | data := ppgo.CompactTextString(raw) 83 | 84 | t.Log(data) 85 | 86 | newType := reflect.New(tRaw.Elem()).Interface() 87 | 88 | assert.Equal(t, ppgo.UnmarshalText(data, newType), nil) 89 | 90 | assert.Equal(t, raw, newType) 91 | } 92 | 93 | func TestFull(t *testing.T) { 94 | 95 | input := makeMyType() 96 | 97 | verifyWire(t, &input) 98 | 99 | t.Logf("%v", ppgo.MarshalTextString(input)) 100 | } 101 | 102 | func TestIntSlice(t *testing.T) { 103 | 104 | var input MyType 105 | input.Int32Slice = []int32{-1, 1, 2} 106 | 107 | verifyWire(t, &input) 108 | } 109 | 110 | func TestSkipField(t *testing.T) { 111 | 112 | input := makeMyType() 113 | 114 | data, err := ppgo.Marshal(&input) 115 | assert.Equal(t, err, nil) 116 | 117 | jsondata, _ := json.Marshal(&input) 118 | 119 | var mini MyTypeMini 120 | assert.Equal(t, ppgo.Unmarshal(data, &mini), nil) 121 | 122 | var miniJson MyTypeMini 123 | json.Unmarshal(jsondata, &miniJson) 124 | assert.Equal(t, miniJson, mini) 125 | } 126 | 127 | func TestPtrField(t *testing.T) { 128 | 129 | input := MyType{} 130 | data, err := ppgo.Marshal(&input) 131 | t.Log(data, err) 132 | 133 | } 134 | 135 | //func TestText(t *testing.T) { 136 | // 137 | // input := makeMyType() 138 | // 139 | // verifyText(t, &input) 140 | //} 141 | 142 | func TestFloat(t *testing.T) { 143 | 144 | type MyFloat struct { 145 | Value float64 146 | } 147 | 148 | input := MyFloat{math.MaxFloat64} 149 | 150 | verifyText(t, &input) 151 | } 152 | 153 | func TestSlice(t *testing.T) { 154 | 155 | type DummyStruct struct { 156 | Num int32 157 | } 158 | 159 | type MyFloat struct { 160 | Value []int32 161 | Dummy DummyStruct 162 | } 163 | 164 | input := MyFloat{ 165 | []int32{-1, 1, 2}, 166 | DummyStruct{5}, 167 | } 168 | 169 | verifyText(t, &input) 170 | } 171 | 172 | func TestEnum(t *testing.T) { 173 | 174 | type MyFloat struct { 175 | Value []MyEnum 176 | } 177 | 178 | input := MyFloat{Value: []MyEnum{MyEnum_One}} 179 | 180 | verifyText(t, &input) 181 | } 182 | 183 | func TestCompatible(t *testing.T) { 184 | 185 | var s S2 186 | s.V = 1 187 | s.S = "a" 188 | 189 | data, err := proto.Marshal(&s) 190 | if err != nil { 191 | t.Error(err) 192 | t.FailNow() 193 | } 194 | 195 | var output S1 196 | err = proto.Unmarshal(data, &output) 197 | if err != nil { 198 | t.Error(err) 199 | t.FailNow() 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /tests/filelist.proto: -------------------------------------------------------------------------------- 1 | import "type.proto" 2 | import "msg.proto" -------------------------------------------------------------------------------- /tests/msg.proto: -------------------------------------------------------------------------------- 1 | 2 | [AutoMsgID MsgDir: "client -> game"] 3 | struct LoginREQ { 4 | 5 | } 6 | 7 | [AutoMsgID] 8 | struct LoginACK { 9 | 10 | } 11 | 12 | -------------------------------------------------------------------------------- /tests/pb_gen.proto: -------------------------------------------------------------------------------- 1 | // Generated by github.com/davyxu/protoplus 2 | // DO NOT EDIT! 3 | syntax = "proto3"; 4 | 5 | option go_package= "./;proto"; 6 | 7 | package proto; 8 | 9 | 10 | enum MyEnum { 11 | Zero = 0; 12 | One = 1; 13 | Two = 2; 14 | } 15 | 16 | 17 | 18 | message MyTypeMini { 19 | bool Bool = 1; 20 | int32 Int32 = 2; 21 | uint32 UInt32 = 3; 22 | int64 Int64 = 4; 23 | uint64 UInt64 = 5; 24 | float Float32 = 6; 25 | double Float64 = 7; 26 | string Str = 8; 27 | } 28 | 29 | 30 | message MySubType { 31 | bool Bool = 1; 32 | int32 Int32 = 2; 33 | uint32 UInt32 = 3; 34 | int64 Int64 = 4; 35 | uint64 UInt64 = 5; 36 | float Float32 = 6; 37 | double Float64 = 7; 38 | string Str = 8; 39 | bytes BytesSlice = 9; 40 | repeated bool BoolSlice = 10; 41 | repeated int32 Int32Slice = 11; 42 | repeated uint32 UInt32Slice = 12; 43 | repeated int64 Int64Slice = 13; 44 | repeated uint64 UInt64Slice = 14; 45 | repeated float Float32Slice = 15; 46 | repeated double Float64Slice = 16; 47 | repeated string StrSlice = 17; 48 | MyEnum Enum = 18; 49 | repeated MyEnum EnumSlice = 19; 50 | } 51 | 52 | 53 | message MyType { 54 | bool Bool = 1; 55 | int32 Int32 = 2; 56 | uint32 UInt32 = 3; 57 | int64 Int64 = 4; 58 | uint64 UInt64 = 5; 59 | float Float32 = 6; 60 | double Float64 = 7; 61 | string Str = 8; 62 | MySubType Struct = 9; 63 | bytes BytesSlice = 10; 64 | repeated bool BoolSlice = 11; 65 | repeated int32 Int32Slice = 12; 66 | repeated uint32 UInt32Slice = 13; 67 | repeated int64 Int64Slice = 14; 68 | repeated uint64 UInt64Slice = 15; 69 | repeated float Float32Slice = 16; 70 | repeated double Float64Slice = 17; 71 | repeated string StrSlice = 18; 72 | repeated MySubType StructSlice = 19; 73 | MyEnum Enum = 20; 74 | repeated MyEnum EnumSlice = 21; 75 | map Map = 22; 76 | } 77 | 78 | 79 | message LoginREQ { 80 | } 81 | 82 | 83 | message LoginACK { 84 | } 85 | 86 | -------------------------------------------------------------------------------- /tests/route.json: -------------------------------------------------------------------------------- 1 | { 2 | "Rule": [ 3 | { 4 | "MsgName": "proto.LoginREQ", 5 | "MsgID": 225, 6 | "SvcType": "game" 7 | } 8 | ] 9 | } -------------------------------------------------------------------------------- /tests/type.proto: -------------------------------------------------------------------------------- 1 | struct MyTypeMini 2 | { 3 | Bool bool 4 | Int32 int32 5 | UInt32 uint32 6 | 7 | Int64 int64 8 | UInt64 uint64 9 | 10 | Float32 float32 11 | Float64 float64 12 | Str string 13 | } 14 | 15 | enum MyEnum 16 | { 17 | Zero = 0 18 | One 19 | Two 20 | } 21 | 22 | struct MySubType 23 | { 24 | Bool bool 25 | Int32 int32 26 | UInt32 uint32 27 | 28 | Int64 int64 29 | UInt64 uint64 30 | 31 | Float32 float32 32 | Float64 float64 33 | Str string 34 | 35 | BytesSlice bytes 36 | 37 | BoolSlice []bool 38 | 39 | Int32Slice []int32 40 | 41 | UInt32Slice []uint32 42 | 43 | Int64Slice []int64 44 | 45 | UInt64Slice []uint64 46 | 47 | Float32Slice []float32 48 | 49 | Float64Slice []float64 50 | 51 | StrSlice []string 52 | 53 | Enum MyEnum 54 | 55 | EnumSlice []MyEnum 56 | } 57 | 58 | 59 | struct MyType 60 | { 61 | Bool bool 62 | Int32 int32 63 | UInt32 uint32 64 | 65 | Int64 int64 66 | UInt64 uint64 67 | 68 | Float32 float32 69 | Float64 float64 70 | Str string 71 | Struct MySubType 72 | 73 | BytesSlice bytes 74 | 75 | BoolSlice []bool 76 | 77 | Int32Slice []int32 78 | 79 | UInt32Slice []uint32 80 | 81 | Int64Slice []int64 82 | 83 | UInt64Slice []uint64 84 | 85 | Float32Slice []float32 86 | 87 | Float64Slice []float64 88 | 89 | StrSlice []string 90 | 91 | StructSlice []MySubType 92 | Enum MyEnum 93 | 94 | EnumSlice []MyEnum 95 | 96 | Map map[int32]string 97 | } 98 | -------------------------------------------------------------------------------- /util/flagwrapper.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "flag" 5 | "github.com/davyxu/protoplus/model" 6 | "github.com/davyxu/protoplus/parser" 7 | ) 8 | 9 | func ParseFileList(dset *model.DescriptorSet) (retErr error) { 10 | 11 | err := parser.ParseFileList(dset, flag.Args()...) 12 | if err != nil { 13 | return err 14 | } 15 | 16 | return 17 | 18 | } 19 | --------------------------------------------------------------------------------