diff --git a/.gitignore b/.gitignore index 9826e9b..bdf4a86 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,8 @@ example/csharp/.vs example/csharp/Example/bin example/csharp/Example/obj -example/csharp/ProtoPlus/obj -example/csharp/ProtoPlus/bin -api/csharp/ProtoPlus/bin api/csharp/ProtoPlus/obj +api/csharp/ProtoPlus/bin +bin +*.gz +tests/reg_gen.go diff --git a/Make.sh b/Make.sh new file mode 100644 index 0000000..8d84b8e --- /dev/null +++ b/Make.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +Version=2.0.0 + +export GOARCH=amd64 +BuildSourcePackage="github.com/davyxu/protoplus/build" +BinaryPackage="github.com/davyxu/protoplus/cmd/protoplus" +BinaryName="protoplus" + +BuildBinary() +{ + set -e + TargetDir=bin/"${1}" + mkdir -p "${TargetDir}" + export GOOS=${1} + BuildTime=$(date -R) + GitCommit=$(git rev-parse HEAD) + VersionString="-X \"${BuildSourcePackage}.BuildTime=${BuildTime}\" -X \"${BuildSourcePackage}.Version=${Version}\" -X \"${BuildSourcePackage}.GitCommit=${GitCommit}\"" + + go build -v -p 4 -o "${TargetDir}"/${BinaryName} -ldflags "${VersionString}" ${BinaryPackage} + PackageDir=$(pwd) + cd "${TargetDir}" + tar zcvf "${PackageDir}"/${BinaryName}-${Version}-"${1}"-x86_64.tar.gz ${BinaryName} + cd "${PackageDir}" +} + + + +if [[ ${1} == "" ]]; then + BuildBinary windows + BuildBinary linux + BuildBinary darwin +else + BuildBinary "${1}" +fi \ No newline at end of file diff --git a/README.md b/README.md index 762bbf5..ce22a8c 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,29 @@ # protoplus -通用的描述文件及代码生成器及工具集 +适用于游戏开发的协议格式、代码生成器及相关开发API +# Why ProtoPlus? +Protobuf作为行业通用的协议格式已经存在多年,各种历史遗留问题及语言设计上的缺陷对游戏开发阻碍非常大。 -# 特性 +为了提高协议编写效率,增加协议使用灵活度,急需一套强于Protobuf的工具集提高开发效率和使用便捷性,ProtoPlus应运而生! -* 提供比Protobuf描述文件更加友好的格式 +# 特性对比 -* 支持插件架构,可以使用任何语言开发自己的协议runtime和代码生成器 +___ | ProtoPlus | Protobuf +---|---|--- +生成字段Tag | 自动/手动 | 手动 +生成枚举值 | 自动/手动 | 手动 +注释扩展 | API简单 | API复杂 +字段扩展 | 专属API支持 | 手动解析注释 +结构扩展 | 专属API支持 | 手动解析注释 +消息ID生成 | 自动/手动 | 不支持 +路由表生成 | 支持 | 不支持 +扩展方式 | 描述文件输出JSON | 复杂的插件格式,调试复杂 -* 插件信息交换使用JSON格式(Protobuf使用pb二进制格式) +注: +* ProtoPlus中的枚举值,不再需要为了兼容C++而必须加上前缀,保证全局枚举值唯一 + +* ProtoPlus二进制编码格式与Protobuf一致,方便调试、分析、优化 # 描述文件格式 @@ -50,100 +64,211 @@ struct AddressBook { ``` -## 特性 -* 自动生成tag序列号(base0),也可以手动指定 -* 自动生成枚举序号(base0),也可以手动指定 +# 协议类型及输出语言类型对应 -* 类go结构体字段命名方式 +描述 |ProtoPlus | Go | C# | Protobuf +---|---|---|---|--- +32位整形| int32 | int32 | int | int32 +64位整形 | int64|int64 | long | int64 +无符号32位整形| uint32|uint32 | uint | uint32 +无符号64位整形| uint64|uint64 | ulong|uint64 +字符串| string|string|string | string +单精度浮点数| float32|float32 | float | float +双精度浮点数|float64|float64| double | double +二进制数据 | bytes | []byte | byte[] |repeated byte +枚举| enum | int32类型常量封装| enum | enum +布尔| bool | bool| bool | bool +结构体| struct | struct| class | message -* 比Protobuf更方便的导出注释内容做协议扩充 -# 支持类型 +# 编译 -* int32: 32位整形 -* int64: 64位整形 -* uint32: 无符号32位整形 -* uint64: 无符号64位整形 -* string: 字符串 -* float32: 单精度浮点数 -* float64: 双精度浮点数 -* bytes: 二进制数据 -* enum: int32封装 -* bool: 布尔 -* struct 结构体 +``` + go get -u -v github.com/davyxu/protoplus/cmd/protoplus +``` -所有类型前添加[]表示数组 +# 功能 -# 编译 +## 输出ProtoPlus编码消息序列化的Go源码 +命令行示例: +```bash +protoplus --ppgo_out=msg_gen.go --package=proto proto1.proto proto2.proto ``` - go get -u -v github.com/davyxu/protoplus + +参数说明: +* ppgo_out + + Go源码文件名 + +* package + + 指定输出时的Go包名 + +## 输出消息绑定的Go源码 + +输出源码被引用时, 自动注册到cellnet的消息Registry中 + +命令行示例: +```bash +protoplus --ppgoreg_out=msg_gen.go --package=proto proto1.proto proto2.proto ``` +参数说明: +* ppgoreg_out + + Go源码文件名 + +* package + + 指定输出时的Go包名 + +* codec + 生成消息注册的默认编码,如在消息中指定编码时,优先使用指定的编码 + + +## 输出ProtoPlus编码的消息序列化C#源码 -# 命令行参数 +输出的C#源码, 需要配合[ProtoPlus C# SDK](https://github.com/davyxu/protoplus/tree/master/api/csharp/ProtoPlus) 使用 -- go_out +命令行示例: +```bash +protoplus --ppcs_out=MsgGen.cs --package=Proto proto1.proto proto2.proto +``` - 生成protoplus协议的go源码文件 +参数说明: +* ppcs_out -- pb_out + C#源码文件名 + +* package - 生成protobuf 3.0协议文件 + 指定输出时的C#命名空间 + +* classbase -- cs_out + C#代码生成时,消息类默认基类名称, 默认基类为IProtoStruct - 生成protoplus协议的C#源码文件 -- json_out +## 输出消息绑定的C#源码 - 生成protoplus协议的json格式描述内容到文件 +输出的C#源码, 需要配合[ProtoPlus C# SDK](https://github.com/davyxu/protoplus/tree/master/api/csharp/ProtoPlus) 使用 -- json +命令行示例: +```bash +protoplus --ppcsreg_out=MsgGen.cs --package=Proto proto1.proto proto2.proto +``` - 生成protoplus协议的json格式描述内容到标准输出 +参数说明: +* ppcsreg_out -- package + C#源码文件名 - 指定生成源码的包,C#对应命名空间 +* package -- structbase + 指定输出时的C#命名空间 - C#代码生成时,消息类默认基类名称 -# 使用方法 +## 输出Protobuf协议描述文件 -* 生成go源码 +输出的Protobuf协议描述文件,可使用protoc编译器编译 +命令行示例: +```bash +protoplus --pbscheme_out=pb.proto --package=proto proto1.proto proto2.proto ``` - protoplus -package=YourPackageName -go_out=YourMsg_gen.go a.proto b.proto + +参数说明: +* pbscheme_out + + 生成protobuf 3.0协议文件 + +* package + + 指定输出时的Protobuf包名 + + +## 输出ProtoPlus描述文件 + +ProtoPlus协议描述文件可输出为JSON格式, 方便插件及工具链获取ProtoPlus的格式信息 + +命令行示例: +```bash +protoplus --ppscheme_out=pp.json proto1.proto proto2.proto ``` -* 生成类型信息 +参数说明: +* ppscheme_out + + JSON格式的ProtoPlus协议描述文件, 格式参见 [协议描述定义](https://github.com/davyxu/protoplus/tree/master/model/descriptorset.go) -默认生成的go,C#源码文件不带消息ID绑定,可以使用以下命令行输出类型后,再结合自己的生成器生成绑定代码 +也可将描述文件的JSON直接输出,示例如下: +```bash +protoplus --ppscheme proto1.proto proto2.proto ``` - protoplus -json_out=YourMsg_gen.go a.proto b.proto +## 输出路由配置 + +在结构体上添加MsgDir字段,标记结构体作为消息时的消息流转方向, 格式范例: +```protoplus +[MsgDir: "client -> game"] +struct LoginREQ { +} ``` +路由信息将输出为JSON格式: +```json +{ + "Rule": [ + { + "MsgName": "proto.LoginREQ", + "SvcName": "game" + } + ] +} +``` +### MsgDir格式说明 +MsgDir的格式包含3个部分 +``` + MsgDir: From -> Mid -> To +``` + +* From + + 消息的发起方,路由一般忽略此部分信息 + +* Mid -# 注意协议区别 + 消息的中间处理, 一般为网关或者路由等 + +* To -1. 文档中标注的"protoplus协议"和"Protobuf协议"为两种不同的协议 + 消息的目标送达点,消息处理最终方, 一般为某种消息服务, 路由表的SvcName字段读取该字段 + +命令行示例: +```bash +protoplus --route_out=route.json --package=proto proto1.proto proto2.proto +``` -2. protoplus协议在很大程度上接近Protobuf协议,但并不是100%兼容, 也没有考虑兼容pb协议 +参数说明: +* route_out -3. go_out,cs_out等语言直接输出支持的是protoplus协议, -如需要pb协议的C#或go语言, 请使用pb_out参数输出proto文件后, 用pb的工具链生成对应语言的源码 + JSON格式的ProtoPlus路由配置, 格式参见 [路由定义](https://github.com/davyxu/protoplus/tree/master/model/route.go) +* package + + 指定输出时消息的包名 + +也可将路由信息的JSON直接输出,示例如下: + +```bash +protoplus --route --package=proto proto1.proto proto2.proto +``` # 备注 感觉不错请star, 谢谢! -知乎: [http://www.zhihu.com/people/sunicdavy](http://www.zhihu.com/people/sunicdavy) - 提交bug及特性: https://github.com/davyxu/protoplus/issues diff --git a/example/csharp/ProtoPlus/FastBitConverter.cs b/api/csharp/ProtoPlus/FastBitConverter.cs similarity index 100% rename from example/csharp/ProtoPlus/FastBitConverter.cs rename to api/csharp/ProtoPlus/FastBitConverter.cs diff --git a/example/csharp/ProtoPlus/InputStream.cs b/api/csharp/ProtoPlus/InputStream.cs similarity index 94% rename from example/csharp/ProtoPlus/InputStream.cs rename to api/csharp/ProtoPlus/InputStream.cs index becbf0d..7631162 100644 --- a/example/csharp/ProtoPlus/InputStream.cs +++ b/api/csharp/ProtoPlus/InputStream.cs @@ -12,7 +12,7 @@ public class InputStream public int Position => _pos; - public int SpaceLeft => _len - _pos; + public int BufferLeft => _len - _pos; public static Func CreateStructFunc = new Func(CreateStruct); @@ -23,7 +23,7 @@ public static T CreateStruct() where T: IProtoStruct public static IProtoStruct CreateStruct(Type t) { - return MessageMeta.NewStruct(t ); + return MessageMeta.NewStruct(t); } @@ -136,7 +136,7 @@ public void ReadEnum(WireFormat.WireType wt, ref List value) where T : str value = new List(); } - while (stream.SpaceLeft > 0) + while (stream.BufferLeft > 0) { int element = 0; stream.ReadInt32(WireFormat.WireType.Varint, ref element); @@ -180,7 +180,7 @@ public void ReadInt32(WireFormat.WireType wt, ref List value) value = new List(); } - while(stream.SpaceLeft > 0 ) + while(stream.BufferLeft > 0 ) { int element = 0; stream.ReadInt32(WireFormat.WireType.Varint, ref element); @@ -220,7 +220,7 @@ public void ReadUInt32(WireFormat.WireType wt, ref List value) value = new List(); } - while (stream.SpaceLeft > 0) + while (stream.BufferLeft > 0) { uint element = 0; stream.ReadUInt32(WireFormat.WireType.Varint, ref element); @@ -264,7 +264,7 @@ public void ReadInt64(WireFormat.WireType wt, ref List value) value = new List(); } - while (stream.SpaceLeft > 0) + while (stream.BufferLeft > 0) { long element = 0; stream.ReadInt64(WireFormat.WireType.Varint, ref element); @@ -304,7 +304,7 @@ public void ReadUInt64(WireFormat.WireType wt, ref List value) value = new List(); } - while (stream.SpaceLeft > 0) + while (stream.BufferLeft > 0) { ulong element = 0; stream.ReadUInt64(WireFormat.WireType.Varint, ref element); @@ -345,7 +345,7 @@ public void ReadFloat(WireFormat.WireType wt, ref List value) value = new List(size/4); } - while (stream.SpaceLeft > 0) + while (stream.BufferLeft > 0) { float element = 0; stream.ReadFloat(WireFormat.WireType.Fixed32, ref element); @@ -386,7 +386,7 @@ public void ReadDouble(WireFormat.WireType wt, ref List value) value = new List(size / 8); } - while (stream.SpaceLeft > 0) + while (stream.BufferLeft > 0) { double element = 0; stream.ReadDouble(WireFormat.WireType.Fixed64, ref element); @@ -483,7 +483,7 @@ public void ReadStruct(WireFormat.WireType wt, ref T value) where T:IProtoStr public void Unmarshal(IProtoStruct s) { - while(SpaceLeft > 0 ) + while(BufferLeft > 0 ) { var tag = ReadVarint32(); @@ -578,7 +578,7 @@ uint SlowReadRawVarint32() return (uint)result; } - uint ReadFixed32() + public uint ReadFixed32() { CheckBuffer(4); @@ -589,8 +589,18 @@ uint ReadFixed32() return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24); } + + public ushort ReadFixed16() + { + CheckBuffer(2); + + uint b1 = _buffer[_pos++]; + uint b2 = _buffer[_pos++]; + + return (ushort)(b1 | (b2 << 8)); + } - ulong ReadFixed64() + public ulong ReadFixed64() { CheckBuffer(8); @@ -607,6 +617,20 @@ ulong ReadFixed64() | (b5 << 32) | (b6 << 40) | (b7 << 48) | (b8 << 56); } + public string ReadFixedString() + { + int len = (int)ReadFixed16(); + if (len > 0) + { + + var ret = Encoding.UTF8.GetString(_buffer, _pos, len); + _pos += len; + return ret; + } + + return string.Empty; + } + ulong ReadVarint64() { int shift = 0; @@ -624,6 +648,7 @@ ulong ReadVarint64() throw new Exception("MalformedVarint"); } + uint ReadVarint32() { diff --git a/example/csharp/ProtoPlus/MessageMeta.cs b/api/csharp/ProtoPlus/MessageMeta.cs similarity index 53% rename from example/csharp/ProtoPlus/MessageMeta.cs rename to api/csharp/ProtoPlus/MessageMeta.cs index 311631e..74a769d 100644 --- a/example/csharp/ProtoPlus/MessageMeta.cs +++ b/api/csharp/ProtoPlus/MessageMeta.cs @@ -12,19 +12,42 @@ public class MetaInfo // 在proto中添加[MsgDir: "client -> game" ], 左边为源, 右边为目标 public string SourcePeer; // 消息发起的源 public string TargetPeer; // 消息的目标 + + public string Name; } // 消息扩展信息集合 public partial class MessageMeta { - private Dictionary metaByID = new Dictionary(); - private Dictionary metaByType = new Dictionary(); + readonly Dictionary metaByID = new Dictionary(); + readonly Dictionary metaByType = new Dictionary(); + readonly Dictionary metaByName = new Dictionary(); + + static MessageMeta _ins; + + public static MessageMeta Instance + { + get + { + if (_ins == null) + { + _ins = new MessageMeta(); + } + + return _ins; + } + } // 注册消息的扩展信息 public void RegisterMeta(MetaInfo info) { - metaByID.Add(info.ID, info); + if (info.ID != 0) + { + metaByID.Add(info.ID, info); + } + metaByType.Add(info.Type, info); + metaByName.Add(info.Name, info); } // 通过ID取信息 @@ -37,6 +60,16 @@ public MetaInfo GetMetaByID(ushort msgid) return null; } + + public MetaInfo GetMetaByName(string msgName) + { + if (metaByName.TryGetValue(msgName, out var value)) + { + return value; + } + + return null; + } // 通过类型取信息 public MetaInfo GetMetaByType(Type t) @@ -58,9 +91,18 @@ public ushort GetMsgIDByType(Type t) return meta.ID; } + + public string GetMsgNameByType(Type t) + { + var meta = GetMetaByType(t); + if (meta == null) + return string.Empty; + + return meta.Type.FullName; + } // 通过消息ID创建消息 - public IProtoStruct CreateMessageByID(ushort msgid) + public IProtoStruct NewStruct(ushort msgid) { var meta = GetMetaByID(msgid); if (meta == null) @@ -68,6 +110,15 @@ public IProtoStruct CreateMessageByID(ushort msgid) return NewStruct(meta.Type); } + + public IProtoStruct NewStruct(string msgName) + { + var meta = GetMetaByName(msgName); + if (meta == null) + return null; + + return NewStruct(meta.Type); + } // 通过类型创建消息 public static IProtoStruct NewStruct(Type t) @@ -83,6 +134,11 @@ public static IProtoStruct NewStruct(Type t) return s; } + public static T NewStruct( ) where T: IProtoStruct + { + return (T)NewStruct(typeof(T)); + } + } } diff --git a/example/csharp/ProtoPlus/OutputStream.cs b/api/csharp/ProtoPlus/OutputStream.cs similarity index 92% rename from example/csharp/ProtoPlus/OutputStream.cs rename to api/csharp/ProtoPlus/OutputStream.cs index 63c3e98..2f219b7 100644 --- a/example/csharp/ProtoPlus/OutputStream.cs +++ b/api/csharp/ProtoPlus/OutputStream.cs @@ -13,8 +13,13 @@ public partial class OutputStream public int Position => _pos; - public int SpaceLeft => _len - _pos; + public int BufferLeft => _len - _pos; + public OutputStream() + { + + } + public OutputStream(byte[] buffer ) { Init(buffer, 0, buffer.Length, false); @@ -28,7 +33,10 @@ public void Init(byte[] buffer, int offset, int length, bool extend) _extend = extend; } - + public void SetPos(int pos) + { + _pos = pos; + } void CheckBuffer(int requireSize) { @@ -272,8 +280,8 @@ public void WriteUInt64(int fieldIndex, List value) } public void WriteFloat(int fieldIndex, float value) - { - if (value == 0F) + { + if( value == 0F) { return; } @@ -488,9 +496,14 @@ internal void WriteVarint64(ulong value) WriteByte((byte) value); } } + public void WriteFixed16(ushort value) + { + CheckBuffer(2); + _buffer[_pos++] = ((byte)value); + _buffer[_pos++] = ((byte)(value >> 8)); + } - - internal void WriteFixed32(uint value) + public void WriteFixed32(uint value) { CheckBuffer(4); _buffer[_pos++] = ((byte)value); @@ -499,7 +512,7 @@ internal void WriteFixed32(uint value) _buffer[_pos++] = ((byte)(value >> 24)); } - internal void WriteFixed64(ulong value) + public void WriteFixed64(ulong value) { CheckBuffer(8); _buffer[_pos++] = ((byte)value); @@ -511,6 +524,31 @@ internal void WriteFixed64(ulong value) _buffer[_pos++] = ((byte)(value >> 48)); _buffer[_pos++] = ((byte)(value >> 56)); } + + public void WriteFixedString(string value ) + { + int strLen = Encoding.UTF8.GetByteCount(value); + + WriteFixed16((ushort)strLen); + + CheckBuffer(strLen); + + // 全ASCII + if (strLen == value.Length) + { + for (int i = 0; i < strLen; i++) + { + _buffer[_pos + i] = (byte)value[i]; + } + } + else + { + Encoding.UTF8.GetBytes(value, 0, value.Length, _buffer, _pos); + + } + + _pos += strLen; + } internal void WriteRawBytes(byte[] value, int length ) { diff --git a/api/csharp/ProtoPlus/ProtoPlus.csproj b/api/csharp/ProtoPlus/ProtoPlus.csproj new file mode 100644 index 0000000..79699fd --- /dev/null +++ b/api/csharp/ProtoPlus/ProtoPlus.csproj @@ -0,0 +1,11 @@ + + + + netcoreapp2.0 + + + + TRACE;DEBUG;NETCOREAPP2_0 + + + diff --git a/example/csharp/ProtoPlus/ProtoStruct.cs b/api/csharp/ProtoPlus/ProtoStruct.cs similarity index 100% rename from example/csharp/ProtoPlus/ProtoStruct.cs rename to api/csharp/ProtoPlus/ProtoStruct.cs diff --git a/example/csharp/ProtoPlus/SizeCaculator.cs b/api/csharp/ProtoPlus/SizeCaculator.cs similarity index 100% rename from example/csharp/ProtoPlus/SizeCaculator.cs rename to api/csharp/ProtoPlus/SizeCaculator.cs diff --git a/example/csharp/ProtoPlus/WireType.cs b/api/csharp/ProtoPlus/WireType.cs similarity index 100% rename from example/csharp/ProtoPlus/WireType.cs rename to api/csharp/ProtoPlus/WireType.cs diff --git a/api/golang/api.go b/api/golang/api.go new file mode 100644 index 0000000..f5d5b80 --- /dev/null +++ b/api/golang/api.go @@ -0,0 +1,79 @@ +package ppgo + +import ( + "github.com/davyxu/protoplus/api/golang/wire" + "github.com/davyxu/ulexer" +) + +type Struct = wire.Struct + +func Marshal(msg Struct) ([]byte, error) { + + if msg == nil { + return nil, nil + } + + l := msg.Size() + + data := make([]byte, 0, l) + + buffer := wire.NewBuffer(data) + + err := msg.Marshal(buffer) + if err != nil { + return nil, err + } + + return buffer.Bytes(), nil + +} + +func Size(msg Struct) int { + + if msg == nil { + return 0 + } + + return msg.Size() +} + +func Unmarshal(data []byte, msg Struct) (err error) { + + buffer := wire.NewBuffer(data) + + return wire.UnmarshalStructObject(buffer, msg) +} + +var ( + defaultTextMarshaler = TextMarshaler{} + compactTextMarshaler = TextMarshaler{Compact: true, IgnoreDefault: true, CompactBytesSize: 50} +) + +func MarshalTextString(obj interface{}) string { + return defaultTextMarshaler.Text(obj) +} + +func CompactTextString(obj interface{}) string { return compactTextMarshaler.Text(obj) } + +func UnmarshalText(s string, obj interface{}) error { + + vObj := safeValueOf(obj) + tObj := safeTypeOf(obj) + + lex := ulexer.NewLexer(s) + + // 读之前, 清掉空白 + lex.SetPreHook(func(lex *ulexer.Lexer) *ulexer.Token { + + lex.Read(ulexer.WhiteSpace()) + return nil + }) + + err := ulexer.Try(lex, func(lex *ulexer.Lexer) { + + parseStruct(lex, tObj, vObj, "") + + }) + + return err +} diff --git a/proto/text_marshaler.go b/api/golang/text_marshaler.go similarity index 95% rename from proto/text_marshaler.go rename to api/golang/text_marshaler.go index 89bfd95..f3e92dd 100644 --- a/proto/text_marshaler.go +++ b/api/golang/text_marshaler.go @@ -1,4 +1,4 @@ -package proto +package ppgo import ( "bufio" @@ -159,6 +159,18 @@ func (self *TextMarshaler) writeAny(w *textWriter, v reflect.Value) error { if err := w.WriteByte(ket); err != nil { return err } + case reflect.Int32: + // 枚举切片的值应该是输出整形 + if _, ok := v.Interface().(fmt.Stringer); ok { + + _, err := fmt.Fprint(w, v.Int()) + return err + + } else { + _, err := fmt.Fprint(w, v.Interface()) + return err + } + default: _, err := fmt.Fprint(w, v.Interface()) return err @@ -359,14 +371,3 @@ func (self *TextMarshaler) Text(obj interface{}) string { self.Marshal(&buf, obj) return buf.String() } - -var ( - defaultTextMarshaler = TextMarshaler{} - compactTextMarshaler = TextMarshaler{Compact: true, IgnoreDefault: true, CompactBytesSize: 50} -) - -func MarshalTextString(obj interface{}) string { - return defaultTextMarshaler.Text(obj) -} - -func CompactTextString(obj interface{}) string { return compactTextMarshaler.Text(obj) } diff --git a/proto/text_marshaler_test.go b/api/golang/text_marshaler_test.go similarity index 99% rename from proto/text_marshaler_test.go rename to api/golang/text_marshaler_test.go index dd32a67..6d9be76 100644 --- a/proto/text_marshaler_test.go +++ b/api/golang/text_marshaler_test.go @@ -1,4 +1,4 @@ -package proto +package ppgo import ( "math" diff --git a/api/golang/text_parser.go b/api/golang/text_parser.go new file mode 100644 index 0000000..b932ba8 --- /dev/null +++ b/api/golang/text_parser.go @@ -0,0 +1,266 @@ +package ppgo + +import ( + "github.com/davyxu/ulexer" + "reflect" + "strings" +) + +type MatchAction func(tk *ulexer.Token) + +func selectAction(self *ulexer.Lexer, mlist []ulexer.Matcher, alist []MatchAction) { + + if len(mlist) != len(alist) { + panic("Matcher list should equal to Action list length") + } + + var hit bool + for index, m := range mlist { + tk := self.Read(m) + + if tk != nil { + + action := alist[index] + if action != nil { + action(tk) + } + hit = true + break + } + } + + if !hit { + + var sb strings.Builder + + for index, m := range mlist { + if index > 0 { + sb.WriteString(" ") + } + sb.WriteString(m.TokenType()) + } + + self.Error("Expect %s", sb.String()) + } + +} + +func detectEnd(lex *ulexer.Lexer, literal string) bool { + if literal != "" { + if tk := lex.Read(ulexer.Contain(literal)); tk.String() == literal { + return true + } + } + + return false +} + +func parseStruct(lex *ulexer.Lexer, tObj reflect.Type, vObj reflect.Value, endLiteral string) { + for { + + if detectEnd(lex, endLiteral) { + break + } + + fieldTk := ulexer.Expect(lex, ulexer.Identifier()) + + tField, fieldExists := tObj.FieldByName(fieldTk.String()) + vField := vObj.FieldByName(fieldTk.String()) + + ulexer.Expect(lex, ulexer.Contain(":")) + + parseMultiValue(lex, []ulexer.Matcher{ulexer.String(), + ulexer.Numeral(), + ulexer.Bool(), + ulexer.Contain("["), + ulexer.Contain("{"), + ulexer.Identifier(), + }, func(tk *ulexer.Token) { + if !fieldExists { + return + } + + switch tField.Type.Kind() { + case reflect.Bool: + vField.SetBool(tk.Bool()) + case reflect.String: + vField.SetString(tk.String()) + case reflect.Int32: + vField.SetInt(int64(tk.Int32())) + case reflect.Int64: + vField.SetInt(int64(tk.Int64())) + case reflect.Uint32: + vField.SetUint(uint64(tk.UInt32())) + case reflect.Uint64: + vField.SetUint(uint64(tk.UInt64())) + case reflect.Float32: + vField.SetFloat(float64(tk.Float32())) + case reflect.Float64: + vField.SetFloat(tk.Float64()) + case reflect.Slice: + parseArray(lex, tField.Type, vField, "]") + case reflect.Struct: + parseStruct(lex, tField.Type, vField, "}") + default: + panic("unsupport field kind " + tField.Type.Kind().String()) + } + }) + } +} + +func parseMultiValue(lex *ulexer.Lexer, mlist []ulexer.Matcher, action MatchAction) { + + alist := make([]MatchAction, 0, len(mlist)) + for i := 0; i < len(mlist); i++ { + alist = append(alist, action) + } + + selectAction(lex, + mlist, + alist, + ) +} + +func parseElement(lex *ulexer.Lexer, endLiteral string, m ulexer.Matcher, onValue MatchAction, onEnd func()) { + for { + + if detectEnd(lex, endLiteral) { + onEnd() + break + } + + tk := ulexer.Expect(lex, m) + onValue(tk) + } + +} + +func parseArray(lex *ulexer.Lexer, tField reflect.Type, vObj reflect.Value, endLiteral string) { + + switch tField.Elem().Kind() { + case reflect.Int32: + + // 枚举 + if vObj.Kind() != reflect.Int32 { + + list := reflect.MakeSlice(vObj.Type(), 0, 0) + + parseElement(lex, endLiteral, ulexer.Integer(), func(tk *ulexer.Token) { + + vElm := reflect.ValueOf(tk.Int32()) + + list = reflect.Append(list, vElm.Convert(vObj.Type().Elem())) + }, func() { + + vObj.Set(list) + }) + + } else { + var value []int32 + parseElement(lex, endLiteral, ulexer.Integer(), func(tk *ulexer.Token) { + value = append(value, tk.Int32()) + }, func() { + + vObj.Set(reflect.ValueOf(value)) + }) + } + + case reflect.Int64: + var value []int64 + parseElement(lex, endLiteral, ulexer.Integer(), func(tk *ulexer.Token) { + value = append(value, tk.Int64()) + }, func() { + vObj.Set(reflect.ValueOf(value)) + }) + case reflect.Uint64: + var value []uint64 + parseElement(lex, endLiteral, ulexer.UInteger(), func(tk *ulexer.Token) { + value = append(value, tk.UInt64()) + }, func() { + vObj.Set(reflect.ValueOf(value)) + }) + case reflect.Float32: + var value []float32 + parseElement(lex, endLiteral, ulexer.Numeral(), func(tk *ulexer.Token) { + value = append(value, tk.Float32()) + }, func() { + vObj.Set(reflect.ValueOf(value)) + }) + case reflect.Float64: + var value []float64 + parseElement(lex, endLiteral, ulexer.Numeral(), func(tk *ulexer.Token) { + value = append(value, tk.Float64()) + }, func() { + vObj.Set(reflect.ValueOf(value)) + }) + case reflect.Uint32: + var value []uint32 + parseElement(lex, endLiteral, ulexer.UInteger(), func(tk *ulexer.Token) { + value = append(value, tk.UInt32()) + }, func() { + vObj.Set(reflect.ValueOf(value)) + }) + case reflect.Bool: + var value []bool + parseElement(lex, endLiteral, ulexer.Bool(), func(tk *ulexer.Token) { + value = append(value, tk.Bool()) + }, func() { + vObj.Set(reflect.ValueOf(value)) + }) + case reflect.String: + var value []string + parseElement(lex, endLiteral, ulexer.String(), func(tk *ulexer.Token) { + value = append(value, tk.String()) + }, func() { + vObj.Set(reflect.ValueOf(value)) + }) + case reflect.Uint8: + var value []byte + parseElement(lex, endLiteral, ulexer.Numeral(), func(tk *ulexer.Token) { + value = append(value, tk.UInt8()) + }, func() { + vObj.SetBytes(value) + }) + case reflect.Struct: + + list := reflect.MakeSlice(tField, 0, 0) + for { + + if detectEnd(lex, endLiteral) { + break + } + + ulexer.Expect(lex, ulexer.Contain("{")) + + element := reflect.New(tField.Elem()).Elem() + + parseStruct(lex, tField.Elem(), element, "}") + + list = reflect.Append(list, element) + + vObj.Set(list) + } + + default: + panic("unsupport array element " + tField.Kind().String()) + } + +} + +func safeValueOf(obj interface{}) reflect.Value { + vObj := reflect.ValueOf(obj) + if vObj.Kind() == reflect.Ptr { + return vObj.Elem() + } + + return vObj +} + +func safeTypeOf(obj interface{}) reflect.Type { + tObj := reflect.TypeOf(obj) + if tObj.Kind() == reflect.Ptr { + return tObj.Elem() + } + + return tObj +} diff --git a/proto/text_writer.go b/api/golang/text_writer.go similarity index 99% rename from proto/text_writer.go rename to api/golang/text_writer.go index c8e859a..eeabffb 100644 --- a/proto/text_writer.go +++ b/api/golang/text_writer.go @@ -1,4 +1,4 @@ -package proto +package ppgo import ( "bytes" diff --git a/proto/buffer.go b/api/golang/wire/buffer.go similarity index 98% rename from proto/buffer.go rename to api/golang/wire/buffer.go index 4a85a5a..9a55fc3 100644 --- a/proto/buffer.go +++ b/api/golang/wire/buffer.go @@ -1,4 +1,4 @@ -package proto +package wire import ( "errors" @@ -22,6 +22,11 @@ func NewBuffer(e []byte) *Buffer { return &Buffer{buf: e} } +func NewBufferBySize(size int) *Buffer { + data := make([]byte, 0, size) + return NewBuffer(data) +} + // Reset resets the Buffer, ready for marshaling a new protocol buffer. func (self *Buffer) Reset() { self.buf = self.buf[0:0] // for reading/writing diff --git a/proto/err.go b/api/golang/wire/err.go similarity index 92% rename from proto/err.go rename to api/golang/wire/err.go index c212696..7deaf46 100644 --- a/proto/err.go +++ b/api/golang/wire/err.go @@ -1,4 +1,4 @@ -package proto +package wire import "errors" diff --git a/proto/field_marshal.go b/api/golang/wire/field_marshal.go similarity index 60% rename from proto/field_marshal.go rename to api/golang/wire/field_marshal.go index 99d56f7..0e8c6c7 100644 --- a/proto/field_marshal.go +++ b/api/golang/wire/field_marshal.go @@ -1,8 +1,7 @@ -package proto +package wire import ( "math" - "reflect" ) func MarshalBool(b *Buffer, fieldIndex uint64, value bool) error { @@ -11,7 +10,7 @@ func MarshalBool(b *Buffer, fieldIndex uint64, value bool) error { return nil } - b.EncodeVarint(makeWireTag(fieldIndex, WireVarint)) + b.EncodeVarint(MakeTag(fieldIndex, WireVarint)) if value { b.buf = append(b.buf, 1) @@ -26,10 +25,10 @@ func MarshalInt32(b *Buffer, fieldIndex uint64, value int32) error { switch { case value > 0: - b.EncodeVarint(makeWireTag(fieldIndex, WireVarint)) + b.EncodeVarint(MakeTag(fieldIndex, WireVarint)) b.EncodeVarint(uint64(value)) case value < 0: - b.EncodeVarint(makeWireTag(fieldIndex, WireFixed32)) + b.EncodeVarint(MakeTag(fieldIndex, WireFixed32)) b.EncodeFixed32(uint64(value)) } @@ -42,7 +41,7 @@ func MarshalUInt32(b *Buffer, fieldIndex uint64, value uint32) error { return nil } - b.EncodeVarint(makeWireTag(fieldIndex, WireVarint)) + b.EncodeVarint(MakeTag(fieldIndex, WireVarint)) b.EncodeVarint(uint64(value)) return nil @@ -52,10 +51,10 @@ func MarshalInt64(b *Buffer, fieldIndex uint64, value int64) error { switch { case value > 0: - b.EncodeVarint(makeWireTag(fieldIndex, WireVarint)) + b.EncodeVarint(MakeTag(fieldIndex, WireVarint)) b.EncodeVarint(uint64(value)) case value < 0: - b.EncodeVarint(makeWireTag(fieldIndex, WireFixed64)) + b.EncodeVarint(MakeTag(fieldIndex, WireFixed64)) b.EncodeFixed64(uint64(value)) } @@ -68,7 +67,7 @@ func MarshalUInt64(b *Buffer, fieldIndex uint64, value uint64) error { return nil } - b.EncodeVarint(makeWireTag(fieldIndex, WireVarint)) + b.EncodeVarint(MakeTag(fieldIndex, WireVarint)) b.EncodeVarint(value) return nil @@ -80,7 +79,7 @@ func MarshalFloat32(b *Buffer, fieldIndex uint64, value float32) error { return nil } - b.EncodeVarint(makeWireTag(fieldIndex, WireFixed32)) + b.EncodeVarint(MakeTag(fieldIndex, WireFixed32)) b.EncodeFixed32(uint64(math.Float32bits(value))) return nil @@ -92,7 +91,7 @@ func MarshalFloat64(b *Buffer, fieldIndex uint64, value float64) error { return nil } - b.EncodeVarint(makeWireTag(fieldIndex, WireFixed64)) + b.EncodeVarint(MakeTag(fieldIndex, WireFixed64)) b.EncodeFixed64(uint64(math.Float64bits(value))) return nil @@ -103,30 +102,9 @@ func MarshalString(b *Buffer, fieldIndex uint64, value string) error { if value == "" { return nil } - b.EncodeVarint(makeWireTag(fieldIndex, WireBytes)) + b.EncodeVarint(MakeTag(fieldIndex, WireBytes)) b.EncodeStringBytes(value) return nil } - -func MarshalStruct(b *Buffer, fieldIndex uint64, msg Struct) error { - - structValue := reflect.ValueOf(msg) - - // *MyType被Message包裹后,判断不为nil - if structValue.IsNil() { - return nil - } - - size := msg.Size() - if size == 0 { - return nil - } - - b.EncodeVarint(makeWireTag(fieldIndex, WireBytes)) - - b.EncodeVarint(uint64(size)) - - return msg.Marshal(b) -} diff --git a/api/golang/wire/field_size.go b/api/golang/wire/field_size.go new file mode 100644 index 0000000..3f7d0f9 --- /dev/null +++ b/api/golang/wire/field_size.go @@ -0,0 +1,81 @@ +package wire + +func SizeBool(fieldIndex uint64, value bool) int { + + if value == false { + return 0 + } + + return SizeVarint(MakeTag(fieldIndex, WireVarint)) + 1 +} + +func SizeInt32(fieldIndex uint64, value int32) int { + + switch { + case value > 0: + return SizeVarint(MakeTag(fieldIndex, WireVarint)) + SizeVarint(uint64(value)) + case value < 0: + return SizeVarint(MakeTag(fieldIndex, WireFixed32)) + 4 + default: + return 0 + } +} + +func SizeUInt32(fieldIndex uint64, value uint32) int { + + if value == 0 { + return 0 + } + + return SizeVarint(MakeTag(fieldIndex, WireVarint)) + SizeVarint(uint64(value)) +} + +func SizeInt64(fieldIndex uint64, value int64) int { + + switch { + case value > 0: + return SizeVarint(MakeTag(fieldIndex, WireVarint)) + SizeVarint(uint64(value)) + case value < 0: + return SizeVarint(MakeTag(fieldIndex, WireFixed64)) + 8 + default: + return 0 + } +} + +func SizeUInt64(fieldIndex uint64, value uint64) int { + + if value == 0 { + return 0 + } + + return SizeVarint(MakeTag(fieldIndex, WireVarint)) + SizeVarint(uint64(value)) +} + +func SizeFloat32(fieldIndex uint64, value float32) int { + + if value == 0 { + return 0 + } + + return SizeVarint(MakeTag(fieldIndex, WireFixed32)) + 4 +} + +func SizeFloat64(fieldIndex uint64, value float64) int { + + if value == 0 { + return 0 + } + + return SizeVarint(MakeTag(fieldIndex, WireFixed64)) + 8 +} + +func SizeString(fieldIndex uint64, value string) int { + + size := len(value) + + if size == 0 { + return 0 + } + + return SizeVarint(MakeTag(fieldIndex, WireVarint)) + SizeVarint(uint64(size)) + size +} diff --git a/api/golang/wire/field_unmarshal.go b/api/golang/wire/field_unmarshal.go new file mode 100644 index 0000000..28834b0 --- /dev/null +++ b/api/golang/wire/field_unmarshal.go @@ -0,0 +1,170 @@ +package wire + +import ( + "io" + "math" +) + +func UnmarshalBool(b *Buffer, wt WireType) (bool, error) { + switch wt { + case WireVarint: + v, err := b.DecodeVarint() + if err != nil { + return false, err + } + return v != 0, nil + default: + return false, ErrBadWireType + } +} + +func UnmarshalInt32(b *Buffer, wt WireType) (int32, error) { + + switch wt { + case WireVarint: + v, err := b.DecodeVarint() + if err != nil { + return 0, err + } + return int32(v), nil + + case WireFixed32: + v, err := b.DecodeFixed32() + if err != nil { + return 0, err + } + + return int32(v), nil + + default: + return 0, ErrBadWireType + } +} + +func UnmarshalUInt32(b *Buffer, wt WireType) (uint32, error) { + + switch wt { + case WireVarint: + v, err := b.DecodeVarint() + if err != nil { + return 0, err + } + + return uint32(v), nil + default: + return 0, ErrBadWireType + } +} + +func UnmarshalInt64(b *Buffer, wt WireType) (int64, error) { + + switch wt { + case WireVarint: + v, err := b.DecodeVarint() + if err != nil { + return 0, err + } + return int64(v), nil + + case WireFixed64: + v, err := b.DecodeFixed64() + if err != nil { + return 0, err + } + + return int64(v), nil + default: + return 0, ErrBadWireType + } +} + +func UnmarshalUInt64(b *Buffer, wt WireType) (uint64, error) { + + switch wt { + case WireVarint: + v, err := b.DecodeVarint() + if err != nil { + return 0, err + } + return v, nil + default: + return 0, ErrBadWireType + } +} + +func UnmarshalFloat32(b *Buffer, wt WireType) (float32, error) { + + switch wt { + case WireFixed32: + v, err := b.DecodeFixed32() + if err != nil { + return 0, err + } + + return math.Float32frombits(uint32(v)), nil + default: + return 0, ErrBadWireType + } + +} + +func UnmarshalFloat64(b *Buffer, wt WireType) (float64, error) { + + switch wt { + case WireFixed64: + v, err := b.DecodeFixed64() + if err != nil { + return 0, err + } + + return math.Float64frombits(uint64(v)), nil + default: + return 0, ErrBadWireType + } +} + +func UnmarshalString(b *Buffer, wt WireType) (string, error) { + switch wt { + case WireBytes: + v, err := b.DecodeStringBytes() + if err != nil { + return "", err + } + + return v, nil + default: + return "", ErrBadWireType + } +} + +func skipField(b *Buffer, wt WireType) error { + + switch wt { + case WireVarint: + _, err := b.DecodeVarint() + return err + case WireBytes: + size, err := b.DecodeVarint() + + if b.BytesRemains() < int(size) { + return io.ErrUnexpectedEOF + } + + b.ConsumeBytes(int(size)) + return err + case WireZigzag32: + _, err := b.DecodeZigzag32() + return err + case WireZigzag64: + _, err := b.DecodeZigzag64() + return err + case WireFixed32: + _, err := b.DecodeFixed32() + return err + case WireFixed64: + _, err := b.DecodeFixed64() + return err + default: + return ErrBadWireType + } +} diff --git a/proto/slice_marshal.go b/api/golang/wire/slice_marshal.go similarity index 85% rename from proto/slice_marshal.go rename to api/golang/wire/slice_marshal.go index 3af4e3b..002be14 100644 --- a/proto/slice_marshal.go +++ b/api/golang/wire/slice_marshal.go @@ -1,4 +1,4 @@ -package proto +package wire import ( "math" @@ -11,7 +11,7 @@ func MarshalBytes(b *Buffer, fieldIndex uint64, value []byte) error { return nil } - b.EncodeVarint(makeWireTag(fieldIndex, WireBytes)) + b.EncodeVarint(MakeTag(fieldIndex, WireBytes)) // 因为bool每一个value都是1个字节,size=1*count b.EncodeVarint(uint64(size)) @@ -27,7 +27,7 @@ func MarshalBoolSlice(b *Buffer, fieldIndex uint64, value []bool) error { return nil } - b.EncodeVarint(makeWireTag(fieldIndex, WireBytes)) + b.EncodeVarint(MakeTag(fieldIndex, WireBytes)) // 因为bool每一个value都是1个字节,size=1*count b.EncodeVarint(uint64(size)) @@ -50,7 +50,7 @@ func MarshalInt32Slice(b *Buffer, fieldIndex uint64, value []int32) error { return nil } - b.EncodeVarint(makeWireTag(fieldIndex, WireBytes)) + b.EncodeVarint(MakeTag(fieldIndex, WireBytes)) // 计算变长单元大小 var size int @@ -73,7 +73,7 @@ func MarshalUInt32Slice(b *Buffer, fieldIndex uint64, value []uint32) error { return nil } - b.EncodeVarint(makeWireTag(fieldIndex, WireBytes)) + b.EncodeVarint(MakeTag(fieldIndex, WireBytes)) // 计算变长单元大小 var size int @@ -96,7 +96,7 @@ func MarshalInt64Slice(b *Buffer, fieldIndex uint64, value []int64) error { return nil } - b.EncodeVarint(makeWireTag(fieldIndex, WireBytes)) + b.EncodeVarint(MakeTag(fieldIndex, WireBytes)) // 计算变长单元大小 var size int @@ -119,7 +119,7 @@ func MarshalUInt64Slice(b *Buffer, fieldIndex uint64, value []uint64) error { return nil } - b.EncodeVarint(makeWireTag(fieldIndex, WireBytes)) + b.EncodeVarint(MakeTag(fieldIndex, WireBytes)) // 计算变长单元大小 var size int @@ -143,7 +143,7 @@ func MarshalStringSlice(b *Buffer, fieldIndex uint64, value []string) error { } for _, v := range value { - b.EncodeVarint(makeWireTag(fieldIndex, WireBytes)) + b.EncodeVarint(MakeTag(fieldIndex, WireBytes)) b.EncodeStringBytes(v) } @@ -157,7 +157,7 @@ func MarshalFloat32Slice(b *Buffer, fieldIndex uint64, value []float32) error { return nil } - b.EncodeVarint(makeWireTag(fieldIndex, WireBytes)) + b.EncodeVarint(MakeTag(fieldIndex, WireBytes)) // 写入长度 b.EncodeVarint(uint64(count * 4)) @@ -176,7 +176,7 @@ func MarshalFloat64Slice(b *Buffer, fieldIndex uint64, value []float64) error { return nil } - b.EncodeVarint(makeWireTag(fieldIndex, WireBytes)) + b.EncodeVarint(MakeTag(fieldIndex, WireBytes)) // 写入长度 b.EncodeVarint(uint64(count * 8)) diff --git a/proto/slice_size.go b/api/golang/wire/slice_size.go similarity index 79% rename from proto/slice_size.go rename to api/golang/wire/slice_size.go index 2eee558..d994097 100644 --- a/proto/slice_size.go +++ b/api/golang/wire/slice_size.go @@ -1,4 +1,4 @@ -package proto +package wire func SizeBytes(fieldIndex uint64, value []byte) int { @@ -9,7 +9,7 @@ func SizeBytes(fieldIndex uint64, value []byte) int { size := count * 1 - return SizeVarint(makeWireTag(fieldIndex, WireBytes)) + SizeVarint(uint64(size)) + size + return SizeVarint(MakeTag(fieldIndex, WireBytes)) + SizeVarint(uint64(size)) + size } func SizeBoolSlice(fieldIndex uint64, value []bool) int { @@ -21,7 +21,7 @@ func SizeBoolSlice(fieldIndex uint64, value []bool) int { size := count * 1 - return SizeVarint(makeWireTag(fieldIndex, WireBytes)) + SizeVarint(uint64(size)) + size + return SizeVarint(MakeTag(fieldIndex, WireBytes)) + SizeVarint(uint64(size)) + size } func SizeInt32Slice(fieldIndex uint64, value []int32) (ret int) { @@ -31,7 +31,7 @@ func SizeInt32Slice(fieldIndex uint64, value []int32) (ret int) { return 0 } - ret = SizeVarint(makeWireTag(fieldIndex, WireBytes)) + ret = SizeVarint(MakeTag(fieldIndex, WireBytes)) // 后部分的长度 size := 0 @@ -53,7 +53,7 @@ func SizeUInt32Slice(fieldIndex uint64, value []uint32) (ret int) { return 0 } - ret = SizeVarint(makeWireTag(fieldIndex, WireBytes)) + ret = SizeVarint(MakeTag(fieldIndex, WireBytes)) // 后部分的长度 size := 0 @@ -75,7 +75,7 @@ func SizeInt64Slice(fieldIndex uint64, value []int64) (ret int) { return 0 } - ret = SizeVarint(makeWireTag(fieldIndex, WireBytes)) + ret = SizeVarint(MakeTag(fieldIndex, WireBytes)) // 后部分的长度 size := 0 @@ -97,7 +97,7 @@ func SizeUInt64Slice(fieldIndex uint64, value []uint64) (ret int) { return 0 } - ret = SizeVarint(makeWireTag(fieldIndex, WireBytes)) + ret = SizeVarint(MakeTag(fieldIndex, WireBytes)) // 后部分的长度 size := 0 @@ -132,7 +132,7 @@ func SizeFloat32Slice(fieldIndex uint64, value []float32) (ret int) { return 0 } - ret = SizeVarint(makeWireTag(fieldIndex, WireBytes)) + ret = SizeVarint(MakeTag(fieldIndex, WireBytes)) size := count * 4 @@ -150,7 +150,7 @@ func SizeFloat64Slice(fieldIndex uint64, value []float64) (ret int) { return 0 } - ret = SizeVarint(makeWireTag(fieldIndex, WireBytes)) + ret = SizeVarint(MakeTag(fieldIndex, WireBytes)) size := count * 8 diff --git a/api/golang/wire/slice_unmarshal.go b/api/golang/wire/slice_unmarshal.go new file mode 100644 index 0000000..7482c44 --- /dev/null +++ b/api/golang/wire/slice_unmarshal.go @@ -0,0 +1,268 @@ +package wire + +import ( + "io" +) + +func UnmarshalBytes(b *Buffer, wt WireType) ([]byte, error) { + + switch wt { + case WireBytes: + size, err := b.DecodeVarint() + if err != nil { + return nil, err + } + + if b.BytesRemains() < int(size) { + return nil, io.ErrUnexpectedEOF + } + + return b.ConsumeBytes(int(size)), nil + + default: + return nil, ErrBadWireType + } +} + +func UnmarshalBoolSlice(b *Buffer, wt WireType) ([]bool, error) { + switch wt { + case WireBytes: + count, err := b.DecodeVarint() + if err != nil { + return nil, err + } + + if b.BytesRemains() < int(int(count)) { + return nil, io.ErrUnexpectedEOF + } + + var ret []bool + for _, element := range b.ConsumeBytes(int(count)) { + + switch element { + case 0: + ret = append(ret, false) + case 1: + ret = append(ret, true) + default: + return nil, ErrBadBoolValue + } + } + + return ret, nil + + default: + return nil, ErrBadWireType + } +} + +func UnmarshalInt32Slice(b *Buffer, wt WireType) ([]int32, error) { + + switch wt { + case WireBytes: + size, err := b.DecodeVarint() + if err != nil { + return nil, err + } + + if b.BytesRemains() < int(size) { + return nil, io.ErrUnexpectedEOF + } + + limitBuffer := NewBuffer(b.ConsumeBytes(int(size))) + + var ret []int32 + for limitBuffer.BytesRemains() > 0 { + var element int32 + element, err = UnmarshalInt32(limitBuffer, WireVarint) + if err != nil { + return nil, err + } + + ret = append(ret, element) + } + + return ret, nil + + default: + return nil, ErrBadWireType + } +} + +func UnmarshalUInt32Slice(b *Buffer, wt WireType) ([]uint32, error) { + + switch wt { + case WireBytes: + size, err := b.DecodeVarint() + if err != nil { + return nil, err + } + + if b.BytesRemains() < int(size) { + return nil, io.ErrUnexpectedEOF + } + + limitBuffer := NewBuffer(b.ConsumeBytes(int(size))) + + var ret []uint32 + for limitBuffer.BytesRemains() > 0 { + var element uint32 + element, err = UnmarshalUInt32(limitBuffer, WireVarint) + if err != nil { + return nil, err + } + + ret = append(ret, element) + } + + return ret, nil + + default: + return nil, ErrBadWireType + } +} + +func UnmarshalInt64Slice(b *Buffer, wt WireType) ([]int64, error) { + + switch wt { + case WireBytes: + size, err := b.DecodeVarint() + if err != nil { + return nil, err + } + + if b.BytesRemains() < int(size) { + return nil, io.ErrUnexpectedEOF + } + + limitBuffer := NewBuffer(b.ConsumeBytes(int(size))) + + var ret []int64 + for limitBuffer.BytesRemains() > 0 { + var element int64 + element, err = UnmarshalInt64(limitBuffer, WireVarint) + if err != nil { + return nil, err + } + + ret = append(ret, element) + } + return ret, nil + + default: + return nil, ErrBadWireType + } +} + +func UnmarshalUInt64Slice(b *Buffer, wt WireType) ([]uint64, error) { + + switch wt { + case WireBytes: + size, err := b.DecodeVarint() + if err != nil { + return nil, err + } + + if b.BytesRemains() < int(size) { + return nil, io.ErrUnexpectedEOF + } + + limitBuffer := NewBuffer(b.ConsumeBytes(int(size))) + + var ret []uint64 + for limitBuffer.BytesRemains() > 0 { + var element uint64 + element, err = UnmarshalUInt64(limitBuffer, WireVarint) + if err != nil { + return nil, err + } + + ret = append(ret, element) + } + + return ret, nil + + default: + return nil, ErrBadWireType + } +} + +func UnmarshalStringSlice(b *Buffer, wt WireType) ([]string, error) { + switch wt { + case WireBytes: + v, err := b.DecodeStringBytes() + if err != nil { + return nil, err + } + + return []string{v}, nil + default: + return nil, ErrBadWireType + } +} + +func UnmarshalFloat32Slice(b *Buffer, wt WireType) ([]float32, error) { + + switch wt { + case WireBytes: + size, err := b.DecodeVarint() + if err != nil { + return nil, err + } + + if b.BytesRemains() < int(size) { + return nil, io.ErrUnexpectedEOF + } + + limitBuffer := NewBuffer(b.ConsumeBytes(int(size))) + + var ret []float32 + for limitBuffer.BytesRemains() > 0 { + var element float32 + element, err = UnmarshalFloat32(limitBuffer, WireFixed32) + if err != nil { + return nil, err + } + + ret = append(ret, element) + } + + return ret, nil + + default: + return nil, ErrBadWireType + } +} + +func UnmarshalFloat64Slice(b *Buffer, wt WireType) ([]float64, error) { + + switch wt { + case WireBytes: + size, err := b.DecodeVarint() + if err != nil { + return nil, err + } + + if b.BytesRemains() < int(size) { + return nil, io.ErrUnexpectedEOF + } + + limitBuffer := NewBuffer(b.ConsumeBytes(int(size))) + + var ret []float64 + for limitBuffer.BytesRemains() > 0 { + var element float64 + element, err = UnmarshalFloat64(limitBuffer, WireFixed64) + if err != nil { + return nil, err + } + + ret = append(ret, element) + } + + return ret, nil + + default: + return nil, ErrBadWireType + } +} diff --git a/api/golang/wire/struct.go b/api/golang/wire/struct.go new file mode 100644 index 0000000..b74d205 --- /dev/null +++ b/api/golang/wire/struct.go @@ -0,0 +1,99 @@ +package wire + +import ( + "io" + "reflect" +) + +type Struct interface { + Marshal(buffer *Buffer) error + + Unmarshal(buffer *Buffer, fieldIndex uint64, wt WireType) error + + Size() int +} + +func MarshalStruct(b *Buffer, fieldIndex uint64, msg Struct) error { + + structValue := reflect.ValueOf(msg) + + // *MyType被Message包裹后,判断不为nil + if structValue.IsNil() { + return nil + } + + size := msg.Size() + if size == 0 { + return nil + } + + b.EncodeVarint(MakeTag(fieldIndex, WireBytes)) + + b.EncodeVarint(uint64(size)) + + return msg.Marshal(b) +} + +func SizeStruct(fieldIndex uint64, msg Struct) int { + + structValue := reflect.ValueOf(msg) + + // *MyType被Message包裹后,判断不为nil + if structValue.IsNil() { + return 0 + } + + size := msg.Size() + + if size == 0 { + return 0 + } + + return SizeVarint(MakeTag(fieldIndex, WireVarint)) + SizeVarint(uint64(size)) + size +} + +func UnmarshalStructObject(b *Buffer, msg Struct) error { + + for b.BytesRemains() > 0 { + wireTag, err := b.DecodeVarint() + + if err != nil { + return err + } + + fieldIndex, wt := ParseTag(wireTag) + + err = msg.Unmarshal(b, fieldIndex, wt) + + if err == ErrUnknownField { + err = skipField(b, wt) + } + + if err != nil { + return err + } + } + + return nil +} + +func UnmarshalStruct(b *Buffer, wt WireType, msgPtr Struct) error { + switch wt { + case WireBytes: + size, err := b.DecodeVarint() + if err != nil { + return err + } + + if b.BytesRemains() < int(size) { + return io.ErrUnexpectedEOF + } + + limitBuffer := NewBuffer(b.ConsumeBytes(int(size))) + + return UnmarshalStructObject(limitBuffer, msgPtr) + + default: + return ErrBadWireType + } +} diff --git a/proto/variant.go b/api/golang/wire/variant.go similarity index 98% rename from proto/variant.go rename to api/golang/wire/variant.go index b7a7fb3..f483e78 100644 --- a/proto/variant.go +++ b/api/golang/wire/variant.go @@ -1,4 +1,4 @@ -package proto +package wire const maxVarintBytes = 10 // maximum length of a varint diff --git a/proto/wiretype.go b/api/golang/wire/wiretype.go similarity index 79% rename from proto/wiretype.go rename to api/golang/wire/wiretype.go index dbd07a0..4a94c09 100644 --- a/proto/wiretype.go +++ b/api/golang/wire/wiretype.go @@ -1,4 +1,4 @@ -package proto +package wire type WireType = uint64 @@ -11,11 +11,11 @@ const ( WireFixed64 // 64位定长 float64 ) -func makeWireTag(tag uint64, wt WireType) WireType { +func MakeTag(tag uint64, wt WireType) WireType { return uint64(tag)<<3 | uint64(wt) } -func parseWireTag(wireTag WireType) (tag uint64, wt WireType) { +func ParseTag(wireTag WireType) (tag uint64, wt WireType) { tag = wireTag >> 3 wt = WireType(wireTag & 7) return diff --git a/build/build.go b/build/build.go new file mode 100644 index 0000000..e470cf3 --- /dev/null +++ b/build/build.go @@ -0,0 +1,15 @@ +package build + +import "fmt" + +var ( + Version string + GitCommit string + BuildTime string +) + +func Print() { + fmt.Println("Version: ", Version) + fmt.Println("GitCommit: ", GitCommit) + fmt.Println("BuildTime: ", BuildTime) +} diff --git a/cmd/protoplus/main.go b/cmd/protoplus/main.go new file mode 100644 index 0000000..116ae39 --- /dev/null +++ b/cmd/protoplus/main.go @@ -0,0 +1,123 @@ +package main + +import ( + "flag" + "fmt" + "github.com/davyxu/protoplus/build" + _ "github.com/davyxu/protoplus/codegen" + "github.com/davyxu/protoplus/gen" + "github.com/davyxu/protoplus/gen/pbscheme" + "github.com/davyxu/protoplus/gen/ppcs" + "github.com/davyxu/protoplus/gen/ppgo" + "github.com/davyxu/protoplus/gen/ppscheme" + _ "github.com/davyxu/protoplus/gen/ppscheme" + "github.com/davyxu/protoplus/gen/route" + "github.com/davyxu/protoplus/model" + "github.com/davyxu/protoplus/util" + "os" +) + +var ( + flagVersion = flag.Bool("version", false, "show version") + + flagPackage = flag.String("package", "", "package name in source files") + flagClassBase = flag.String("classbase", "IProtoStruct", "struct inherite class type name in c#") + flagCodec = flag.String("codec", "protoplus", "default codec in register entry") +) + +type GenEntry struct { + name string + usage string + flagOutFile *string + flagExecute *bool + + outfile func(ctx *gen.Context) error + execute func(ctx *gen.Context) error +} + +var ( + genEntryList = []*GenEntry{ + {name: "ppgo_out", usage: "output protoplus message serialize golang source file", outfile: ppgo.GenGo}, + {name: "ppgoreg_out", usage: "output protoplus message register entry in golang", outfile: ppgo.GenGoReg}, + {name: "ppcs_out", usage: "output protoplus message serialize csharp source file", outfile: ppcs.GenCS}, + {name: "ppcsreg_out", usage: "output protoplus message register entry in csharp", outfile: ppcs.GenCSReg}, + {name: "pbscheme_out", usage: "output google protobuf schema file as single file", outfile: pbscheme.GenProto}, + + // 使用例子: protoc $(cat filelist.txt) + {name: "pbscheme_dir", usage: "output google protobuf schema files into dir", outfile: pbscheme.GenProtoDir}, + {name: "ppscheme_out", usage: "output protoplus scheme json file", outfile: ppscheme.GenJson}, + {name: "route_out", usage: "output route table json file", outfile: route.GenJson}, + + {name: "ppscheme", usage: "output protoplus scheme json to std out", execute: ppscheme.OutputJson}, + {name: "route", usage: "output route table json to std out", execute: route.OutputJson}, + } +) + +func defineEntryFlag() { + for _, entry := range genEntryList { + if entry.outfile != nil { + entry.flagOutFile = flag.String(entry.name, "", entry.usage) + } + if entry.execute != nil { + entry.flagExecute = flag.Bool(entry.name, false, entry.usage) + } + + } +} + +func runEntry(ctx *gen.Context) error { + for _, entry := range genEntryList { + if entry.flagOutFile != nil && *entry.flagOutFile != "" { + ctx.OutputFileName = *entry.flagOutFile + + fmt.Printf("[%s] %s\n", entry.name, ctx.OutputFileName) + err := entry.outfile(ctx) + if err != nil { + return err + } + } + + if entry.flagExecute != nil && *entry.flagExecute { + err := entry.execute(ctx) + if err != nil { + return err + } + } + } + + return nil +} + +func main() { + + defineEntryFlag() + + flag.Parse() + + // 版本 + if *flagVersion { + build.Print() + return + } + + var err error + var ctx gen.Context + ctx.DescriptorSet = new(model.DescriptorSet) + ctx.PackageName = *flagPackage + ctx.ClassBase = *flagClassBase + ctx.Codec = *flagCodec + + err = util.ParseFileList(ctx.DescriptorSet) + + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + err = runEntry(&ctx) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + +} diff --git a/codegen/codegen.go b/codegen/codegen.go index c065422..52c30d5 100644 --- a/codegen/codegen.go +++ b/codegen/codegen.go @@ -129,8 +129,6 @@ func (self *CodeGen) WriteOutputFile(outputFileName string) *CodeGen { return self } - fmt.Printf("%s\n", outputFileName) - return self } diff --git a/codegen/msgid.go b/codegen/msgid.go new file mode 100644 index 0000000..2a041db --- /dev/null +++ b/codegen/msgid.go @@ -0,0 +1,38 @@ +package codegen + +import ( + "github.com/davyxu/protoplus/model" + "strings" +) + +// 字符串转为16位整形值 +func stringHash(s string) (hash uint16) { + + for _, c := range s { + ch := uint16(c) + hash = hash + ((hash) << 5) + ch + (ch << 7) + } + + return +} + +func StructMsgID(d *model.Descriptor) (msgid int) { + if !IsMessage(d) { + return 0 + } + + if d.Kind == model.Kind_Struct { + msgid = d.TagValueInt("MsgID") + } + + if msgid == 0 { + // 这里不能引入packageName, 不同语言的package设置为不同, 造成消息id不一致 + msgid = int(stringHash(strings.ToLower(d.Name))) + } + + return +} + +func init() { + UsefulFunc["StructMsgID"] = StructMsgID +} diff --git a/example/csharp/Example.sln b/example/csharp/Example.sln index fc95afb..53b8293 100644 --- a/example/csharp/Example.sln +++ b/example/csharp/Example.sln @@ -5,7 +5,7 @@ VisualStudioVersion = 15.0.28010.2046 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example", "Example\Example.csproj", "{660CB175-1256-4A1C-B76C-08B45E9F0159}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtoPlus", "ProtoPlus\ProtoPlus.csproj", "{59F81F0A-5130-4882-90A3-100358537F2E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtoPlus", "..\..\api\csharp\ProtoPlus\ProtoPlus.csproj", "{1E171D88-E6CB-4493-98D1-5C7A36CA422B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -17,10 +17,10 @@ Global {660CB175-1256-4A1C-B76C-08B45E9F0159}.Debug|Any CPU.Build.0 = Debug|Any CPU {660CB175-1256-4A1C-B76C-08B45E9F0159}.Release|Any CPU.ActiveCfg = Release|Any CPU {660CB175-1256-4A1C-B76C-08B45E9F0159}.Release|Any CPU.Build.0 = Release|Any CPU - {59F81F0A-5130-4882-90A3-100358537F2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {59F81F0A-5130-4882-90A3-100358537F2E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {59F81F0A-5130-4882-90A3-100358537F2E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {59F81F0A-5130-4882-90A3-100358537F2E}.Release|Any CPU.Build.0 = Release|Any CPU + {1E171D88-E6CB-4493-98D1-5C7A36CA422B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1E171D88-E6CB-4493-98D1-5C7A36CA422B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1E171D88-E6CB-4493-98D1-5C7A36CA422B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1E171D88-E6CB-4493-98D1-5C7A36CA422B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/example/csharp/Example/Example.csproj b/example/csharp/Example/Example.csproj index 86932a4..c9a24bf 100644 --- a/example/csharp/Example/Example.csproj +++ b/example/csharp/Example/Example.csproj @@ -2,10 +2,14 @@ Exe - netcoreapp2.1 + netcoreapp2.0 Example.Program + + TRACE;DEBUG;NETCOREAPP2_0 + + @@ -16,7 +20,7 @@ - + diff --git a/example/csharp/Example/ProtoGen.cs b/example/csharp/Example/ProtoGen.cs index 56a1cf2..f73a018 100644 --- a/example/csharp/Example/ProtoGen.cs +++ b/example/csharp/Example/ProtoGen.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using ProtoPlus; +#pragma warning disable 162 namespace Proto { @@ -18,26 +19,43 @@ public enum MyEnum public partial class MyTypeMini : IProtoStruct { - public string Str; public bool Bool; + public int Int32; + public uint UInt32; + public long Int64; + public ulong UInt64; + public float Float32; + public double Float64; + public string Str; #region Serialize Code public void Init( ) - { - + { } public void Marshal(OutputStream stream) { - stream.WriteString(1, Str ); - stream.WriteBool(2, Bool ); + stream.WriteBool(1, Bool); + stream.WriteInt32(2, Int32); + stream.WriteUInt32(3, UInt32); + stream.WriteInt64(4, Int64); + stream.WriteUInt64(5, UInt64); + stream.WriteFloat(6, Float32); + stream.WriteDouble(7, Float64); + stream.WriteString(8, Str); } public int GetSize() { int size = 0; - size += OutputStream.SizeString(1, Str); - size += OutputStream.SizeBool(2, Bool); + size += OutputStream.SizeBool(1, Bool); + size += OutputStream.SizeInt32(2, Int32); + size += OutputStream.SizeUInt32(3, UInt32); + size += OutputStream.SizeInt64(4, Int64); + size += OutputStream.SizeUInt64(5, UInt64); + size += OutputStream.SizeFloat(6, Float32); + size += OutputStream.SizeDouble(7, Float64); + size += OutputStream.SizeString(8, Str); return size; } @@ -46,10 +64,28 @@ public bool Unmarshal(InputStream stream, int fieldNumber, WireFormat.WireType w switch (fieldNumber) { case 1: - stream.ReadString(wt, ref Str); + stream.ReadBool(wt, ref Bool); break; case 2: - stream.ReadBool(wt, ref Bool); + stream.ReadInt32(wt, ref Int32); + break; + case 3: + stream.ReadUInt32(wt, ref UInt32); + break; + case 4: + stream.ReadInt64(wt, ref Int64); + break; + case 5: + stream.ReadUInt64(wt, ref UInt64); + break; + case 6: + stream.ReadFloat(wt, ref Float32); + break; + case 7: + stream.ReadDouble(wt, ref Float64); + break; + case 8: + stream.ReadString(wt, ref Str); break; default: return true; @@ -93,32 +129,30 @@ public void Init( ) UInt64Slice = new List(); Float32Slice = new List(); Float64Slice = new List(); - StrSlice = new List(); - EnumSlice = new List(); - + EnumSlice = new List(); } public void Marshal(OutputStream stream) { - stream.WriteBool(1, Bool ); - stream.WriteInt32(2, Int32 ); - stream.WriteUInt32(3, UInt32 ); - stream.WriteInt64(4, Int64 ); - stream.WriteUInt64(5, UInt64 ); - stream.WriteFloat(6, Float32 ); - stream.WriteDouble(7, Float64 ); - stream.WriteString(8, Str ); - stream.WriteBytes(9, BytesSlice ); - stream.WriteBool(10, BoolSlice ); - stream.WriteInt32(11, Int32Slice ); - stream.WriteUInt32(12, UInt32Slice ); - stream.WriteInt64(13, Int64Slice ); - stream.WriteUInt64(14, UInt64Slice ); - stream.WriteFloat(15, Float32Slice ); - stream.WriteDouble(16, Float64Slice ); - stream.WriteString(17, StrSlice ); - stream.WriteEnum(18, Enum ); - stream.WriteEnum(19, EnumSlice ); + stream.WriteBool(1, Bool); + stream.WriteInt32(2, Int32); + stream.WriteUInt32(3, UInt32); + stream.WriteInt64(4, Int64); + stream.WriteUInt64(5, UInt64); + stream.WriteFloat(6, Float32); + stream.WriteDouble(7, Float64); + stream.WriteString(8, Str); + stream.WriteBytes(9, BytesSlice); + stream.WriteBool(10, BoolSlice); + stream.WriteInt32(11, Int32Slice); + stream.WriteUInt32(12, UInt32Slice); + stream.WriteInt64(13, Int64Slice); + stream.WriteUInt64(14, UInt64Slice); + stream.WriteFloat(15, Float32Slice); + stream.WriteDouble(16, Float64Slice); + stream.WriteString(17, StrSlice); + stream.WriteEnum(18, Enum); + stream.WriteEnum(19, EnumSlice); } public int GetSize() @@ -251,35 +285,34 @@ public void Init( ) UInt64Slice = new List(); Float32Slice = new List(); Float64Slice = new List(); - StrSlice = new List(); - EnumSlice = new List(); - - Struct = (MySubType) InputStream.CreateStruct(typeof(MySubType)); + StructSlice = new List(); + EnumSlice = new List(); + Struct = (MySubType) MessageMeta.NewStruct(typeof(MySubType)); } public void Marshal(OutputStream stream) { - stream.WriteBool(1, Bool ); - stream.WriteInt32(2, Int32 ); - stream.WriteUInt32(3, UInt32 ); - stream.WriteInt64(4, Int64 ); - stream.WriteUInt64(5, UInt64 ); - stream.WriteFloat(6, Float32 ); - stream.WriteDouble(7, Float64 ); - stream.WriteString(8, Str ); - stream.WriteStruct(9, Struct ); - stream.WriteBytes(10, BytesSlice ); - stream.WriteBool(11, BoolSlice ); - stream.WriteInt32(12, Int32Slice ); - stream.WriteUInt32(13, UInt32Slice ); - stream.WriteInt64(14, Int64Slice ); - stream.WriteUInt64(15, UInt64Slice ); - stream.WriteFloat(16, Float32Slice ); - stream.WriteDouble(17, Float64Slice ); - stream.WriteString(18, StrSlice ); - stream.WriteStruct(19, StructSlice ); - stream.WriteEnum(20, Enum ); - stream.WriteEnum(21, EnumSlice ); + stream.WriteBool(1, Bool); + stream.WriteInt32(2, Int32); + stream.WriteUInt32(3, UInt32); + stream.WriteInt64(4, Int64); + stream.WriteUInt64(5, UInt64); + stream.WriteFloat(6, Float32); + stream.WriteDouble(7, Float64); + stream.WriteString(8, Str); + stream.WriteStruct(9, Struct); + stream.WriteBytes(10, BytesSlice); + stream.WriteBool(11, BoolSlice); + stream.WriteInt32(12, Int32Slice); + stream.WriteUInt32(13, UInt32Slice); + stream.WriteInt64(14, Int64Slice); + stream.WriteUInt64(15, UInt64Slice); + stream.WriteFloat(16, Float32Slice); + stream.WriteDouble(17, Float64Slice); + stream.WriteString(18, StrSlice); + stream.WriteStruct(19, StructSlice); + stream.WriteEnum(20, Enum); + stream.WriteEnum(21, EnumSlice); } public int GetSize() @@ -385,27 +418,68 @@ public bool Unmarshal(InputStream stream, int fieldNumber, WireFormat.WireType w #endregion } + + public partial class LoginREQ : IProtoStruct + { + + #region Serialize Code + public void Init( ) + { + } + + public void Marshal(OutputStream stream) + { + } + + public int GetSize() + { + int size = 0; + return size; + } + + public bool Unmarshal(InputStream stream, int fieldNumber, WireFormat.WireType wt) + { + switch (fieldNumber) + { + default: + return true; + } + + return false; + } + #endregion + } + + + public partial class LoginACK : IProtoStruct + { + + #region Serialize Code + public void Init( ) + { + } + + public void Marshal(OutputStream stream) + { + } + public int GetSize() + { + int size = 0; + return size; + } - public static class MessageMetaRegister - { - public static void RegisterGeneratedMeta(MessageMeta meta) - { - meta.RegisterMeta(new MetaInfo - { - Type = typeof(MySubType), - ID = 33606, - SourcePeer = "client", - TargetPeer = "game", - }); - meta.RegisterMeta(new MetaInfo - { - Type = typeof(MyType), - ID = 9980, - SourcePeer = "", - TargetPeer = "", - }); + public bool Unmarshal(InputStream stream, int fieldNumber, WireFormat.WireType wt) + { + switch (fieldNumber) + { + default: + return true; + } + + return false; } - } + #endregion + } } diff --git a/example/csharp/Example/ProtoGenReg.cs b/example/csharp/Example/ProtoGenReg.cs new file mode 100644 index 0000000..5d0d6f5 --- /dev/null +++ b/example/csharp/Example/ProtoGenReg.cs @@ -0,0 +1,63 @@ +// Generated by github.com/davyxu/protoplus +// DO NOT EDIT! +using System; +using System.Collections.Generic; +#pragma warning disable 162 + +namespace Proto +{ + public class MetaInfo + { + public ushort ID; // 消息ID + public Type Type; // 消息类型 + + // 消息方向 + // 在proto中添加[MsgDir: "client -> game" ], 左边为源, 右边为目标 + public string SourcePeer; // 消息发起的源 + public string TargetPeer; // 消息的目标 + + public string Name; + } + + public static class MessageVisitor + { + public static void Visit(Action callback) + { + callback(new MetaInfo + { + Type = typeof(MyTypeMini), + ID = 0, + SourcePeer = "", + TargetPeer = "", + }); + callback(new MetaInfo + { + Type = typeof(MySubType), + ID = 0, + SourcePeer = "", + TargetPeer = "", + }); + callback(new MetaInfo + { + Type = typeof(MyType), + ID = 0, + SourcePeer = "", + TargetPeer = "", + }); + callback(new MetaInfo + { + Type = typeof(LoginREQ), + ID = 225, + SourcePeer = "client", + TargetPeer = "game", + }); + callback(new MetaInfo + { + Type = typeof(LoginACK), + ID = 27592, + SourcePeer = "", + TargetPeer = "", + }); + } + } +} diff --git a/example/csharp/Example/Test.cs b/example/csharp/Example/Test.cs index 99bded8..210cc4e 100644 --- a/example/csharp/Example/Test.cs +++ b/example/csharp/Example/Test.cs @@ -110,7 +110,7 @@ static MyType MakeMyType() }; } - static void TestFull() + static void TestSkipField() { byte[] data = new byte[256]; var s = new OutputStream(data); @@ -122,30 +122,40 @@ static void TestFull() var s2 = new InputStream(); s2.Init(data, 0, s.Position); - var myType2 = InputStream.CreateStruct(); + var myType2 = InputStream.CreateStruct(); s2.Unmarshal(myType2); - Debug.Assert(myType.Equals(myType2)); + Debug.Assert(myType2.Bool == myType2.Bool && myType2.Float32 == myType.Float32 && + myType2.Int32 == myType.Int32 && myType2.Int64 == myType.Int64 + && myType2.UInt64 == myType.UInt64 && myType2.UInt32 == myType.UInt32 + && myType2.Str == myType.Str); } - static void TestMessage() + static void TestFull() { - var mm = new MessageMeta(); - MessageMetaRegister.RegisterGeneratedMeta(mm); - var msg = mm.CreateMessageByID(33606); + byte[] data = new byte[256]; + var s = new OutputStream(data); - var meta = mm.GetMetaByType(msg.GetType()); + var myType = MakeMyType(); - Debug.Assert(meta.ID == 33606); + s.Marshal(myType); - Debug.Assert(meta.SourcePeer == "client"); + var s2 = new InputStream(); + s2.Init(data, 0, s.Position); + + var myType2 = InputStream.CreateStruct(); + + s2.Unmarshal(myType2); + + Debug.Assert(myType.Equals(myType2)); } + static void Main(string[] args) { TestFull(); - TestMessage(); + TestSkipField(); } } diff --git a/example/csharp/ProtoPlus/ProtoPlus.csproj b/example/csharp/ProtoPlus/ProtoPlus.csproj deleted file mode 100644 index 86ea3bb..0000000 --- a/example/csharp/ProtoPlus/ProtoPlus.csproj +++ /dev/null @@ -1,7 +0,0 @@ - - - - netcoreapp2.1 - - - diff --git a/gen/csharp/gen_cs.go b/gen/csharp/gen_cs.go deleted file mode 100644 index cc0e69e..0000000 --- a/gen/csharp/gen_cs.go +++ /dev/null @@ -1,23 +0,0 @@ -package csharp - -import ( - "fmt" - "github.com/davyxu/protoplus/codegen" - "github.com/davyxu/protoplus/gen" - _ "github.com/davyxu/protoplus/msgidutil" -) - -func GenCSharp(ctx *gen.Context) error { - - gen := codegen.NewCodeGen("cs"). - RegisterTemplateFunc(codegen.UsefulFunc). - RegisterTemplateFunc(UsefulFunc). - ParseTemplate(TemplateText, ctx) - - if gen.Error() != nil { - fmt.Println(string(gen.Code())) - return gen.Error() - } - - return gen.WriteOutputFile(ctx.OutputFileName).Error() -} diff --git a/gen/gen.go b/gen/gen.go index 0b93be0..029bae0 100644 --- a/gen/gen.go +++ b/gen/gen.go @@ -7,6 +7,5 @@ import ( type Context struct { *model.DescriptorSet OutputFileName string - StructBase string - RegEntry bool + ClassBase string } diff --git a/gen/golang/gen_go.go b/gen/golang/gen_go.go deleted file mode 100644 index 3631318..0000000 --- a/gen/golang/gen_go.go +++ /dev/null @@ -1,24 +0,0 @@ -package golang - -import ( - "fmt" - "github.com/davyxu/protoplus/codegen" - "github.com/davyxu/protoplus/gen" - _ "github.com/davyxu/protoplus/msgidutil" -) - -func GenGo(ctx *gen.Context) error { - - gen := codegen.NewCodeGen("go"). - RegisterTemplateFunc(codegen.UsefulFunc). - RegisterTemplateFunc(UsefulFunc). - ParseTemplate(TemplateText, ctx). - FormatGoCode() - - if gen.Error() != nil { - fmt.Println(string(gen.Code())) - return gen.Error() - } - - return gen.WriteOutputFile(ctx.OutputFileName).Error() -} diff --git a/gen/golang/text.go b/gen/golang/text.go deleted file mode 100644 index 92966c3..0000000 --- a/gen/golang/text.go +++ /dev/null @@ -1,124 +0,0 @@ -package golang - -// 报错行号+7 -const TemplateText = `// Generated by github.com/davyxu/protoplus -// DO NOT EDIT! -package {{.PackageName}} - -import ( - "github.com/davyxu/protoplus/proto" - "unsafe" {{if .RegEntry}} - "reflect" - "github.com/davyxu/cellnet" - "github.com/davyxu/cellnet/codec" {{end}} -) -var ( - _ *proto.Buffer - _ unsafe.Pointer {{if .RegEntry}} - _ cellnet.MessageMeta - _ codec.CodecRecycler - _ reflect.Kind {{end}} -) - -{{range $a, $enumobj := .Enums}} -type {{.Name}} int32 -const ( {{range .Fields}} - {{$enumobj.Name}}_{{.Name}} {{$enumobj.Name}} = {{PbTagNumber $enumobj .}} {{end}} -) - -var ( -{{$enumobj.Name}}MapperValueByName = map[string]int32{ {{range .Fields}} - "{{.Name}}": {{PbTagNumber $enumobj .}}, {{end}} -} - -{{$enumobj.Name}}MapperNameByValue = map[int32]string{ {{range .Fields}} - {{PbTagNumber $enumobj .}}: "{{.Name}}" , {{end}} -} -) - -func (self {{$enumobj.Name}}) String() string { - return {{$enumobj.Name}}MapperNameByValue[int32(self)] -} -{{end}} - -{{range $a, $obj := .Structs}} -{{ObjectLeadingComment .}} -type {{.Name}} struct{ {{range .Fields}} - {{GoFieldName .}} {{ProtoTypeName .}} {{GoStructTag .}}{{FieldTrailingComment .}} {{end}} -} - -func (self *{{.Name}}) String() string { return proto.CompactTextString(self) } - -func (self *{{.Name}}) Size() (ret int) { -{{range .Fields}} - {{if IsStructSlice .}} - if len(self.{{GoFieldName .}}) > 0 { - for _, elm := range self.{{GoFieldName .}} { - ret += proto.SizeStruct({{PbTagNumber $obj .}}, &elm) - } - } - {{else if IsStruct .}} - ret += proto.Size{{CodecName .}}({{PbTagNumber $obj .}}, &self.{{GoFieldName .}}) - {{else if IsEnum .}} - ret += proto.Size{{CodecName .}}({{PbTagNumber $obj .}}, int32(self.{{GoFieldName .}})) - {{else if IsEnumSlice .}} - ret += proto.Size{{CodecName .}}({{PbTagNumber $obj .}}, *(*[]int32)(unsafe.Pointer(&self.{{GoFieldName .}}))) - {{else}} - ret += proto.Size{{CodecName .}}({{PbTagNumber $obj .}}, self.{{GoFieldName .}}) - {{end}} -{{end}} - return -} - -func (self *{{.Name}}) Marshal(buffer *proto.Buffer) error { -{{range .Fields}} - {{if IsStructSlice .}} - for _, elm := range self.{{GoFieldName .}} { - proto.MarshalStruct(buffer, {{PbTagNumber $obj .}}, &elm) - } - {{else if IsStruct .}} - proto.Marshal{{CodecName .}}(buffer, {{PbTagNumber $obj .}}, &self.{{GoFieldName .}}) - {{else if IsEnum .}} - proto.Marshal{{CodecName .}}(buffer, {{PbTagNumber $obj .}}, int32(self.{{GoFieldName .}})) - {{else if IsEnumSlice .}} - proto.Marshal{{CodecName .}}(buffer, {{PbTagNumber $obj .}}, *(*[]int32)(unsafe.Pointer(&self.{{GoFieldName .}}))) - {{else}} - proto.Marshal{{CodecName .}}(buffer, {{PbTagNumber $obj .}}, self.{{GoFieldName .}}) - {{end}} -{{end}} - return nil -} - -func (self *{{.Name}}) Unmarshal(buffer *proto.Buffer, fieldIndex uint64, wt proto.WireType) error { - switch fieldIndex { - {{range .Fields}} case {{PbTagNumber $obj .}}: {{if IsStructSlice .}} - var elm {{.Type}} - if err := proto.UnmarshalStruct(buffer, wt, &elm); err != nil { - return err - } else { - self.{{GoFieldName .}} = append(self.{{GoFieldName .}}, elm) - return nil - }{{else if IsEnum .}} - return proto.Unmarshal{{CodecName .}}(buffer, wt, (*int32)(&self.{{GoFieldName .}})) {{else if IsEnumSlice .}} - return proto.Unmarshal{{CodecName .}}(buffer, wt, (*[]int32)(unsafe.Pointer(&self.{{GoFieldName .}}))) {{else}} - return proto.Unmarshal{{CodecName .}}(buffer, wt, &self.{{GoFieldName .}}) {{end}} - {{end}} - } - - return proto.ErrUnknownField -} -{{end}} - - -func init() { -{{if .RegEntry}} - {{range .Structs}} {{ if IsMessage . }} - cellnet.RegisterMessageMeta(&cellnet.MessageMeta{ - Codec: codec.MustGetCodec("{{StructCodec .}}"), - Type: reflect.TypeOf((*{{.Name}})(nil)).Elem(), - ID: {{StructMsgID .}}, - }) {{end}} {{end}} -{{end}} -} - -` diff --git a/gen/gogopb/func.go b/gen/pbscheme/func.go similarity index 96% rename from gen/gogopb/func.go rename to gen/pbscheme/func.go index 2cdd964..859c2f0 100644 --- a/gen/gogopb/func.go +++ b/gen/pbscheme/func.go @@ -1,4 +1,4 @@ -package gogopb +package pbscheme import ( "github.com/davyxu/protoplus/model" diff --git a/gen/pbscheme/gen_dir.go b/gen/pbscheme/gen_dir.go new file mode 100644 index 0000000..683bb3f --- /dev/null +++ b/gen/pbscheme/gen_dir.go @@ -0,0 +1,141 @@ +package pbscheme + +import ( + "fmt" + "github.com/davyxu/protoplus/codegen" + "github.com/davyxu/protoplus/gen" + "github.com/davyxu/protoplus/model" + "io/ioutil" + "path/filepath" + "sort" + "strings" +) + +const protoDirCodeTemplate = `// Generated by github.com/davyxu/protoplus +// DO NOT EDIT! +syntax = "proto3"; + +option go_package= "./;{{.PackageName}}"; + +package {{.PackageName}}; + +{{range $a, $enumobj := .DependentSource}} +import "{{.}}"; {{end}} + +{{range $a, $enumobj := .Enums}} +enum {{.Name}} { {{range .Fields}} + {{.Name}} = {{PbTagNumber $enumobj .}}; {{end}} +}{{end}} + +{{range $a, $obj := .Structs}} +{{ObjectLeadingComment .}} +message {{.Name}} { {{range .Fields}} + {{PbTypeName .}} {{GoFieldName .}} = {{PbTagNumber $obj .}};{{FieldTrailingComment .}} {{end}} +} +{{end}} +` + +type PBDescriptorSet struct { + model.DescriptorSet + + // pb生成文件依赖时, 使用以下字段 + DependentSource []string // 按文件管理的描述符取出时, 这个字段有效. 本文件依赖的其他source的symbiol + SourceName string // 按文件管理的描述符取出时, 这个字段有效. 表示本DescriptorSet的文件名 + dsBySource map[string]*PBDescriptorSet // 按文件名管理的描述符集合 +} + +func (self *PBDescriptorSet) addDependentSource(name string) { + + if self.SourceName == name { + return + } + + for _, n := range self.DependentSource { + if n == name { + return + } + } + + self.DependentSource = append(self.DependentSource, name) +} + +func (self *PBDescriptorSet) DescriptorSetBySource() map[string]*PBDescriptorSet { + if self.dsBySource != nil { + return self.dsBySource + } + + self.dsBySource = map[string]*PBDescriptorSet{} + + for _, obj := range self.Objects { + ds := self.dsBySource[obj.SrcName] + if ds == nil { + ds = &PBDescriptorSet{} + + ds.PackageName = self.PackageName + ds.Codec = self.Codec + ds.SourceName = obj.SrcName + + self.dsBySource[obj.SrcName] = ds + } + + ds.AddObject(obj) + } + + for _, file := range self.dsBySource { + for _, st := range file.Structs() { + + for _, fd := range st.Fields { + + switch fd.Kind { + case model.Kind_Struct, model.Kind_Enum: + refTarget := self.ObjectByName(fd.Type) + if refTarget != nil { + file.addDependentSource(refTarget.SrcName) + } + } + } + } + } + + return self.dsBySource +} + +func GenProtoDir(ctx *gen.Context) error { + + rootDS := &PBDescriptorSet{DescriptorSet: *ctx.DescriptorSet} + + var sb strings.Builder + + var srcNameList []string + for srcName, ds := range rootDS.DescriptorSetBySource() { + + srcNameList = append(srcNameList, srcName) + + gen := codegen.NewCodeGen("dirproto"). + RegisterTemplateFunc(codegen.UsefulFunc). + RegisterTemplateFunc(UsefulFunc). + ParseTemplate(protoDirCodeTemplate, ds) + + if gen.Error() != nil { + fmt.Println(string(gen.Data())) + return gen.Error() + } + + fullPathName := filepath.Join(ctx.OutputFileName, srcName) + + err := gen.WriteOutputFile(fullPathName).Error() + if err != nil { + return err + } + } + + sort.Strings(srcNameList) + + for _, d := range srcNameList { + fmt.Fprintf(&sb, "%s ", d) + } + + err := ioutil.WriteFile(filepath.Join(ctx.OutputFileName, "filelist.txt"), []byte(sb.String()), 0666) + + return err +} diff --git a/gen/gogopb/gen_proto.go b/gen/pbscheme/gen_proto.go similarity index 93% rename from gen/gogopb/gen_proto.go rename to gen/pbscheme/gen_proto.go index 0266934..49df3d0 100644 --- a/gen/gogopb/gen_proto.go +++ b/gen/pbscheme/gen_proto.go @@ -1,4 +1,4 @@ -package gogopb +package pbscheme import ( "fmt" @@ -11,6 +11,8 @@ const protoCodeTemplate = `// Generated by github.com/davyxu/protoplus // DO NOT EDIT! syntax = "proto3"; +option go_package= "./;{{.PackageName}}"; + package {{.PackageName}}; {{range $a, $enumobj := .Enums}} diff --git a/gen/csharp/func.go b/gen/ppcs/func.go similarity index 78% rename from gen/csharp/func.go rename to gen/ppcs/func.go index fa978ad..c60a14f 100644 --- a/gen/csharp/func.go +++ b/gen/ppcs/func.go @@ -1,4 +1,4 @@ -package csharp +package ppcs import ( "fmt" @@ -42,11 +42,28 @@ func init() { return CSTypeNameFull(fd) } - UsefulFunc["IsPrimitiveSlice"] = func(raw interface{}) bool { + // 原生类型/结构体 | 数组 | 导出方式 + // 原生类型 无初始化 + // 原生类型 是 new Type[]() + // 结构体 MessageMeta.NewStruct() + // 结构体 是 new Type[]() + + UsefulFunc["NoneStructCanInit"] = func(raw interface{}) bool { + + fd := raw.(*model.FieldDescriptor) + + if fd.Kind == model.Kind_Primitive && fd.Type == "string" { + return false + } + + return !fd.TagExists("NoInit") && fd.Repeatd + } + + UsefulFunc["StructCanInit"] = func(raw interface{}) bool { fd := raw.(*model.FieldDescriptor) - return fd.Repeatd && fd.Kind != model.Kind_Struct + return !fd.TagExists("NoInit") && !fd.Repeatd && fd.Kind == model.Kind_Struct } UsefulFunc["IsStructSlice"] = func(raw interface{}) bool { diff --git a/gen/ppcs/gen_cs.go b/gen/ppcs/gen_cs.go new file mode 100644 index 0000000..9df5804 --- /dev/null +++ b/gen/ppcs/gen_cs.go @@ -0,0 +1,37 @@ +package ppcs + +import ( + "fmt" + "github.com/davyxu/protoplus/codegen" + "github.com/davyxu/protoplus/gen" +) + +func GenCS(ctx *gen.Context) error { + + gen := codegen.NewCodeGen("cs"). + RegisterTemplateFunc(codegen.UsefulFunc). + RegisterTemplateFunc(UsefulFunc). + ParseTemplate(TemplateText, ctx) + + if gen.Error() != nil { + fmt.Println(string(gen.Code())) + return gen.Error() + } + + return gen.WriteOutputFile(ctx.OutputFileName).Error() +} + +func GenCSReg(ctx *gen.Context) error { + + gen := codegen.NewCodeGen("csreg"). + RegisterTemplateFunc(codegen.UsefulFunc). + RegisterTemplateFunc(UsefulFunc). + ParseTemplate(RegTemplateText, ctx) + + if gen.Error() != nil { + fmt.Println(string(gen.Code())) + return gen.Error() + } + + return gen.WriteOutputFile(ctx.OutputFileName).Error() +} diff --git a/gen/csharp/text.go b/gen/ppcs/text.go similarity index 55% rename from gen/csharp/text.go rename to gen/ppcs/text.go index 4d38196..b65ac70 100644 --- a/gen/csharp/text.go +++ b/gen/ppcs/text.go @@ -1,4 +1,4 @@ -package csharp +package ppcs // 报错行号+7 const TemplateText = `// Generated by github.com/davyxu/protoplus @@ -6,6 +6,7 @@ const TemplateText = `// Generated by github.com/davyxu/protoplus using System; using System.Collections.Generic; using ProtoPlus; +#pragma warning disable 162 namespace {{.PackageName}} { @@ -17,21 +18,20 @@ namespace {{.PackageName}} } {{end}} {{range $a, $obj := .Structs}} {{ObjectLeadingComment .}} - public partial class {{$obj.Name}} : {{$.StructBase}} + public partial class {{$obj.Name}} : {{$.ClassBase}} { {{range .Fields}}public {{CSTypeNameFull .}} {{.Name}}; {{end}} #region Serialize Code public void Init( ) - { {{range .Fields}}{{if IsPrimitiveSlice .}} - {{.Name}} = new {{CSTypeNameFull .}}(); {{end}}{{end}} - {{range .Fields}}{{if IsStruct .}} - {{.Name}} = ({{CSTypeNameFull .}}) InputStream.CreateStruct(typeof({{CSTypeNameFull .}})); {{end}} {{end}} + { {{range .Fields}}{{if NoneStructCanInit . }} + {{.Name}} = new {{CSTypeNameFull .}}(); {{end}}{{end}}{{range .Fields}}{{if StructCanInit .}} + {{.Name}} = ({{CSTypeNameFull .}}) MessageMeta.NewStruct(typeof({{CSTypeNameFull .}})); {{end}} {{end}} } public void Marshal(OutputStream stream) { {{range .Fields}} - stream.Write{{CodecName .}}({{PbTagNumber $obj .}}, {{.Name}} ); {{end}} + stream.Write{{CodecName .}}({{PbTagNumber $obj .}}, {{.Name}}); {{end}} } public int GetSize() @@ -57,21 +57,42 @@ namespace {{.PackageName}} #endregion } {{end}} +} +` -{{if .RegEntry}} - public static class MessageMetaRegister +const RegTemplateText = `// Generated by github.com/davyxu/protoplus +// DO NOT EDIT! +using System; +using System.Collections.Generic; +#pragma warning disable 162 + +namespace {{.PackageName}} +{ + public class MetaInfo + { + public ushort ID; // 消息ID + public Type Type; // 消息类型 + + // 消息方向 + // 在proto中添加[MsgDir: "client -> game" ], 左边为源, 右边为目标 + public string SourcePeer; // 消息发起的源 + public string TargetPeer; // 消息的目标 + + public string Name; + } + + public static class MessageVisitor { - public static void RegisterGeneratedMeta(MessageMeta meta) - { {{range .Structs}}{{ if IsMessage .}} - meta.RegisterMeta(new MetaInfo + public static void Visit(Action callback) + { {{range .Structs}} + callback(new MetaInfo { Type = typeof({{.Name}}), ID = {{StructMsgID .}}, SourcePeer = "{{GetSourcePeer .}}", TargetPeer = "{{GetTargetPeer .}}", - });{{end}} {{end}} + });{{end}} } } -{{end}} } ` diff --git a/gen/golang/func.go b/gen/ppgo/func.go similarity index 79% rename from gen/golang/func.go rename to gen/ppgo/func.go index bc95813..ebd8ae0 100644 --- a/gen/golang/func.go +++ b/gen/ppgo/func.go @@ -1,4 +1,4 @@ -package golang +package ppgo import ( "github.com/davyxu/protoplus/codegen" @@ -9,10 +9,16 @@ import ( var UsefulFunc = template.FuncMap{} func init() { + + // 所有结构生成Entry + UsefulFunc["GenEntry"] = func(d *model.Descriptor) bool { + return true + } + UsefulFunc["StructCodec"] = func(d *model.Descriptor) string { codecName := d.TagValueString("Codec") if codecName == "" { - return "protoplus" + return d.DescriptorSet.Codec } return codecName @@ -26,9 +32,17 @@ func init() { } // 默认指针 - //if fd.Kind == model.Kind_Struct { - // ret += "*" - //} + if fd.Kind == model.Kind_Struct { + ret += "*" + } + + ret += codegen.GoTypeName(fd) + return + } + + UsefulFunc["ProtoElementTypeName"] = func(raw interface{}) (ret string) { + + fd := raw.(*model.FieldDescriptor) ret += codegen.GoTypeName(fd) return @@ -48,6 +62,13 @@ func init() { return !fd.Repeatd && fd.Kind == model.Kind_Struct } + UsefulFunc["IsSlice"] = func(raw interface{}) bool { + + fd := raw.(*model.FieldDescriptor) + + return fd.Repeatd + } + UsefulFunc["IsEnum"] = func(raw interface{}) bool { fd := raw.(*model.FieldDescriptor) diff --git a/gen/ppgo/gen_go.go b/gen/ppgo/gen_go.go new file mode 100644 index 0000000..6898480 --- /dev/null +++ b/gen/ppgo/gen_go.go @@ -0,0 +1,39 @@ +package ppgo + +import ( + "fmt" + "github.com/davyxu/protoplus/codegen" + "github.com/davyxu/protoplus/gen" +) + +func GenGo(ctx *gen.Context) error { + + codeGen := codegen.NewCodeGen("go"). + RegisterTemplateFunc(codegen.UsefulFunc). + RegisterTemplateFunc(UsefulFunc). + ParseTemplate(TemplateText, ctx). + FormatGoCode() + + if codeGen.Error() != nil { + fmt.Println(string(codeGen.Code())) + return codeGen.Error() + } + + return codeGen.WriteOutputFile(ctx.OutputFileName).Error() +} + +func GenGoReg(ctx *gen.Context) error { + + codeGen := codegen.NewCodeGen("goreg"). + RegisterTemplateFunc(codegen.UsefulFunc). + RegisterTemplateFunc(UsefulFunc). + ParseTemplate(RegTemplateText, ctx). + FormatGoCode() + + if codeGen.Error() != nil { + fmt.Println(codeGen.Code()) + return codeGen.Error() + } + + return codeGen.WriteOutputFile(ctx.OutputFileName).Error() +} diff --git a/gen/ppgo/text.go b/gen/ppgo/text.go new file mode 100644 index 0000000..046dad7 --- /dev/null +++ b/gen/ppgo/text.go @@ -0,0 +1,149 @@ +package ppgo + +// 报错行号+7 +const TemplateText = `// Generated by github.com/davyxu/protoplus +// DO NOT EDIT! +package {{.PackageName}} + +import ( + "github.com/davyxu/protoplus/api/golang" + "github.com/davyxu/protoplus/api/golang/wire" + "unsafe" +) +var ( + _ *wire.Buffer + _ = ppgo.Marshal + _ unsafe.Pointer +) + +{{range $a, $enumobj := .Enums}} +type {{.Name}} int32 +const ( {{range .Fields}} + {{$enumobj.Name}}_{{.Name}} {{$enumobj.Name}} = {{PbTagNumber $enumobj .}} {{end}} +) + +var ( +{{$enumobj.Name}}MapperValueByName = map[string]int32{ {{range .Fields}} + "{{.Name}}": {{PbTagNumber $enumobj .}}, {{end}} +} + +{{$enumobj.Name}}MapperNameByValue = map[int32]string{ {{range .Fields}} + {{PbTagNumber $enumobj .}}: "{{.Name}}" , {{end}} +} +) + +func (self {{$enumobj.Name}}) String() string { + return {{$enumobj.Name}}MapperNameByValue[int32(self)] +} +{{end}} + +{{range $a, $obj := .Structs}} +{{ObjectLeadingComment .}} +type {{.Name}} struct{ {{range .Fields}} + {{GoFieldName .}} {{ProtoTypeName .}} {{GoStructTag .}}{{FieldTrailingComment .}} {{end}} +} + +func (self *{{.Name}}) String() string { return ppgo.CompactTextString(self) } + +func (self *{{.Name}}) Size() (ret int) { +{{range .Fields}} + {{if IsStructSlice .}} + if len(self.{{GoFieldName .}}) > 0 { + for _, elm := range self.{{GoFieldName .}} { + ret += wire.SizeStruct({{PbTagNumber $obj .}}, elm) + } + } + {{else if IsStruct .}} + ret += wire.Size{{CodecName .}}({{PbTagNumber $obj .}}, self.{{GoFieldName .}}) + {{else if IsEnum .}} + ret += wire.Size{{CodecName .}}({{PbTagNumber $obj .}}, int32(self.{{GoFieldName .}})) + {{else if IsEnumSlice .}} + ret += wire.Size{{CodecName .}}({{PbTagNumber $obj .}}, *(*[]int32)(unsafe.Pointer(&self.{{GoFieldName .}}))) + {{else}} + ret += wire.Size{{CodecName .}}({{PbTagNumber $obj .}}, self.{{GoFieldName .}}) + {{end}} +{{end}} + return +} + +func (self *{{.Name}}) Marshal(buffer *wire.Buffer) error { +{{range .Fields}} + {{if IsStructSlice .}} + for _, elm := range self.{{GoFieldName .}} { + wire.MarshalStruct(buffer, {{PbTagNumber $obj .}}, elm) + } + {{else if IsStruct .}} + wire.Marshal{{CodecName .}}(buffer, {{PbTagNumber $obj .}}, self.{{GoFieldName .}}) + {{else if IsEnum .}} + wire.Marshal{{CodecName .}}(buffer, {{PbTagNumber $obj .}}, int32(self.{{GoFieldName .}})) + {{else if IsEnumSlice .}} + wire.Marshal{{CodecName .}}(buffer, {{PbTagNumber $obj .}}, *(*[]int32)(unsafe.Pointer(&self.{{GoFieldName .}}))) + {{else}} + wire.Marshal{{CodecName .}}(buffer, {{PbTagNumber $obj .}}, self.{{GoFieldName .}}) + {{end}} +{{end}} + return nil +} + +func (self *{{.Name}}) Unmarshal(buffer *wire.Buffer, fieldIndex uint64, wt wire.WireType) error { + switch fieldIndex { + {{range .Fields}} case {{PbTagNumber $obj .}}: {{if IsStructSlice .}} + var elm {{.Type}} + if err := wire.UnmarshalStruct(buffer, wt, &elm); err != nil { + return err + } else { + self.{{GoFieldName .}} = append(self.{{GoFieldName .}}, &elm) + return nil + }{{else if IsEnum .}} + v, err := wire.Unmarshal{{CodecName .}}(buffer, wt) + self.{{GoFieldName .}} = {{ProtoTypeName .}}(v) + return err {{else if IsStruct .}} + var elm {{.Type}} + self.{{GoFieldName .}} = &elm + return wire.Unmarshal{{CodecName .}}(buffer, wt, self.{{GoFieldName .}}) {{else if IsEnumSlice .}} + v, err := wire.Unmarshal{{CodecName .}}(buffer, wt) + for _, vv := range v { + self.{{GoFieldName .}} = append(self.{{GoFieldName .}}, {{ProtoElementTypeName .}}(vv)) + } + return err {{else if IsSlice .}} + v, err := wire.Unmarshal{{CodecName .}}(buffer, wt) + self.{{GoFieldName .}} = append(self.{{GoFieldName .}}, v...) + return err {{else}} + v, err := wire.Unmarshal{{CodecName .}}(buffer, wt) + self.{{GoFieldName .}} = v + return err{{end}} + {{end}} + } + + return wire.ErrUnknownField +} +{{end}} +` + +const RegTemplateText = `// Generated by github.com/davyxu/protoplus +package {{.PackageName}} + +import ( + "github.com/davyxu/cellnet/codec" + "github.com/davyxu/cellnet/meta" + "reflect" +) + + +var ( + _ cellmeta.Meta + _ cellcodec.CodecRecycler + _ reflect.Kind +) + +func init() { + {{range .Structs}} + cellmeta.Register(&cellmeta.Meta{ + FullName: "{{$.PackageName}}.{{.Name}}", + ID: {{StructMsgID .}}, + New: func() interface{} { return &{{.Name}}{} }, + Type: reflect.TypeOf((*{{.Name}})(nil)).Elem(), + Codec: cellcodec.MustGetByName("{{StructCodec .}}"), + }) {{end}} +} +` diff --git a/gen/json/json.go b/gen/ppscheme/json.go similarity index 85% rename from gen/json/json.go rename to gen/ppscheme/json.go index 6a6eace..c7d745c 100644 --- a/gen/json/json.go +++ b/gen/ppscheme/json.go @@ -1,10 +1,10 @@ -package json +package ppscheme import ( "encoding/json" "fmt" + "github.com/davyxu/protoplus/codegen" "github.com/davyxu/protoplus/gen" - "github.com/davyxu/protoplus/msgidutil" "io/ioutil" "strconv" ) @@ -13,7 +13,7 @@ func genJsonData(ctx *gen.Context) (error, []byte) { for _, obj := range ctx.DescriptorSet.Objects { if obj.TagExists("AutoMsgID") { - obj.SetTagValue("AutoMsgID", strconv.Itoa(msgidutil.StructMsgID(obj))) + obj.SetTagValue("AutoMsgID", strconv.Itoa(codegen.StructMsgID(obj))) } } diff --git a/gen/route/msgdir.go b/gen/route/msgdir.go new file mode 100644 index 0000000..3972a8d --- /dev/null +++ b/gen/route/msgdir.go @@ -0,0 +1,100 @@ +package route + +import ( + "fmt" + "github.com/davyxu/protoplus/model" + "strings" +) + +type MsgDir struct { + From, Mid, To string + Name string +} + +func (self *MsgDir) Valid() bool { + return self.From != "" && self.To != "" +} + +func (self *MsgDir) HasStar() bool { + if self.From == "*" { + return true + } + + if self.Mid == "*" { + return true + } + + if self.To == "*" { + return true + } + + return false +} + +func (self *MsgDir) Less(Other MsgDir) bool { + + if self.From != Other.From { + return self.From < Other.From + } + + if self.Mid != Other.Mid { + return self.Mid < Other.Mid + } + + if self.To != Other.To { + return self.To < Other.To + } + + return self.Name < Other.Name +} + +func parseMessage(d *model.Descriptor) (rm MsgDir) { + + msgdir := d.TagValueString("MsgDir") + if msgdir == "" { + return + } + + // 上行 + if strings.Contains(msgdir, "->") { + endPoints := strings.Split(msgdir, "->") + rm.Name = d.Name + + switch len(endPoints) { + case 3: + rm.From = strings.TrimSpace(endPoints[0]) + + rm.Mid = strings.TrimSpace(endPoints[1]) + + rm.To = strings.TrimSpace(endPoints[2]) + return + case 2: + rm.From = strings.TrimSpace(endPoints[0]) + + rm.To = strings.TrimSpace(endPoints[1]) + return + } + } else if strings.Contains(msgdir, "<-") { // 下行 + endPoints := strings.Split(msgdir, "<-") + rm.Name = d.Name + + switch len(endPoints) { + case 3: + rm.From = strings.TrimSpace(endPoints[2]) + + rm.Mid = strings.TrimSpace(endPoints[1]) + + rm.To = strings.TrimSpace(endPoints[0]) + return + case 2: + rm.From = strings.TrimSpace(endPoints[1]) + + rm.To = strings.TrimSpace(endPoints[0]) + return + } + } else { + fmt.Println("unknown msg dir", d.Name, msgdir) + } + + return +} diff --git a/gen/route/route.go b/gen/route/route.go new file mode 100644 index 0000000..d8246b0 --- /dev/null +++ b/gen/route/route.go @@ -0,0 +1,64 @@ +package route + +import ( + "encoding/json" + "fmt" + "github.com/davyxu/protoplus/codegen" + "github.com/davyxu/protoplus/gen" + "github.com/davyxu/protoplus/model" + "io/ioutil" +) + +// 输出到文件 +func GenJson(ctx *gen.Context) error { + + data, err := genJsonData(ctx) + + if err != nil { + return err + } + + return ioutil.WriteFile(ctx.OutputFileName, data, 0666) +} + +// 将json输出到标准输出 +func OutputJson(ctx *gen.Context) error { + + data, err := genJsonData(ctx) + + if err != nil { + return err + } + + fmt.Println(string(data)) + return nil +} + +func genJsonData(ctx *gen.Context) ([]byte, error) { + + var rt model.RouteTable + + for _, d := range ctx.Structs() { + + msgDir := parseMessage(d) + msgID := codegen.StructMsgID(d) + + if msgDir.Valid() { + + rt.Rule = append(rt.Rule, &model.RouteRule{ + MsgName: ctx.PackageName + "." + d.Name, + SvcType: msgDir.To, + Router: msgDir.Mid, + MsgID: msgID, + }) + } + } + + data, err := json.MarshalIndent(&rt, "", "\t") + + if err != nil { + return nil, err + } + + return data, nil +} diff --git a/go.mod b/go.mod index 46414ab..206c83b 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,11 @@ module github.com/davyxu/protoplus go 1.12 -require github.com/davyxu/golexer v0.0.0-20180314091252-f048a86ae200 +require ( + // 测试用 + github.com/davyxu/golexer v0.1.1-0.20200202091144-a15ddde83f6a + github.com/davyxu/ulexer v0.0.0-20200713054812-c9bb8db3521f + github.com/stretchr/testify v1.7.0 +) + +replace github.com/davyxu/ulexer => ../ulexer diff --git a/go.sum b/go.sum index ab0c915..7d4f742 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,13 @@ -github.com/davyxu/golexer v0.0.0-20180314091252-f048a86ae200 h1:qLWlQBFg5c7HUOK+UdoGouLzRaYBQr2WwoAqixU+eik= -github.com/davyxu/golexer v0.0.0-20180314091252-f048a86ae200/go.mod h1:K/1PVWqaQEwMs+N+VvaoS66o1BAAwso+jEgXKBIa8QY= -github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davyxu/golexer v0.1.1-0.20200202091144-a15ddde83f6a h1:VYps2zwgBJPNuLGLiPrR4w6ud6cJpwlBA1OOytrCpx4= +github.com/davyxu/golexer v0.1.1-0.20200202091144-a15ddde83f6a/go.mod h1:dCUDBJcBQ9/AOzz6++KvSetGgVf5zXphevt6LQvKy0A= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go deleted file mode 100644 index 7d845e5..0000000 --- a/main.go +++ /dev/null @@ -1,110 +0,0 @@ -package main - -import ( - "flag" - "fmt" - _ "github.com/davyxu/protoplus/codegen" - "github.com/davyxu/protoplus/gen" - "github.com/davyxu/protoplus/gen/csharp" - "github.com/davyxu/protoplus/gen/gogopb" - "github.com/davyxu/protoplus/gen/golang" - "github.com/davyxu/protoplus/gen/json" - _ "github.com/davyxu/protoplus/gen/json" - "github.com/davyxu/protoplus/model" - "github.com/davyxu/protoplus/util" - "os" -) - -// 显示版本号 -var ( - flagVersion = flag.Bool("version", false, "Show version") - flagPackage = flag.String("package", "", "package name in source files") - flagPbOut = flag.String("pb_out", "", "output google protobuf schema file") - flagGoOut = flag.String("go_out", "", "output golang source file") - flagCSOut = flag.String("cs_out", "", "output csharp source file") - flagJsonOut = flag.String("json_out", "", "output json file") - flagJson = flag.Bool("json", false, "output json to std out") - flagGenReg = flag.Bool("genreg", false, "gen message register entry") - flagStructBase = flag.String("structbase", "IProtoStruct", "struct inherite class type name in c#") -) - -const Version = "0.1.0" - -func main() { - - flag.Parse() - - // 版本 - if *flagVersion { - fmt.Println(Version) - return - } - - var err error - var ctx gen.Context - ctx.DescriptorSet = new(model.DescriptorSet) - ctx.PackageName = *flagPackage - ctx.StructBase = *flagStructBase - ctx.RegEntry = *flagGenReg - - err = util.ParseFileList(ctx.DescriptorSet) - - if err != nil { - goto OnError - } - - if *flagGoOut != "" { - ctx.OutputFileName = *flagGoOut - - err = golang.GenGo(&ctx) - - if err != nil { - goto OnError - } - } - - if *flagCSOut != "" { - ctx.OutputFileName = *flagCSOut - - err = csharp.GenCSharp(&ctx) - - if err != nil { - goto OnError - } - } - - if *flagPbOut != "" { - ctx.OutputFileName = *flagPbOut - - err = gogopb.GenProto(&ctx) - - if err != nil { - goto OnError - } - } - - if *flagJsonOut != "" { - ctx.OutputFileName = *flagJsonOut - - err = json.GenJson(&ctx) - - if err != nil { - goto OnError - } - } - - if *flagJson { - - err = json.OutputJson(&ctx) - - if err != nil { - goto OnError - } - } - - return - -OnError: - fmt.Println(err) - os.Exit(1) -} diff --git a/model/descriptorset.go b/model/descriptorset.go index bc9db8f..d09d53d 100644 --- a/model/descriptorset.go +++ b/model/descriptorset.go @@ -3,17 +3,7 @@ package model type DescriptorSet struct { Objects []*Descriptor `json:",omitempty"` PackageName string -} - -func (self *DescriptorSet) Services() (ret []*Descriptor) { - - for _, o := range self.Objects { - if o.Kind == Kind_Service { - ret = append(ret, o) - } - } - - return + Codec string } func (self *DescriptorSet) Structs() (ret []*Descriptor) { diff --git a/model/field.go b/model/field.go index b0d28a1..ef12743 100644 --- a/model/field.go +++ b/model/field.go @@ -12,7 +12,7 @@ type FieldDescriptor struct { Tag int `json:",omitempty"` Repeatd bool `json:",omitempty"` - Descriptor *Descriptor `json:"-"` + Descriptor *Descriptor `json:"-"` // 字段归属的父级描述符 } func (self *FieldDescriptor) ParseType(str string) { diff --git a/model/route.go b/model/route.go new file mode 100644 index 0000000..699893d --- /dev/null +++ b/model/route.go @@ -0,0 +1,15 @@ +package model + +// 路由规则 +type RouteRule struct { + MsgName string + MsgID int + + SvcType string + Router string `json:",omitempty"` +} + +// 路由表,包含多条路由规则 +type RouteTable struct { + Rule []*RouteRule +} diff --git a/model/type.go b/model/type.go index 0fa2e2b..09ce59a 100644 --- a/model/type.go +++ b/model/type.go @@ -7,7 +7,6 @@ const ( Kind_Primitive = "primitive" Kind_Struct = "struct" Kind_Enum = "enum" - Kind_Service = "service" ) var SchemeType2Type = map[string]string{ diff --git a/msgidutil/flag.go b/msgidutil/flag.go deleted file mode 100644 index ff0edcf..0000000 --- a/msgidutil/flag.go +++ /dev/null @@ -1,13 +0,0 @@ -package msgidutil - -import "flag" - -var ( - flagAutoMsgIDCacheFile = flag.String("AutoMsgIDCacheFile", "", "Specifies auto msgid cache file") - flagShowOverWriteCacheFileWarning = flag.Bool("ShowOverWriteCacheFileWarning", false, "Show warning when over write auto msgid cahce file, default is false") - flagSuggestMsgIDStart = flag.Int("SuggestMsgIDStart", 0, "Suggest msgid start, default is 0") - flagCheckDuplicateMsgID = flag.Bool("CheckDuplicateMsgID", false, "Check duplicate msgid, default is false") - - // 消息号发生重复时,添加一个自定义的字符串可以错开 - flagMsgIDSalt = flag.String("MsgIDSalt", "", "extra string add to input msgname in order to prevent hash collide") -) diff --git a/msgidutil/msgid.go b/msgidutil/msgid.go deleted file mode 100644 index c08ce10..0000000 --- a/msgidutil/msgid.go +++ /dev/null @@ -1,197 +0,0 @@ -package msgidutil - -import ( - "bufio" - "encoding/json" - "errors" - "fmt" - "github.com/davyxu/protoplus/codegen" - "github.com/davyxu/protoplus/model" - "io/ioutil" - "os" -) - -var skipDupCacheMsgIDTips bool // 跳过重复缓存消息ID的警告提示 - -var msgNameByMsgID = map[int]string{} - -type MsgInfo struct { - Name string - MsgID int -} - -type AutoMsgIDCacheFile struct { - Caches []MsgInfo -} - -func (self *AutoMsgIDCacheFile) Load(cacheFileName string) { - existsFileData, _ := ioutil.ReadFile(cacheFileName) - - json.Unmarshal(existsFileData, self) -} - -func (self *AutoMsgIDCacheFile) Save(cacheFileName string) { - data, _ := json.MarshalIndent(self, "", "\t") - - ioutil.WriteFile(cacheFileName, data, 0666) -} - -func (self *AutoMsgIDCacheFile) ExistsMsgID(name string) int { - for _, m := range self.Caches { - if m.Name == name { - return m.MsgID - } - } - - return 0 -} - -func (self *AutoMsgIDCacheFile) GetNameByID(msgid int) string { - - for _, m := range self.Caches { - if m.MsgID == msgid { - return m.Name - } - } - - return "" -} - -func (self *AutoMsgIDCacheFile) AddNewMsg(name string, msgid int) { - - self.Caches = append(self.Caches, MsgInfo{name, msgid}) -} - -func (self *AutoMsgIDCacheFile) ModifyByMsgID(msgid int, name string) { - - for index, m := range self.Caches { - if m.MsgID == msgid { - self.Caches[index].Name = name - return - } - } - -} - -// MsgId:100 Descriptor FileA -// Descriptor <- auto gen 101 -// MsgID:200 Descriptor FileB -// Descriptor <- auto gen 201 - -func genMsgID(d *model.Descriptor, cacheFileName string, cachedMsgIDs *AutoMsgIDCacheFile) int { - - var msgid = 0 - for _, obj := range d.DescriptorSet.Objects { - - userMsgID := obj.TagValueInt("MsgID") - - if userMsgID == 0 && !obj.TagExists("AutoMsgID") { - continue - } - - if userMsgID > 0 { - msgid = userMsgID - } else { - msgid++ - } - - if obj == d { - - if existsName := cachedMsgIDs.GetNameByID(msgid); existsName != "" { - - if !skipDupCacheMsgIDTips && *flagShowOverWriteCacheFileWarning { - - fmt.Println("Warning: auto generate msg id has exists in automsgidcache file, the file will be overwrited.") - bufio.NewReader(os.Stdin).ReadString('\n') - - skipDupCacheMsgIDTips = true - } - - // msgid已存在,msgid拿给该消息使用 - cachedMsgIDs.ModifyByMsgID(msgid, d.Name) - } else { - // msgid不存在,添加 - cachedMsgIDs.AddNewMsg(d.Name, msgid) - } - - cachedMsgIDs.Save(cacheFileName) - - return msgid - } - } - - // 不会运行到这里的 - return 0 -} - -func autogenMsgIDByCacheFile(cacheFileName string, d *model.Descriptor) (newMsgID int) { - - var cachedMsgIDs AutoMsgIDCacheFile - cachedMsgIDs.Load(cacheFileName) - - // 协议里用户指定的ID - userMsgID := d.TagValueInt("MsgID") - - // 文件中,这个消息已经记忆的ID - existsMsgID := cachedMsgIDs.ExistsMsgID(d.Name) - - switch { - case userMsgID == 0 && existsMsgID == 0: // 缓冲无记录,用户没有指定ID,生成新ID - newMsgID = genMsgID(d, cacheFileName, &cachedMsgIDs) - case userMsgID != 0 && existsMsgID == 0: // 缓冲无记录,用户指定ID,用用户指定的ID - return userMsgID - case userMsgID == 0 && existsMsgID != 0: // 缓冲有记录ID,用户没有指定ID,用缓冲ID - return existsMsgID - case userMsgID != 0 && existsMsgID != 0: // 缓冲有记录ID,用户指定ID, 优先使用用户ID - return userMsgID - } - - return -} - -// 字符串转为16位整形值 -func StringHash(s string) (hash uint16) { - - for _, c := range s { - - ch := uint16(c) - - hash = hash + ((hash) << 5) + ch + (ch << 7) - } - - return -} - -func StructMsgID(d *model.Descriptor) (msgid int) { - if !codegen.IsMessage(d) { - return 0 - } - - if d.Kind == model.Kind_Struct { - msgid = d.TagValueInt("MsgID") - } - - if *flagAutoMsgIDCacheFile != "" { - msgid = autogenMsgIDByCacheFile(*flagAutoMsgIDCacheFile, d) - } else if msgid == 0 { - msgid = int(StringHash(d.DescriptorSet.PackageName + d.Name + *flagMsgIDSalt)) - } - - if *flagCheckDuplicateMsgID { - - oldName, exists := msgNameByMsgID[msgid] - if exists && d.Name != oldName { - panic(errors.New(fmt.Sprintf("%s's msgid(%d) has used by %s", d.Name, msgid, oldName))) - } - - msgNameByMsgID[msgid] = d.Name - - } - - return -} - -func init() { - - codegen.UsefulFunc["StructMsgID"] = StructMsgID -} diff --git a/msgidutil/suggest.go b/msgidutil/suggest.go deleted file mode 100644 index 8b88d38..0000000 --- a/msgidutil/suggest.go +++ /dev/null @@ -1,43 +0,0 @@ -package msgidutil - -import ( - "fmt" - "github.com/davyxu/protoplus/model" -) - -const sugguestMsgIDInterval = 100 - -func GenSuggestMsgID(dset *model.DescriptorSet) { - - // 段: MsgID/100 - - sectionMap := make(map[int]bool) - - for _, d := range dset.Objects { - - if d.Kind != model.Kind_Struct { - continue - } - userMsgID := d.TagValueInt("MsgID") - - if userMsgID == 0 { - continue - } - - sectionMap[userMsgID/sugguestMsgIDInterval] = true - } - - var section = *flagSuggestMsgIDStart / sugguestMsgIDInterval - - for ; ; section++ { - - if _, ok := sectionMap[section]; ok { - continue - } - - fmt.Println("Suggest msgid:", section*sugguestMsgIDInterval+1) - - return - } - -} diff --git a/parser/context.go b/parser/context.go index 486928b..b0df135 100644 --- a/parser/context.go +++ b/parser/context.go @@ -3,22 +3,33 @@ package parser import ( "github.com/davyxu/golexer" "github.com/davyxu/protoplus/model" + "strings" ) type Context struct { + + // 每个文件对应的属性 SourceName string *protoParser *model.DescriptorSet - *model.Descriptor + // 全局属性 + symbolPos map[interface{}]golexer.TokenPos + + sourceByName map[string]struct{} +} - *model.FieldDescriptor +func (self *Context) AddSource(sourceName string) bool { + lowerName := strings.ToLower(sourceName) + if _, ok := self.sourceByName[lowerName]; ok { + return false + } - *model.ServiceCall + self.sourceByName[lowerName] = struct{}{} - symbolPos map[interface{}]golexer.TokenPos + return true } func (self *Context) QuerySymbolPosString(v interface{}) string { @@ -31,13 +42,23 @@ func (self *Context) QuerySymbolPosString(v interface{}) string { } func (self *Context) AddSymbol(v interface{}, pos golexer.TokenPos) { - self.symbolPos[v] = pos } +func (self *Context) Clone(srcName string) *Context { + + return &Context{ + SourceName: srcName, + symbolPos: self.symbolPos, + sourceByName: self.sourceByName, + DescriptorSet: self.DescriptorSet, + } +} + func newContext() *Context { return &Context{ - symbolPos: make(map[interface{}]golexer.TokenPos), + symbolPos: map[interface{}]golexer.TokenPos{}, + sourceByName: map[string]struct{}{}, } } diff --git a/parser/entry.go b/parser/entry.go index f61da8b..3a9b296 100644 --- a/parser/entry.go +++ b/parser/entry.go @@ -2,7 +2,6 @@ package parser import ( "github.com/davyxu/protoplus/model" - "os" "strings" ) @@ -32,23 +31,10 @@ func ParseFileList(dset *model.DescriptorSet, filelist ...string) error { ctx.DescriptorSet = dset for _, filename := range filelist { - - ctx.SourceName = filename - - if file, err := os.Open(filename); err != nil { + err := parseFile(ctx, filename) + if err != nil { return err - } else { - - if err := rawParse(ctx, file); err != nil { - file.Close() - - return err - } - - file.Close() - } - } return checkAndFix(ctx) diff --git a/parser/enumfield.go b/parser/enumfield.go index 6f7f84c..86db954 100644 --- a/parser/enumfield.go +++ b/parser/enumfield.go @@ -2,18 +2,19 @@ package parser import ( "errors" + "github.com/davyxu/protoplus/model" ) -func parseEnumField(ctx *Context) { +func parseEnumField(ctx *Context, fd *model.FieldDescriptor) { // 注释 nameToken := ctx.RawToken() // 字段名 - ctx.FieldDescriptor.Name = ctx.Expect(Token_Identifier).Value() + fd.Name = ctx.Expect(Token_Identifier).Value() - if ctx.FieldNameExists(ctx.FieldDescriptor.Name) { - panic(errors.New("Duplicate field name: " + ctx.FieldDescriptor.Name)) + if fd.Descriptor.FieldNameExists(fd.Name) { + panic(errors.New("Duplicate field name: " + fd.Name)) } // 有等号 @@ -21,26 +22,26 @@ func parseEnumField(ctx *Context) { ctx.NextToken() // tag - ctx.FieldDescriptor.Tag = ctx.Expect(Token_Numeral).ToInt() + fd.Tag = ctx.Expect(Token_Numeral).ToInt() } else { // 没等号自动生成枚举序号 - if len(ctx.Fields) == 0 { - //fd.AutoTag = 0 - } else { - - // 按前面的序号+1 - //fd.AutoTag = d.MaxTag() + 1 - } + //if len(ctx.Fields) == 0 { + // //fd.AutoTag = 0 + //} else { + // + // // 按前面的序号+1 + // //fd.AutoTag = d.MaxTag() + 1 + //} } - ctx.FieldDescriptor.Comment = ctx.CommentGroupByLine(nameToken.Line()) + fd.Comment = ctx.CommentGroupByLine(nameToken.Line()) // 枚举值类型,始终为int32 - ctx.FieldDescriptor.ParseType("int32") + fd.ParseType("int32") - ctx.AddField(ctx.FieldDescriptor) + fd.Descriptor.AddField(fd) return } diff --git a/parser/parse_descriptor.go b/parser/parse_descriptor.go index 5678631..24908e5 100644 --- a/parser/parse_descriptor.go +++ b/parser/parse_descriptor.go @@ -5,15 +5,14 @@ import ( "github.com/davyxu/protoplus/model" ) -func parseObject(ctx *Context) { +func parseObject(ctx *Context, d *model.Descriptor) { - dotToken := ctx.RawToken() + keywordToken := ctx.RawToken() ctx.NextToken() // 名字 - ctx.Descriptor.Name = ctx.Expect(Token_Identifier).Value() - ctx.SrcName = ctx.SourceName + d.Name = ctx.Expect(Token_Identifier).Value() // 名字上面的注释 @@ -22,29 +21,19 @@ func parseObject(ctx *Context) { for ctx.TokenID() != Token_CurlyBraceR { - switch ctx.Descriptor.Kind { - case model.Kind_Struct, model.Kind_Enum: - var fd model.FieldDescriptor - ctx.FieldDescriptor = &fd - if ctx.TokenID() == Token_BracketL { - fd.TagSet = parseTagSet(ctx) - } - - case model.Kind_Service: - var sc model.ServiceCall - ctx.ServiceCall = &sc - if ctx.TokenID() == Token_BracketL { - sc.TagSet = parseTagSet(ctx) - } - } + var fd model.FieldDescriptor + fd.Descriptor = d - switch ctx.Descriptor.Kind { + switch d.Kind { case model.Kind_Struct: - parseStructField(ctx) + parseStructField(ctx, &fd) case model.Kind_Enum: - parseEnumField(ctx) - case model.Kind_Service: - parseSvcCallField(ctx) + parseEnumField(ctx, &fd) + } + + // 读取字段后面的[Tag项] + if ctx.TokenID() == Token_BracketL { + fd.TagSet = parseTagSet(ctx) } } @@ -53,14 +42,14 @@ func parseObject(ctx *Context) { // } - ctx.Descriptor.Comment = ctx.CommentGroupByLine(dotToken.Line()) + d.Comment = ctx.CommentGroupByLine(keywordToken.Line()) // 名字重复检查 - if ctx.DescriptorSet.ObjectNameExists(ctx.Descriptor.Name) { - panic(errors.New("Duplicate name: " + ctx.Descriptor.Name)) + if ctx.DescriptorSet.ObjectNameExists(d.Name) { + panic(errors.New("Duplicate name: " + d.Name)) } - ctx.AddObject(ctx.Descriptor) + ctx.AddObject(d) } diff --git a/parser/parse_descriptorset.go b/parser/parse_descriptorset.go index 48b1cf9..fab9182 100644 --- a/parser/parse_descriptorset.go +++ b/parser/parse_descriptorset.go @@ -7,6 +7,7 @@ import ( "github.com/davyxu/protoplus/model" "io" "io/ioutil" + "strings" ) // 解析字符串 @@ -33,7 +34,7 @@ func rawParse(ctx *Context, reader io.Reader) (retErr error) { for ctx.TokenID() != Token_EOF { var d model.Descriptor - ctx.Descriptor = &d + d.SrcName = ctx.SourceName if ctx.TokenID() == Token_BracketL { d.TagSet = parseTagSet(ctx) @@ -42,13 +43,12 @@ func rawParse(ctx *Context, reader io.Reader) (retErr error) { switch ctx.TokenID() { case Token_Struct: d.Kind = model.Kind_Struct - parseObject(ctx) + parseObject(ctx, &d) case Token_Enum: d.Kind = model.Kind_Enum - parseObject(ctx) - case Token_Service: - d.Kind = model.Kind_Service - parseObject(ctx) + parseObject(ctx, &d) + case Token_Import: + parseImport(ctx) default: panic(errors.New("Unknown token: " + ctx.TokenValue())) } @@ -91,6 +91,13 @@ func checkAndFix(ctx *Context) error { } } + if !d.TagExists("AutoMsgID") && !d.TagExists("MsgID") && (strings.HasSuffix(d.Name, "REQ") || strings.HasSuffix(d.Name, "ACK")) { + return fmt.Errorf("struct like message but not gen msgid: %s", d.Name) + } + + if d.Kind == model.Kind_Struct && (d.TagExists("AutoMsgID") || d.TagExists("MsgID")) && (!strings.HasSuffix(d.Name, "REQ") && !strings.HasSuffix(d.Name, "ACK")) { + return fmt.Errorf("struct gen msgid, but not like a message(REQ/ACK) : %s", d.Name) + } } return nil diff --git a/parser/parse_import.go b/parser/parse_import.go new file mode 100644 index 0000000..22c2d1f --- /dev/null +++ b/parser/parse_import.go @@ -0,0 +1,30 @@ +package parser + +import "os" + +func parseImport(ctx *Context) error { + + ctx.NextToken() + + fileName := ctx.Expect(Token_String).Value() + + return parseFile(ctx, fileName) +} + +func parseFile(ctx *Context, fileName string) error { + if !ctx.AddSource(fileName) { + return nil + } + + file, err := os.Open(fileName) + + if err != nil { + return err + } + + defer file.Close() + + newCtx := ctx.Clone(fileName) + + return rawParse(newCtx, file) +} diff --git a/parser/parser.go b/parser/parser.go index 0b76a48..f8bcb29 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -33,6 +33,7 @@ const ( Token_Assign // = Token_Service // service Token_RPC // rpc + Token_Import // import ) type protoParser struct { @@ -137,6 +138,7 @@ func newProtoParser(srcName string) *protoParser { l.AddMatcher(golexer.NewKeywordMatcher(Token_Struct, "struct")) l.AddMatcher(golexer.NewKeywordMatcher(Token_Service, "service")) l.AddMatcher(golexer.NewKeywordMatcher(Token_RPC, "rpc")) + l.AddMatcher(golexer.NewKeywordMatcher(Token_Import, "import")) l.AddMatcher(golexer.NewIdentifierMatcher(Token_Identifier)) diff --git a/parser/service.go b/parser/service.go deleted file mode 100644 index f75e489..0000000 --- a/parser/service.go +++ /dev/null @@ -1,44 +0,0 @@ -package parser - -import ( - "errors" -) - -func parseSvcCallField(ctx *Context) { - - // 注释 - nameToken := ctx.RawToken() - - if ctx.TokenID() == Token_RPC { - ctx.NextToken() - ctx.ServiceCall.IsRPC = true - } - - // 字段名 - ctx.ServiceCall.Name = ctx.Expect(Token_Identifier).Value() - - if ctx.CallNameExists(ctx.ServiceCall.Name) { - panic(errors.New("Duplicate svc call name: " + ctx.ServiceCall.Name)) - } - - tp := ctx.TokenPos() - - if ctx.TokenID() == Token_ParenL { - ctx.NextToken() - - ctx.ServiceCall.RequestName = ctx.Expect(Token_Identifier).Value() - ctx.Expect(Token_ParenR) - ctx.ServiceCall.RespondName = ctx.Expect(Token_Identifier).Value() - } else { - ctx.ServiceCall.RequestName = ctx.ServiceCall.Name + "REQ" - ctx.ServiceCall.RespondName = ctx.ServiceCall.Name + "ACK" - } - - ctx.ServiceCall.Comment = ctx.CommentGroupByLine(nameToken.Line()) - - ctx.AddSymbol(ctx.ServiceCall, tp) - - ctx.AddSvcCall(ctx.ServiceCall) - - return -} diff --git a/parser/structfield.go b/parser/structfield.go index 1f2c46e..588c52a 100644 --- a/parser/structfield.go +++ b/parser/structfield.go @@ -2,18 +2,19 @@ package parser import ( "errors" + "github.com/davyxu/protoplus/model" ) -func parseStructField(ctx *Context) { +func parseStructField(ctx *Context, fd *model.FieldDescriptor) { // 注释 nameToken := ctx.RawToken() // 字段名 - ctx.FieldDescriptor.Name = ctx.Expect(Token_Identifier).Value() + fd.Name = ctx.Expect(Token_Identifier).Value() - if ctx.FieldNameExists(ctx.FieldDescriptor.Name) { - panic(errors.New("Duplicate field name: " + ctx.FieldDescriptor.Name)) + if fd.Descriptor.FieldNameExists(fd.Name) { + panic(errors.New("Duplicate field name: " + fd.Name)) } tp := ctx.TokenPos() @@ -22,17 +23,17 @@ func parseStructField(ctx *Context) { if ctx.TokenID() == Token_BracketL { ctx.NextToken() ctx.Expect(Token_BracketR) - ctx.Repeatd = true + fd.Repeatd = true } // 延后在所有解析完后,检查TypeName是否合法,通过symbol还原位置并报错 - ctx.FieldDescriptor.ParseType(ctx.Expect(Token_Identifier).Value()) + fd.ParseType(ctx.Expect(Token_Identifier).Value()) - ctx.FieldDescriptor.Comment = ctx.CommentGroupByLine(nameToken.Line()) + fd.Comment = ctx.CommentGroupByLine(nameToken.Line()) - ctx.AddSymbol(ctx.FieldDescriptor, tp) + ctx.AddSymbol(fd, tp) - ctx.AddField(ctx.FieldDescriptor) + fd.Descriptor.AddField(fd) return } diff --git a/proto/api.go b/proto/api.go deleted file mode 100644 index 06e1cc6..0000000 --- a/proto/api.go +++ /dev/null @@ -1,43 +0,0 @@ -package proto - -type Struct interface { - Marshal(buffer *Buffer) error - - Unmarshal(buffer *Buffer, fieldIndex uint64, wt WireType) error - - Size() int -} - -func Marshal(raw interface{}) ([]byte, error) { - - msg := raw.(Struct) - - l := msg.Size() - - data := make([]byte, 0, l) - - buffer := NewBuffer(data) - - err := msg.Marshal(buffer) - if err != nil { - return nil, err - } - - return buffer.Bytes(), nil -} - -func Size(raw interface{}) int { - msg := raw.(Struct) - - return msg.Size() -} - -func Unmarshal(data []byte, raw interface{}) (err error) { - - msg := raw.(Struct) - - buffer := NewBuffer(data) - - return rawUnmarshalStruct(buffer, msg) - -} diff --git a/proto/field_size.go b/proto/field_size.go deleted file mode 100644 index 1359906..0000000 --- a/proto/field_size.go +++ /dev/null @@ -1,103 +0,0 @@ -package proto - -import ( - "reflect" -) - -func SizeBool(fieldIndex uint64, value bool) int { - - if value == false { - return 0 - } - - return SizeVarint(makeWireTag(fieldIndex, WireVarint)) + 1 -} - -func SizeInt32(fieldIndex uint64, value int32) int { - - switch { - case value > 0: - return SizeVarint(makeWireTag(fieldIndex, WireVarint)) + SizeVarint(uint64(value)) - case value < 0: - return SizeVarint(makeWireTag(fieldIndex, WireFixed32)) + 4 - default: - return 0 - } -} - -func SizeUInt32(fieldIndex uint64, value uint32) int { - - if value == 0 { - return 0 - } - - return SizeVarint(makeWireTag(fieldIndex, WireVarint)) + SizeVarint(uint64(value)) -} - -func SizeInt64(fieldIndex uint64, value int64) int { - - switch { - case value > 0: - return SizeVarint(makeWireTag(fieldIndex, WireVarint)) + SizeVarint(uint64(value)) - case value < 0: - return SizeVarint(makeWireTag(fieldIndex, WireFixed64)) + 8 - default: - return 0 - } -} - -func SizeUInt64(fieldIndex uint64, value uint64) int { - - if value == 0 { - return 0 - } - - return SizeVarint(makeWireTag(fieldIndex, WireVarint)) + SizeVarint(uint64(value)) -} - -func SizeFloat32(fieldIndex uint64, value float32) int { - - if value == 0 { - return 0 - } - - return SizeVarint(makeWireTag(fieldIndex, WireFixed32)) + 4 -} - -func SizeFloat64(fieldIndex uint64, value float64) int { - - if value == 0 { - return 0 - } - - return SizeVarint(makeWireTag(fieldIndex, WireFixed64)) + 8 -} - -func SizeString(fieldIndex uint64, value string) int { - - size := len(value) - - if size == 0 { - return 0 - } - - return SizeVarint(makeWireTag(fieldIndex, WireVarint)) + SizeVarint(uint64(size)) + size -} - -func SizeStruct(fieldIndex uint64, msg Struct) int { - - structValue := reflect.ValueOf(msg) - - // *MyType被Message包裹后,判断不为nil - if structValue.IsNil() { - return 0 - } - - size := msg.Size() - - if size == 0 { - return 0 - } - - return SizeVarint(makeWireTag(fieldIndex, WireVarint)) + SizeVarint(uint64(size)) + size -} diff --git a/proto/field_unmarshal.go b/proto/field_unmarshal.go deleted file mode 100644 index 74054f0..0000000 --- a/proto/field_unmarshal.go +++ /dev/null @@ -1,236 +0,0 @@ -package proto - -import ( - "io" - "math" -) - -func UnmarshalBool(b *Buffer, wt WireType, ret *bool) error { - switch wt { - case WireVarint: - v, err := b.DecodeVarint() - if err != nil { - return err - } - - if v != 0 { - *ret = true - } else { - *ret = false - } - default: - return ErrBadWireType - } - - return nil -} - -func UnmarshalInt32(b *Buffer, wt WireType, ret *int32) error { - - switch wt { - case WireVarint: - v, err := b.DecodeVarint() - if err != nil { - return err - } - *ret = int32(v) - - case WireFixed32: - v, err := b.DecodeFixed32() - if err != nil { - break - } - - *ret = int32(v) - default: - return ErrBadWireType - } - - return nil -} - -func UnmarshalUInt32(b *Buffer, wt WireType, ret *uint32) error { - - switch wt { - case WireVarint: - v, err := b.DecodeVarint() - if err != nil { - return err - } - *ret = uint32(v) - default: - return ErrBadWireType - } - - return nil -} - -func UnmarshalInt64(b *Buffer, wt WireType, ret *int64) error { - - switch wt { - case WireVarint: - v, err := b.DecodeVarint() - if err != nil { - return err - } - *ret = int64(v) - - case WireFixed64: - v, err := b.DecodeFixed64() - if err != nil { - break - } - - *ret = int64(v) - default: - return ErrBadWireType - } - - return nil -} - -func UnmarshalUInt64(b *Buffer, wt WireType, ret *uint64) error { - - switch wt { - case WireVarint: - v, err := b.DecodeVarint() - if err != nil { - return err - } - *ret = v - default: - return ErrBadWireType - } - - return nil -} - -func UnmarshalFloat32(b *Buffer, wt WireType, ret *float32) error { - - switch wt { - case WireFixed32: - v, err := b.DecodeFixed32() - if err != nil { - return err - } - - *ret = math.Float32frombits(uint32(v)) - default: - return ErrBadWireType - } - - return nil -} - -func UnmarshalFloat64(b *Buffer, wt WireType, ret *float64) error { - - switch wt { - case WireFixed64: - v, err := b.DecodeFixed64() - if err != nil { - return err - } - - *ret = math.Float64frombits(uint64(v)) - default: - return ErrBadWireType - } - - return nil -} - -func UnmarshalString(b *Buffer, wt WireType, ret *string) error { - switch wt { - case WireBytes: - v, err := b.DecodeStringBytes() - if err != nil { - return err - } - - *ret = v - default: - return ErrBadWireType - } - - return nil -} - -func skipField(b *Buffer, wt WireType) error { - - switch wt { - case WireVarint: - _, err := b.DecodeVarint() - return err - case WireBytes: - size, err := b.DecodeVarint() - - if b.BytesRemains() < int(size) { - return io.ErrUnexpectedEOF - } - - b.ConsumeBytes(int(size)) - return err - case WireZigzag32: - _, err := b.DecodeZigzag32() - return err - case WireZigzag64: - _, err := b.DecodeZigzag64() - return err - case WireFixed32: - _, err := b.DecodeFixed32() - return err - case WireFixed64: - _, err := b.DecodeFixed64() - return err - default: - return ErrBadWireType - } - - return nil -} - -func rawUnmarshalStruct(b *Buffer, msg Struct) error { - - for b.BytesRemains() > 0 { - wireTag, err := b.DecodeVarint() - - if err != nil { - return err - } - - fieldIndex, wt := parseWireTag(wireTag) - - err = msg.Unmarshal(b, fieldIndex, wt) - - if err == ErrUnknownField { - err = skipField(b, wt) - } - - if err != nil { - return err - } - } - - return nil -} - -func UnmarshalStruct(b *Buffer, wt WireType, msgPtr Struct) error { - switch wt { - case WireBytes: - size, err := b.DecodeVarint() - if err != nil { - return err - } - - if b.BytesRemains() < int(size) { - return io.ErrUnexpectedEOF - } - - limitBuffer := NewBuffer(b.ConsumeBytes(int(size))) - - return rawUnmarshalStruct(limitBuffer, msgPtr) - - default: - return ErrBadWireType - } -} diff --git a/proto/slice_unmarshal.go b/proto/slice_unmarshal.go deleted file mode 100644 index cb291a7..0000000 --- a/proto/slice_unmarshal.go +++ /dev/null @@ -1,265 +0,0 @@ -package proto - -import "io" - -func UnmarshalBytes(b *Buffer, wt WireType, ret *[]byte) error { - - switch wt { - case WireBytes: - size, err := b.DecodeVarint() - if err != nil { - return err - } - - if b.BytesRemains() < int(size) { - return io.ErrUnexpectedEOF - } - - *ret = append(*ret, b.ConsumeBytes(int(size))...) - - default: - return ErrBadWireType - } - - return nil -} - -func UnmarshalBoolSlice(b *Buffer, wt WireType, ret *[]bool) error { - switch wt { - case WireBytes: - count, err := b.DecodeVarint() - if err != nil { - return err - } - - if b.BytesRemains() < int(int(count)) { - return io.ErrUnexpectedEOF - } - - for _, element := range b.ConsumeBytes(int(count)) { - - switch element { - case 0: - *ret = append(*ret, false) - case 1: - *ret = append(*ret, true) - default: - return ErrBadBoolValue - } - - } - - default: - return ErrBadWireType - } - - return nil -} - -func UnmarshalInt32Slice(b *Buffer, wt WireType, ret *[]int32) error { - - switch wt { - case WireBytes: - size, err := b.DecodeVarint() - if err != nil { - return err - } - - if b.BytesRemains() < int(size) { - return io.ErrUnexpectedEOF - } - - limitBuffer := NewBuffer(b.ConsumeBytes(int(size))) - - for limitBuffer.BytesRemains() > 0 { - var element int32 - err = UnmarshalInt32(limitBuffer, WireVarint, &element) - if err != nil { - return err - } - - *ret = append(*ret, element) - } - - default: - return ErrBadWireType - } - - return nil -} - -func UnmarshalUInt32Slice(b *Buffer, wt WireType, ret *[]uint32) error { - - switch wt { - case WireBytes: - size, err := b.DecodeVarint() - if err != nil { - return err - } - - if b.BytesRemains() < int(size) { - return io.ErrUnexpectedEOF - } - - limitBuffer := NewBuffer(b.ConsumeBytes(int(size))) - - for limitBuffer.BytesRemains() > 0 { - var element uint32 - err = UnmarshalUInt32(limitBuffer, WireVarint, &element) - if err != nil { - return err - } - - *ret = append(*ret, element) - } - - default: - return ErrBadWireType - } - - return nil -} - -func UnmarshalInt64Slice(b *Buffer, wt WireType, ret *[]int64) error { - - switch wt { - case WireBytes: - size, err := b.DecodeVarint() - if err != nil { - return err - } - - if b.BytesRemains() < int(size) { - return io.ErrUnexpectedEOF - } - - limitBuffer := NewBuffer(b.ConsumeBytes(int(size))) - - for limitBuffer.BytesRemains() > 0 { - var element int64 - err = UnmarshalInt64(limitBuffer, WireVarint, &element) - if err != nil { - return err - } - - *ret = append(*ret, element) - } - - default: - return ErrBadWireType - } - - return nil -} - -func UnmarshalUInt64Slice(b *Buffer, wt WireType, ret *[]uint64) error { - - switch wt { - case WireBytes: - size, err := b.DecodeVarint() - if err != nil { - return err - } - - if b.BytesRemains() < int(size) { - return io.ErrUnexpectedEOF - } - - limitBuffer := NewBuffer(b.ConsumeBytes(int(size))) - - for limitBuffer.BytesRemains() > 0 { - var element uint64 - err = UnmarshalUInt64(limitBuffer, WireVarint, &element) - if err != nil { - return err - } - - *ret = append(*ret, element) - } - - default: - return ErrBadWireType - } - - return nil -} - -func UnmarshalStringSlice(b *Buffer, wt WireType, ret *[]string) error { - switch wt { - case WireBytes: - v, err := b.DecodeStringBytes() - if err != nil { - return err - } - - *ret = append(*ret, v) - default: - return ErrBadWireType - } - - return nil -} - -func UnmarshalFloat32Slice(b *Buffer, wt WireType, ret *[]float32) error { - - switch wt { - case WireBytes: - size, err := b.DecodeVarint() - if err != nil { - return err - } - - if b.BytesRemains() < int(size) { - return io.ErrUnexpectedEOF - } - - limitBuffer := NewBuffer(b.ConsumeBytes(int(size))) - - for limitBuffer.BytesRemains() > 0 { - var element float32 - err = UnmarshalFloat32(limitBuffer, WireFixed32, &element) - if err != nil { - return err - } - - *ret = append(*ret, element) - } - - default: - return ErrBadWireType - } - - return nil -} - -func UnmarshalFloat64Slice(b *Buffer, wt WireType, ret *[]float64) error { - - switch wt { - case WireBytes: - size, err := b.DecodeVarint() - if err != nil { - return err - } - - if b.BytesRemains() < int(size) { - return io.ErrUnexpectedEOF - } - - limitBuffer := NewBuffer(b.ConsumeBytes(int(size))) - - for limitBuffer.BytesRemains() > 0 { - var element float64 - err = UnmarshalFloat64(limitBuffer, WireFixed64, &element) - if err != nil { - return err - } - - *ret = append(*ret, element) - } - - default: - return ErrBadWireType - } - - return nil -} diff --git a/tests/Make.sh b/tests/Make.sh index 549b550..54ae890 100644 --- a/tests/Make.sh +++ b/tests/Make.sh @@ -1,12 +1,15 @@ #!/usr/bin/env bash -CURRDIR=`pwd` -cd ../../../../.. -export GOPATH=`pwd` -cd ${CURRDIR} -go build -v -o=${GOPATH}/bin/protoplus github.com/davyxu/protoplus +set -e + +go build -v -o=${GOPATH}/bin/protoplus github.com/davyxu/protoplus/cmd/protoplus # code.proto为输入文件 -${GOPATH}/bin/protoplus -go_out=code_gen.go -package=tests code.proto -${GOPATH}/bin/protoplus -cs_out=../csharp/Example/ProtoGen.cs -genreg -package=proto code.proto -${GOPATH}/bin/protoplus -pb_out=pb_gen.proto -package=proto code.proto \ No newline at end of file +ProtoPlusBin=${GOPATH}/bin/protoplus + +${ProtoPlusBin} -ppgo_out=code_gen.go -package=tests filelist.proto +${ProtoPlusBin} -ppgoreg_out=reg_gen.go -package=tests filelist.proto +${ProtoPlusBin} -ppcs_out=../example/csharp/Example/ProtoGen.cs -package=Proto filelist.proto +${ProtoPlusBin} -ppcsreg_out=../example/csharp/Example/ProtoGenReg.cs -package=Proto filelist.proto +${ProtoPlusBin} -pbscheme_out=pb_gen.proto -package=proto filelist.proto +${ProtoPlusBin} -route_out=route.json -package=proto filelist.proto \ No newline at end of file diff --git a/tests/code_gen.go b/tests/code_gen.go index cea6715..2614931 100644 --- a/tests/code_gen.go +++ b/tests/code_gen.go @@ -3,12 +3,14 @@ package tests import ( - "github.com/davyxu/protoplus/proto" + "github.com/davyxu/protoplus/api/golang" + "github.com/davyxu/protoplus/api/golang/wire" "unsafe" ) var ( - _ *proto.Buffer + _ *wire.Buffer + _ = ppgo.Marshal _ unsafe.Pointer ) @@ -39,40 +41,98 @@ func (self MyEnum) String() string { } type MyTypeMini struct { - Str string - Bool bool + Bool bool + Int32 int32 + UInt32 uint32 + Int64 int64 + UInt64 uint64 + Float32 float32 + Float64 float64 + Str string } -func (self *MyTypeMini) String() string { return proto.CompactTextString(self) } +func (self *MyTypeMini) String() string { return ppgo.CompactTextString(self) } func (self *MyTypeMini) Size() (ret int) { - ret += proto.SizeString(1, self.Str) + ret += wire.SizeBool(1, self.Bool) - ret += proto.SizeBool(2, self.Bool) + ret += wire.SizeInt32(2, self.Int32) + + ret += wire.SizeUInt32(3, self.UInt32) + + ret += wire.SizeInt64(4, self.Int64) + + ret += wire.SizeUInt64(5, self.UInt64) + + ret += wire.SizeFloat32(6, self.Float32) + + ret += wire.SizeFloat64(7, self.Float64) + + ret += wire.SizeString(8, self.Str) return } -func (self *MyTypeMini) Marshal(buffer *proto.Buffer) error { +func (self *MyTypeMini) Marshal(buffer *wire.Buffer) error { + + wire.MarshalBool(buffer, 1, self.Bool) + + wire.MarshalInt32(buffer, 2, self.Int32) + + wire.MarshalUInt32(buffer, 3, self.UInt32) - proto.MarshalString(buffer, 1, self.Str) + wire.MarshalInt64(buffer, 4, self.Int64) - proto.MarshalBool(buffer, 2, self.Bool) + wire.MarshalUInt64(buffer, 5, self.UInt64) + + wire.MarshalFloat32(buffer, 6, self.Float32) + + wire.MarshalFloat64(buffer, 7, self.Float64) + + wire.MarshalString(buffer, 8, self.Str) return nil } -func (self *MyTypeMini) Unmarshal(buffer *proto.Buffer, fieldIndex uint64, wt proto.WireType) error { +func (self *MyTypeMini) Unmarshal(buffer *wire.Buffer, fieldIndex uint64, wt wire.WireType) error { switch fieldIndex { case 1: - return proto.UnmarshalString(buffer, wt, &self.Str) + v, err := wire.UnmarshalBool(buffer, wt) + self.Bool = v + return err case 2: - return proto.UnmarshalBool(buffer, wt, &self.Bool) + v, err := wire.UnmarshalInt32(buffer, wt) + self.Int32 = v + return err + case 3: + v, err := wire.UnmarshalUInt32(buffer, wt) + self.UInt32 = v + return err + case 4: + v, err := wire.UnmarshalInt64(buffer, wt) + self.Int64 = v + return err + case 5: + v, err := wire.UnmarshalUInt64(buffer, wt) + self.UInt64 = v + return err + case 6: + v, err := wire.UnmarshalFloat32(buffer, wt) + self.Float32 = v + return err + case 7: + v, err := wire.UnmarshalFloat64(buffer, wt) + self.Float64 = v + return err + case 8: + v, err := wire.UnmarshalString(buffer, wt) + self.Str = v + return err } - return proto.ErrUnknownField + return wire.ErrUnknownField } type MySubType struct { @@ -97,138 +157,178 @@ type MySubType struct { EnumSlice []MyEnum } -func (self *MySubType) String() string { return proto.CompactTextString(self) } +func (self *MySubType) String() string { return ppgo.CompactTextString(self) } func (self *MySubType) Size() (ret int) { - ret += proto.SizeBool(1, self.Bool) + ret += wire.SizeBool(1, self.Bool) - ret += proto.SizeInt32(2, self.Int32) + ret += wire.SizeInt32(2, self.Int32) - ret += proto.SizeUInt32(3, self.UInt32) + ret += wire.SizeUInt32(3, self.UInt32) - ret += proto.SizeInt64(4, self.Int64) + ret += wire.SizeInt64(4, self.Int64) - ret += proto.SizeUInt64(5, self.UInt64) + ret += wire.SizeUInt64(5, self.UInt64) - ret += proto.SizeFloat32(6, self.Float32) + ret += wire.SizeFloat32(6, self.Float32) - ret += proto.SizeFloat64(7, self.Float64) + ret += wire.SizeFloat64(7, self.Float64) - ret += proto.SizeString(8, self.Str) + ret += wire.SizeString(8, self.Str) - ret += proto.SizeBytes(9, self.BytesSlice) + ret += wire.SizeBytes(9, self.BytesSlice) - ret += proto.SizeBoolSlice(10, self.BoolSlice) + ret += wire.SizeBoolSlice(10, self.BoolSlice) - ret += proto.SizeInt32Slice(11, self.Int32Slice) + ret += wire.SizeInt32Slice(11, self.Int32Slice) - ret += proto.SizeUInt32Slice(12, self.UInt32Slice) + ret += wire.SizeUInt32Slice(12, self.UInt32Slice) - ret += proto.SizeInt64Slice(13, self.Int64Slice) + ret += wire.SizeInt64Slice(13, self.Int64Slice) - ret += proto.SizeUInt64Slice(14, self.UInt64Slice) + ret += wire.SizeUInt64Slice(14, self.UInt64Slice) - ret += proto.SizeFloat32Slice(15, self.Float32Slice) + ret += wire.SizeFloat32Slice(15, self.Float32Slice) - ret += proto.SizeFloat64Slice(16, self.Float64Slice) + ret += wire.SizeFloat64Slice(16, self.Float64Slice) - ret += proto.SizeStringSlice(17, self.StrSlice) + ret += wire.SizeStringSlice(17, self.StrSlice) - ret += proto.SizeInt32(18, int32(self.Enum)) + ret += wire.SizeInt32(18, int32(self.Enum)) - ret += proto.SizeInt32Slice(19, *(*[]int32)(unsafe.Pointer(&self.EnumSlice))) + ret += wire.SizeInt32Slice(19, *(*[]int32)(unsafe.Pointer(&self.EnumSlice))) return } -func (self *MySubType) Marshal(buffer *proto.Buffer) error { +func (self *MySubType) Marshal(buffer *wire.Buffer) error { - proto.MarshalBool(buffer, 1, self.Bool) + wire.MarshalBool(buffer, 1, self.Bool) - proto.MarshalInt32(buffer, 2, self.Int32) + wire.MarshalInt32(buffer, 2, self.Int32) - proto.MarshalUInt32(buffer, 3, self.UInt32) + wire.MarshalUInt32(buffer, 3, self.UInt32) - proto.MarshalInt64(buffer, 4, self.Int64) + wire.MarshalInt64(buffer, 4, self.Int64) - proto.MarshalUInt64(buffer, 5, self.UInt64) + wire.MarshalUInt64(buffer, 5, self.UInt64) - proto.MarshalFloat32(buffer, 6, self.Float32) + wire.MarshalFloat32(buffer, 6, self.Float32) - proto.MarshalFloat64(buffer, 7, self.Float64) + wire.MarshalFloat64(buffer, 7, self.Float64) - proto.MarshalString(buffer, 8, self.Str) + wire.MarshalString(buffer, 8, self.Str) - proto.MarshalBytes(buffer, 9, self.BytesSlice) + wire.MarshalBytes(buffer, 9, self.BytesSlice) - proto.MarshalBoolSlice(buffer, 10, self.BoolSlice) + wire.MarshalBoolSlice(buffer, 10, self.BoolSlice) - proto.MarshalInt32Slice(buffer, 11, self.Int32Slice) + wire.MarshalInt32Slice(buffer, 11, self.Int32Slice) - proto.MarshalUInt32Slice(buffer, 12, self.UInt32Slice) + wire.MarshalUInt32Slice(buffer, 12, self.UInt32Slice) - proto.MarshalInt64Slice(buffer, 13, self.Int64Slice) + wire.MarshalInt64Slice(buffer, 13, self.Int64Slice) - proto.MarshalUInt64Slice(buffer, 14, self.UInt64Slice) + wire.MarshalUInt64Slice(buffer, 14, self.UInt64Slice) - proto.MarshalFloat32Slice(buffer, 15, self.Float32Slice) + wire.MarshalFloat32Slice(buffer, 15, self.Float32Slice) - proto.MarshalFloat64Slice(buffer, 16, self.Float64Slice) + wire.MarshalFloat64Slice(buffer, 16, self.Float64Slice) - proto.MarshalStringSlice(buffer, 17, self.StrSlice) + wire.MarshalStringSlice(buffer, 17, self.StrSlice) - proto.MarshalInt32(buffer, 18, int32(self.Enum)) + wire.MarshalInt32(buffer, 18, int32(self.Enum)) - proto.MarshalInt32Slice(buffer, 19, *(*[]int32)(unsafe.Pointer(&self.EnumSlice))) + wire.MarshalInt32Slice(buffer, 19, *(*[]int32)(unsafe.Pointer(&self.EnumSlice))) return nil } -func (self *MySubType) Unmarshal(buffer *proto.Buffer, fieldIndex uint64, wt proto.WireType) error { +func (self *MySubType) Unmarshal(buffer *wire.Buffer, fieldIndex uint64, wt wire.WireType) error { switch fieldIndex { case 1: - return proto.UnmarshalBool(buffer, wt, &self.Bool) + v, err := wire.UnmarshalBool(buffer, wt) + self.Bool = v + return err case 2: - return proto.UnmarshalInt32(buffer, wt, &self.Int32) + v, err := wire.UnmarshalInt32(buffer, wt) + self.Int32 = v + return err case 3: - return proto.UnmarshalUInt32(buffer, wt, &self.UInt32) + v, err := wire.UnmarshalUInt32(buffer, wt) + self.UInt32 = v + return err case 4: - return proto.UnmarshalInt64(buffer, wt, &self.Int64) + v, err := wire.UnmarshalInt64(buffer, wt) + self.Int64 = v + return err case 5: - return proto.UnmarshalUInt64(buffer, wt, &self.UInt64) + v, err := wire.UnmarshalUInt64(buffer, wt) + self.UInt64 = v + return err case 6: - return proto.UnmarshalFloat32(buffer, wt, &self.Float32) + v, err := wire.UnmarshalFloat32(buffer, wt) + self.Float32 = v + return err case 7: - return proto.UnmarshalFloat64(buffer, wt, &self.Float64) + v, err := wire.UnmarshalFloat64(buffer, wt) + self.Float64 = v + return err case 8: - return proto.UnmarshalString(buffer, wt, &self.Str) + v, err := wire.UnmarshalString(buffer, wt) + self.Str = v + return err case 9: - return proto.UnmarshalBytes(buffer, wt, &self.BytesSlice) + v, err := wire.UnmarshalBytes(buffer, wt) + self.BytesSlice = v + return err case 10: - return proto.UnmarshalBoolSlice(buffer, wt, &self.BoolSlice) + v, err := wire.UnmarshalBoolSlice(buffer, wt) + self.BoolSlice = append(self.BoolSlice, v...) + return err case 11: - return proto.UnmarshalInt32Slice(buffer, wt, &self.Int32Slice) + v, err := wire.UnmarshalInt32Slice(buffer, wt) + self.Int32Slice = append(self.Int32Slice, v...) + return err case 12: - return proto.UnmarshalUInt32Slice(buffer, wt, &self.UInt32Slice) + v, err := wire.UnmarshalUInt32Slice(buffer, wt) + self.UInt32Slice = append(self.UInt32Slice, v...) + return err case 13: - return proto.UnmarshalInt64Slice(buffer, wt, &self.Int64Slice) + v, err := wire.UnmarshalInt64Slice(buffer, wt) + self.Int64Slice = append(self.Int64Slice, v...) + return err case 14: - return proto.UnmarshalUInt64Slice(buffer, wt, &self.UInt64Slice) + v, err := wire.UnmarshalUInt64Slice(buffer, wt) + self.UInt64Slice = append(self.UInt64Slice, v...) + return err case 15: - return proto.UnmarshalFloat32Slice(buffer, wt, &self.Float32Slice) + v, err := wire.UnmarshalFloat32Slice(buffer, wt) + self.Float32Slice = append(self.Float32Slice, v...) + return err case 16: - return proto.UnmarshalFloat64Slice(buffer, wt, &self.Float64Slice) + v, err := wire.UnmarshalFloat64Slice(buffer, wt) + self.Float64Slice = append(self.Float64Slice, v...) + return err case 17: - return proto.UnmarshalStringSlice(buffer, wt, &self.StrSlice) + v, err := wire.UnmarshalStringSlice(buffer, wt) + self.StrSlice = append(self.StrSlice, v...) + return err case 18: - return proto.UnmarshalInt32(buffer, wt, (*int32)(&self.Enum)) + v, err := wire.UnmarshalInt32(buffer, wt) + self.Enum = MyEnum(v) + return err case 19: - return proto.UnmarshalInt32Slice(buffer, wt, (*[]int32)(unsafe.Pointer(&self.EnumSlice))) + v, err := wire.UnmarshalInt32Slice(buffer, wt) + for _, vv := range v { + self.EnumSlice = append(self.EnumSlice, MyEnum(vv)) + } + return err } - return proto.ErrUnknownField + return wire.ErrUnknownField } type MyType struct { @@ -240,7 +340,7 @@ type MyType struct { Float32 float32 Float64 float64 Str string - Struct MySubType + Struct *MySubType BytesSlice []byte BoolSlice []bool Int32Slice []int32 @@ -250,282 +350,253 @@ type MyType struct { Float32Slice []float32 Float64Slice []float64 StrSlice []string - StructSlice []MySubType + StructSlice []*MySubType Enum MyEnum EnumSlice []MyEnum } -func (self *MyType) String() string { return proto.CompactTextString(self) } +func (self *MyType) String() string { return ppgo.CompactTextString(self) } func (self *MyType) Size() (ret int) { - ret += proto.SizeBool(1, self.Bool) + ret += wire.SizeBool(1, self.Bool) - ret += proto.SizeInt32(2, self.Int32) + ret += wire.SizeInt32(2, self.Int32) - ret += proto.SizeUInt32(3, self.UInt32) + ret += wire.SizeUInt32(3, self.UInt32) - ret += proto.SizeInt64(4, self.Int64) + ret += wire.SizeInt64(4, self.Int64) - ret += proto.SizeUInt64(5, self.UInt64) + ret += wire.SizeUInt64(5, self.UInt64) - ret += proto.SizeFloat32(6, self.Float32) + ret += wire.SizeFloat32(6, self.Float32) - ret += proto.SizeFloat64(7, self.Float64) + ret += wire.SizeFloat64(7, self.Float64) - ret += proto.SizeString(8, self.Str) + ret += wire.SizeString(8, self.Str) - ret += proto.SizeStruct(9, &self.Struct) + ret += wire.SizeStruct(9, self.Struct) - ret += proto.SizeBytes(10, self.BytesSlice) + ret += wire.SizeBytes(10, self.BytesSlice) - ret += proto.SizeBoolSlice(11, self.BoolSlice) + ret += wire.SizeBoolSlice(11, self.BoolSlice) - ret += proto.SizeInt32Slice(12, self.Int32Slice) + ret += wire.SizeInt32Slice(12, self.Int32Slice) - ret += proto.SizeUInt32Slice(13, self.UInt32Slice) + ret += wire.SizeUInt32Slice(13, self.UInt32Slice) - ret += proto.SizeInt64Slice(14, self.Int64Slice) + ret += wire.SizeInt64Slice(14, self.Int64Slice) - ret += proto.SizeUInt64Slice(15, self.UInt64Slice) + ret += wire.SizeUInt64Slice(15, self.UInt64Slice) - ret += proto.SizeFloat32Slice(16, self.Float32Slice) + ret += wire.SizeFloat32Slice(16, self.Float32Slice) - ret += proto.SizeFloat64Slice(17, self.Float64Slice) + ret += wire.SizeFloat64Slice(17, self.Float64Slice) - ret += proto.SizeStringSlice(18, self.StrSlice) + ret += wire.SizeStringSlice(18, self.StrSlice) if len(self.StructSlice) > 0 { for _, elm := range self.StructSlice { - ret += proto.SizeStruct(19, &elm) + ret += wire.SizeStruct(19, elm) } } - ret += proto.SizeInt32(20, int32(self.Enum)) + ret += wire.SizeInt32(20, int32(self.Enum)) - ret += proto.SizeInt32Slice(21, *(*[]int32)(unsafe.Pointer(&self.EnumSlice))) + ret += wire.SizeInt32Slice(21, *(*[]int32)(unsafe.Pointer(&self.EnumSlice))) return } -func (self *MyType) Marshal(buffer *proto.Buffer) error { +func (self *MyType) Marshal(buffer *wire.Buffer) error { - proto.MarshalBool(buffer, 1, self.Bool) + wire.MarshalBool(buffer, 1, self.Bool) - proto.MarshalInt32(buffer, 2, self.Int32) + wire.MarshalInt32(buffer, 2, self.Int32) - proto.MarshalUInt32(buffer, 3, self.UInt32) + wire.MarshalUInt32(buffer, 3, self.UInt32) - proto.MarshalInt64(buffer, 4, self.Int64) + wire.MarshalInt64(buffer, 4, self.Int64) - proto.MarshalUInt64(buffer, 5, self.UInt64) + wire.MarshalUInt64(buffer, 5, self.UInt64) - proto.MarshalFloat32(buffer, 6, self.Float32) + wire.MarshalFloat32(buffer, 6, self.Float32) - proto.MarshalFloat64(buffer, 7, self.Float64) + wire.MarshalFloat64(buffer, 7, self.Float64) - proto.MarshalString(buffer, 8, self.Str) + wire.MarshalString(buffer, 8, self.Str) - proto.MarshalStruct(buffer, 9, &self.Struct) + wire.MarshalStruct(buffer, 9, self.Struct) - proto.MarshalBytes(buffer, 10, self.BytesSlice) + wire.MarshalBytes(buffer, 10, self.BytesSlice) - proto.MarshalBoolSlice(buffer, 11, self.BoolSlice) + wire.MarshalBoolSlice(buffer, 11, self.BoolSlice) - proto.MarshalInt32Slice(buffer, 12, self.Int32Slice) + wire.MarshalInt32Slice(buffer, 12, self.Int32Slice) - proto.MarshalUInt32Slice(buffer, 13, self.UInt32Slice) + wire.MarshalUInt32Slice(buffer, 13, self.UInt32Slice) - proto.MarshalInt64Slice(buffer, 14, self.Int64Slice) + wire.MarshalInt64Slice(buffer, 14, self.Int64Slice) - proto.MarshalUInt64Slice(buffer, 15, self.UInt64Slice) + wire.MarshalUInt64Slice(buffer, 15, self.UInt64Slice) - proto.MarshalFloat32Slice(buffer, 16, self.Float32Slice) + wire.MarshalFloat32Slice(buffer, 16, self.Float32Slice) - proto.MarshalFloat64Slice(buffer, 17, self.Float64Slice) + wire.MarshalFloat64Slice(buffer, 17, self.Float64Slice) - proto.MarshalStringSlice(buffer, 18, self.StrSlice) + wire.MarshalStringSlice(buffer, 18, self.StrSlice) for _, elm := range self.StructSlice { - proto.MarshalStruct(buffer, 19, &elm) + wire.MarshalStruct(buffer, 19, elm) } - proto.MarshalInt32(buffer, 20, int32(self.Enum)) + wire.MarshalInt32(buffer, 20, int32(self.Enum)) - proto.MarshalInt32Slice(buffer, 21, *(*[]int32)(unsafe.Pointer(&self.EnumSlice))) + wire.MarshalInt32Slice(buffer, 21, *(*[]int32)(unsafe.Pointer(&self.EnumSlice))) return nil } -func (self *MyType) Unmarshal(buffer *proto.Buffer, fieldIndex uint64, wt proto.WireType) error { +func (self *MyType) Unmarshal(buffer *wire.Buffer, fieldIndex uint64, wt wire.WireType) error { switch fieldIndex { case 1: - return proto.UnmarshalBool(buffer, wt, &self.Bool) + v, err := wire.UnmarshalBool(buffer, wt) + self.Bool = v + return err case 2: - return proto.UnmarshalInt32(buffer, wt, &self.Int32) + v, err := wire.UnmarshalInt32(buffer, wt) + self.Int32 = v + return err case 3: - return proto.UnmarshalUInt32(buffer, wt, &self.UInt32) + v, err := wire.UnmarshalUInt32(buffer, wt) + self.UInt32 = v + return err case 4: - return proto.UnmarshalInt64(buffer, wt, &self.Int64) + v, err := wire.UnmarshalInt64(buffer, wt) + self.Int64 = v + return err case 5: - return proto.UnmarshalUInt64(buffer, wt, &self.UInt64) + v, err := wire.UnmarshalUInt64(buffer, wt) + self.UInt64 = v + return err case 6: - return proto.UnmarshalFloat32(buffer, wt, &self.Float32) + v, err := wire.UnmarshalFloat32(buffer, wt) + self.Float32 = v + return err case 7: - return proto.UnmarshalFloat64(buffer, wt, &self.Float64) + v, err := wire.UnmarshalFloat64(buffer, wt) + self.Float64 = v + return err case 8: - return proto.UnmarshalString(buffer, wt, &self.Str) + v, err := wire.UnmarshalString(buffer, wt) + self.Str = v + return err case 9: - return proto.UnmarshalStruct(buffer, wt, &self.Struct) + var elm MySubType + self.Struct = &elm + return wire.UnmarshalStruct(buffer, wt, self.Struct) case 10: - return proto.UnmarshalBytes(buffer, wt, &self.BytesSlice) + v, err := wire.UnmarshalBytes(buffer, wt) + self.BytesSlice = v + return err case 11: - return proto.UnmarshalBoolSlice(buffer, wt, &self.BoolSlice) + v, err := wire.UnmarshalBoolSlice(buffer, wt) + self.BoolSlice = append(self.BoolSlice, v...) + return err case 12: - return proto.UnmarshalInt32Slice(buffer, wt, &self.Int32Slice) + v, err := wire.UnmarshalInt32Slice(buffer, wt) + self.Int32Slice = append(self.Int32Slice, v...) + return err case 13: - return proto.UnmarshalUInt32Slice(buffer, wt, &self.UInt32Slice) + v, err := wire.UnmarshalUInt32Slice(buffer, wt) + self.UInt32Slice = append(self.UInt32Slice, v...) + return err case 14: - return proto.UnmarshalInt64Slice(buffer, wt, &self.Int64Slice) + v, err := wire.UnmarshalInt64Slice(buffer, wt) + self.Int64Slice = append(self.Int64Slice, v...) + return err case 15: - return proto.UnmarshalUInt64Slice(buffer, wt, &self.UInt64Slice) + v, err := wire.UnmarshalUInt64Slice(buffer, wt) + self.UInt64Slice = append(self.UInt64Slice, v...) + return err case 16: - return proto.UnmarshalFloat32Slice(buffer, wt, &self.Float32Slice) + v, err := wire.UnmarshalFloat32Slice(buffer, wt) + self.Float32Slice = append(self.Float32Slice, v...) + return err case 17: - return proto.UnmarshalFloat64Slice(buffer, wt, &self.Float64Slice) + v, err := wire.UnmarshalFloat64Slice(buffer, wt) + self.Float64Slice = append(self.Float64Slice, v...) + return err case 18: - return proto.UnmarshalStringSlice(buffer, wt, &self.StrSlice) + v, err := wire.UnmarshalStringSlice(buffer, wt) + self.StrSlice = append(self.StrSlice, v...) + return err case 19: var elm MySubType - if err := proto.UnmarshalStruct(buffer, wt, &elm); err != nil { + if err := wire.UnmarshalStruct(buffer, wt, &elm); err != nil { return err } else { - self.StructSlice = append(self.StructSlice, elm) + self.StructSlice = append(self.StructSlice, &elm) return nil } case 20: - return proto.UnmarshalInt32(buffer, wt, (*int32)(&self.Enum)) + v, err := wire.UnmarshalInt32(buffer, wt) + self.Enum = MyEnum(v) + return err case 21: - return proto.UnmarshalInt32Slice(buffer, wt, (*[]int32)(unsafe.Pointer(&self.EnumSlice))) + v, err := wire.UnmarshalInt32Slice(buffer, wt) + for _, vv := range v { + self.EnumSlice = append(self.EnumSlice, MyEnum(vv)) + } + return err } - return proto.ErrUnknownField + return wire.ErrUnknownField } type LoginREQ struct { } -func (self *LoginREQ) String() string { return proto.CompactTextString(self) } +func (self *LoginREQ) String() string { return ppgo.CompactTextString(self) } func (self *LoginREQ) Size() (ret int) { return } -func (self *LoginREQ) Marshal(buffer *proto.Buffer) error { +func (self *LoginREQ) Marshal(buffer *wire.Buffer) error { return nil } -func (self *LoginREQ) Unmarshal(buffer *proto.Buffer, fieldIndex uint64, wt proto.WireType) error { +func (self *LoginREQ) Unmarshal(buffer *wire.Buffer, fieldIndex uint64, wt wire.WireType) error { switch fieldIndex { } - return proto.ErrUnknownField + return wire.ErrUnknownField } type LoginACK struct { } -func (self *LoginACK) String() string { return proto.CompactTextString(self) } +func (self *LoginACK) String() string { return ppgo.CompactTextString(self) } func (self *LoginACK) Size() (ret int) { return } -func (self *LoginACK) Marshal(buffer *proto.Buffer) error { +func (self *LoginACK) Marshal(buffer *wire.Buffer) error { return nil } -func (self *LoginACK) Unmarshal(buffer *proto.Buffer, fieldIndex uint64, wt proto.WireType) error { +func (self *LoginACK) Unmarshal(buffer *wire.Buffer, fieldIndex uint64, wt wire.WireType) error { switch fieldIndex { } - return proto.ErrUnknownField -} - -type S1 struct { - V int32 -} - -func (self *S1) String() string { return proto.CompactTextString(self) } - -func (self *S1) Size() (ret int) { - - ret += proto.SizeInt32(1, self.V) - - return -} - -func (self *S1) Marshal(buffer *proto.Buffer) error { - - proto.MarshalInt32(buffer, 1, self.V) - - return nil -} - -func (self *S1) Unmarshal(buffer *proto.Buffer, fieldIndex uint64, wt proto.WireType) error { - switch fieldIndex { - case 1: - return proto.UnmarshalInt32(buffer, wt, &self.V) - - } - - return proto.ErrUnknownField -} - -type S2 struct { - V int32 - S string -} - -func (self *S2) String() string { return proto.CompactTextString(self) } - -func (self *S2) Size() (ret int) { - - ret += proto.SizeInt32(1, self.V) - - ret += proto.SizeString(2, self.S) - - return -} - -func (self *S2) Marshal(buffer *proto.Buffer) error { - - proto.MarshalInt32(buffer, 1, self.V) - - proto.MarshalString(buffer, 2, self.S) - - return nil -} - -func (self *S2) Unmarshal(buffer *proto.Buffer, fieldIndex uint64, wt proto.WireType) error { - switch fieldIndex { - case 1: - return proto.UnmarshalInt32(buffer, wt, &self.V) - case 2: - return proto.UnmarshalString(buffer, wt, &self.S) - - } - - return proto.ErrUnknownField -} - -func init() { - + return wire.ErrUnknownField } diff --git a/tests/code_test.go b/tests/code_test.go index 9a59989..e79470b 100644 --- a/tests/code_test.go +++ b/tests/code_test.go @@ -1,7 +1,11 @@ package tests import ( - "github.com/davyxu/protoplus/proto" + "encoding/json" + "github.com/stretchr/testify/assert" + //_ "github.com/davyxu/cellnet/codec/protoplus" + "github.com/davyxu/protoplus/api/golang" + //"github.com/stretchr/testify/assert" "math" "reflect" "testing" @@ -9,19 +13,13 @@ import ( func TestOptional(t *testing.T) { bigData := makeMyType() - data, err := proto.Marshal(&bigData) - if err != nil { - t.Error(err) - t.FailNow() - } + data, err := ppgo.Marshal(&bigData) + assert.Equal(t, err, nil) var output MyTypeMini - err = proto.Unmarshal(data, &output) - if err != nil { - t.Error(err) - t.FailNow() - } + assert.Equal(t, ppgo.Unmarshal(data, &output), nil) - t.Logf("%+v", output) + //t.Logf("%+v", output) + //assert.Equal(t, bigData, output) } @@ -48,11 +46,11 @@ func makeMyType() (input MyType) { input.Enum = MyEnum_Two input.EnumSlice = []MyEnum{MyEnum_Two, MyEnum_One, MyEnum_Zero} - input.Struct = MySubType{ + input.Struct = &MySubType{ Str: "world", } - input.StructSlice = []MySubType{ + input.StructSlice = []*MySubType{ {Int32: 100}, {Str: "200"}, } @@ -60,36 +58,45 @@ func makeMyType() (input MyType) { return } -func verify(t *testing.T, raw interface{}) { - t.Logf("size: %d", proto.Size(raw)) +func verifyWire(t *testing.T, raw ppgo.Struct) { + data, err := ppgo.Marshal(raw) + assert.Equal(t, err, nil) - data, err := proto.Marshal(raw) - if err != nil { - t.Error(err) - t.FailNow() - } t.Log("proto+:", len(data), data) - newType := reflect.New(reflect.TypeOf(raw).Elem()).Interface() + newType := reflect.New(reflect.TypeOf(raw).Elem()).Interface().(ppgo.Struct) - err = proto.Unmarshal(data, newType) - if err != nil { - t.Error(err) - t.FailNow() - } + assert.Equal(t, ppgo.Unmarshal(data, newType), nil) - if !reflect.DeepEqual(raw, newType) { - t.FailNow() + assert.Equal(t, raw, newType) +} + +func verifyText(t *testing.T, raw interface{}) { + + tRaw := reflect.TypeOf(raw) + + if tRaw.Kind() != reflect.Ptr { + panic("expect ptr") } + + data := ppgo.CompactTextString(raw) + + t.Log(data) + + newType := reflect.New(tRaw.Elem()).Interface() + + assert.Equal(t, ppgo.UnmarshalText(data, newType), nil) + + assert.Equal(t, raw, newType) } func TestFull(t *testing.T) { input := makeMyType() - verify(t, &input) + verifyWire(t, &input) - t.Logf("%v", input.String()) + t.Logf("%v", ppgo.MarshalTextString(input)) } func TestIntSlice(t *testing.T) { @@ -97,8 +104,80 @@ func TestIntSlice(t *testing.T) { var input MyType input.Int32Slice = []int32{-1, 1, 2} - verify(t, &input) + verifyWire(t, &input) +} + +func TestSkipField(t *testing.T) { + + input := makeMyType() + + data, err := ppgo.Marshal(&input) + assert.Equal(t, err, nil) + + jsondata, _ := json.Marshal(&input) + + var mini MyTypeMini + assert.Equal(t, ppgo.Unmarshal(data, &mini), nil) + + var miniJson MyTypeMini + json.Unmarshal(jsondata, &miniJson) + assert.Equal(t, miniJson, mini) +} + +func TestPtrField(t *testing.T) { + + input := MyType{} + data, err := ppgo.Marshal(&input) + t.Log(data, err) + +} + +//func TestText(t *testing.T) { +// +// input := makeMyType() +// +// verifyText(t, &input) +//} + +func TestFloat(t *testing.T) { + + type MyFloat struct { + Value float64 + } + + input := MyFloat{math.MaxFloat64} + + verifyText(t, &input) +} + +func TestSlice(t *testing.T) { + + type DummyStruct struct { + Num int32 + } + + type MyFloat struct { + Value []int32 + Dummy DummyStruct + } + + input := MyFloat{ + []int32{-1, 1, 2}, + DummyStruct{5}, + } + + verifyText(t, &input) +} + +func TestEnum(t *testing.T) { + + type MyFloat struct { + Value []MyEnum + } + + input := MyFloat{Value: []MyEnum{MyEnum_One}} + verifyText(t, &input) } func TestCompatible(t *testing.T) { diff --git a/tests/filelist.proto b/tests/filelist.proto new file mode 100644 index 0000000..2533fb1 --- /dev/null +++ b/tests/filelist.proto @@ -0,0 +1,2 @@ +import "type.proto" +import "msg.proto" \ No newline at end of file diff --git a/tests/msg.proto b/tests/msg.proto new file mode 100644 index 0000000..7654256 --- /dev/null +++ b/tests/msg.proto @@ -0,0 +1,11 @@ + +[AutoMsgID MsgDir: "client -> game"] +struct LoginREQ { + +} + +[AutoMsgID] +struct LoginACK { + +} + diff --git a/tests/pb_gen.proto b/tests/pb_gen.proto index 4a8edbb..454e333 100644 --- a/tests/pb_gen.proto +++ b/tests/pb_gen.proto @@ -2,6 +2,8 @@ // DO NOT EDIT! syntax = "proto3"; +option go_package= "./;proto"; + package proto; @@ -14,8 +16,14 @@ enum MyEnum { message MyTypeMini { - string Str = 1; - bool Bool = 2; + bool Bool = 1; + int32 Int32 = 2; + uint32 UInt32 = 3; + int64 Int64 = 4; + uint64 UInt64 = 5; + float Float32 = 6; + double Float64 = 7; + string Str = 8; } @@ -74,14 +82,3 @@ message LoginREQ { message LoginACK { } - -message S1 { - int32 V = 1; -} - - -message S2 { - int32 V = 1; - string S = 2; -} - diff --git a/tests/route.json b/tests/route.json new file mode 100644 index 0000000..dd486c8 --- /dev/null +++ b/tests/route.json @@ -0,0 +1,9 @@ +{ + "Rule": [ + { + "MsgName": "proto.LoginREQ", + "MsgID": 225, + "SvcType": "game" + } + ] +} \ No newline at end of file diff --git a/tests/code.proto b/tests/type.proto similarity index 78% rename from tests/code.proto rename to tests/type.proto index f40eb0b..3f0ff54 100644 --- a/tests/code.proto +++ b/tests/type.proto @@ -1,7 +1,15 @@ struct MyTypeMini { - Str string - Bool bool + Bool bool + Int32 int32 + UInt32 uint32 + + Int64 int64 + UInt64 uint64 + + Float32 float32 + Float64 float64 + Str string } enum MyEnum @@ -11,7 +19,6 @@ enum MyEnum Two } -[AutoMsgID MsgDir: "client -> game"] struct MySubType { Bool bool @@ -48,7 +55,7 @@ struct MySubType EnumSlice []MyEnum } -[AutoMsgID ] + struct MyType { Bool bool @@ -86,27 +93,3 @@ struct MyType EnumSlice []MyEnum } - -struct LoginREQ { - -} - - -struct LoginACK { - -} - -service login -{ - LoginStd(LoginREQ) LoginACK - rpc Login -} - -struct S1 { - V int32 -} - -struct S2 { - V int32 - S string -} \ No newline at end of file