diff --git a/compiler/src/Brickred.Exchange.Compiler/CSharpCodeGenerator.cs b/compiler/src/Brickred.Exchange.Compiler/CSharpCodeGenerator.cs index c5b1441..a182dcc 100644 --- a/compiler/src/Brickred.Exchange.Compiler/CSharpCodeGenerator.cs +++ b/compiler/src/Brickred.Exchange.Compiler/CSharpCodeGenerator.cs @@ -285,12 +285,18 @@ private void GetUsingStatementsDecl( ProtocolDescriptor.StructDef structDef = protoDef.Structs[i]; + if (structDef.Fields.Count > 0) { + useSystemCollectionsGeneric = true; + } + for (int j = 0; j < structDef.Fields.Count; ++j) { ProtocolDescriptor.StructDef.FieldDef fieldDef = structDef.Fields[j]; - if (fieldDef.Type == FieldType.List) { - useSystemCollectionsGeneric = true; + if (fieldDef.Type == FieldType.String || + fieldDef.ListType == FieldType.String) { + // for BitConverter + useSystem = true; } } } @@ -403,6 +409,7 @@ private void GetStructDecl( string cloneFuncDecl; string encodeToStreamFuncDecl; string decodeFromStreamFuncDecl; + string dumpFuncDecl; string optionalFuncDecl; indent += " "; @@ -420,6 +427,8 @@ private void GetStructDecl( structDef, indent, out encodeToStreamFuncDecl); GetStructDeclDecodeFromStreamFunc( structDef, indent, out decodeFromStreamFuncDecl); + GetStructDeclDumpFunc( + structDef, indent, out dumpFuncDecl); GetStructDeclOptionalFunc( structDef, indent, out optionalFuncDecl); @@ -439,6 +448,8 @@ private void GetStructDecl( sb.Append(encodeToStreamFuncDecl); sb.Append(this.newLineStr); sb.Append(decodeFromStreamFuncDecl); + sb.Append(this.newLineStr); + sb.Append(dumpFuncDecl); if (optionalFuncDecl != "") { sb.Append(this.newLineStr); sb.Append(optionalFuncDecl); @@ -1294,6 +1305,185 @@ private void GetStructDeclDecodeFromStreamFuncReadStatement( output = sb.ToString(); } + private void GetStructDeclDumpFunc( + ProtocolDescriptor.StructDef structDef, + string indent, out string output) + { + StringBuilder sb = new StringBuilder(); + + string start = string.Format( + "{0}public override string Dump(){1}" + + "{0}{{{1}", + indent, this.newLineStr); + string end = string.Format( + "{0}}}{1}", + indent, this.newLineStr); + + sb.Append(start); + + indent += " "; + + if (structDef.Fields.Count == 0) { + sb.AppendFormat( + "{0}return \"\";{1}", + indent, this.newLineStr); + } else { + sb.AppendFormat( + "{0}List sb = new List();{1}" + + "{1}", + indent, this.newLineStr); + + for (int i = 0; i < structDef.Fields.Count; ++i) { + string writeStatement; + GetStructDeclDumpFuncWriteStatement( + structDef.Fields[i], indent, out writeStatement); + sb.Append(writeStatement); + } + + sb.AppendFormat( + "{1}" + + "{0}return string.Join(\" \", sb);{1}", + indent, this.newLineStr); + } + + sb.Append(end); + + output = sb.ToString(); + } + + private void GetStructDeclDumpFuncWriteStatement( + ProtocolDescriptor.StructDef.FieldDef fieldDef, + string indent, out string output) + { + StringBuilder sb = new StringBuilder(); + + string optionalCheckStart = ""; + string optionalCheckEnd = ""; + + if (fieldDef.IsOptional) { + optionalCheckStart = string.Format( + "{0}if (has_{1}()) {{{2}", + indent, fieldDef.Name, this.newLineStr); + optionalCheckEnd = string.Format( + "{0}}}{1}", + indent, this.newLineStr); + indent += " "; + } + + sb.Append(optionalCheckStart); + + FieldType checkType; + if (fieldDef.Type == FieldType.List) { + checkType = fieldDef.ListType; + } else { + checkType = fieldDef.Type; + } + bool isList = (fieldDef.Type == FieldType.List); + + if (checkType == FieldType.I8 || + checkType == FieldType.U8 || + checkType == FieldType.I16 || + checkType == FieldType.U16 || + checkType == FieldType.I32 || + checkType == FieldType.U32 || + checkType == FieldType.I64 || + checkType == FieldType.U64 || + checkType == FieldType.I16V || + checkType == FieldType.U16V || + checkType == FieldType.I32V || + checkType == FieldType.U32V || + checkType == FieldType.I64V || + checkType == FieldType.U64V) { + if (isList) { + sb.AppendFormat( + "{0}for (int i = 0; i < this.{1}.Count; ++i) {{{2}" + + "{0} sb.Add(string.Format(" + + "\"{1}: {{0}}\", this.{1}[i]));{2}" + + "{0}}}{2}", + indent, fieldDef.Name, this.newLineStr); + } else { + sb.AppendFormat( + "{0}sb.Add(string.Format(\"{1}: {{0}}\", this.{1}));{2}", + indent, fieldDef.Name, this.newLineStr); + } + } else if (checkType == FieldType.Bool) { + if (isList) { + sb.AppendFormat( + "{0}for (int i = 0; i < this.{1}.Count; ++i) {{{2}" + + "{0} sb.Add(string.Format(" + + "\"{1}: {{0}}\", this.{1}[i] ? 1 : 0));{2}" + + "{0}}}{2}", + indent, fieldDef.Name, this.newLineStr); + } else { + sb.AppendFormat( + "{0}sb.Add(string.Format(\"{1}: {{0}}\", " + + "this.{1} ? 1 : 0));{2}", + indent, fieldDef.Name, this.newLineStr); + } + } else if (checkType == FieldType.Enum) { + if (isList) { + sb.AppendFormat( + "{0}for (int i = 0; i < this.{1}.Count; ++i) {{{2}" + + "{0} sb.Add(string.Format(" + + "\"{1}: {{0}}\", (int)this.{1}[i]));{2}" + + "{0}}}{2}", + indent, fieldDef.Name, this.newLineStr); + } else { + sb.AppendFormat( + "{0}sb.Add(string.Format(\"{1}: {{0}}\", " + + "(int)this.{1}));{2}", + indent, fieldDef.Name, this.newLineStr); + } + } else if (checkType == FieldType.String) { + if (isList) { + sb.AppendFormat( + "{0}for (int i = 0; i < this.{1}.Count; ++i) {{{2}" + + "{0} sb.Add(string.Format(" + + "\"{1}: \\\"{{0}}\\\"\", this.{1}[i]));{2}" + + "{0}}}{2}", + indent, fieldDef.Name, this.newLineStr); + } else { + sb.AppendFormat( + "{0}sb.Add(string.Format(\"{1}: \\\"{{0}}\\\"\", " + + "this.{1}));{2}", + indent, fieldDef.Name, this.newLineStr); + } + } else if (checkType == FieldType.Bytes) { + if (isList) { + sb.AppendFormat( + "{0}for (int i = 0; i < this.{1}.Count; ++i) {{{2}" + + "{0} sb.Add(string.Format(" + + "\"{1}: \\\"{{0}}\\\"\", " + + "BitConverter.ToString(this.{1}[i])));{2}" + + "{0}}}{2}", + indent, fieldDef.Name, this.newLineStr); + } else { + sb.AppendFormat( + "{0}sb.Add(string.Format(\"{1}: \\\"{{0}}\\\"\", " + + "BitConverter.ToString(this.{1})));{2}", + indent, fieldDef.Name, this.newLineStr); + } + } else if (checkType == FieldType.Struct) { + if (isList) { + sb.AppendFormat( + "{0}for (int i = 0; i < this.{1}.Count; ++i) {{{2}" + + "{0} sb.Add(string.Format(" + + "\"{1} {{{{ {{0}} }}}}\", this.{1}[i].Dump()));{2}" + + "{0}}}{2}", + indent, fieldDef.Name, this.newLineStr); + } else { + sb.AppendFormat( + "{0}sb.Add(string.Format(\"{1} {{{{ {{0}} }}}}\", " + + "this.{1}.Dump()));{2}", + indent, fieldDef.Name, this.newLineStr); + } + } + + sb.Append(optionalCheckEnd); + + output = sb.ToString(); + } + private void GetStructDeclOptionalFunc( ProtocolDescriptor.StructDef structDef, string indent, out string output) diff --git a/compiler/src/Brickred.Exchange.Compiler/CppCodeGenerator.cs b/compiler/src/Brickred.Exchange.Compiler/CppCodeGenerator.cs index 9b9ad74..05b3e4a 100644 --- a/compiler/src/Brickred.Exchange.Compiler/CppCodeGenerator.cs +++ b/compiler/src/Brickred.Exchange.Compiler/CppCodeGenerator.cs @@ -626,7 +626,8 @@ private void GetHeaderFileStructDecl( " virtual {0} *clone() const {{" + " return new {0}(*this); }}{1}" + " virtual int encode(char *buffer, size_t size) const;{1}" + - " virtual int decode(const char *buffer, size_t size);{1}", + " virtual int decode(const char *buffer, size_t size);{1}" + + " virtual std::string dump() const;{1}", structDef.Name, this.newLineStr); string end = string.Format( "}};{0}", this.newLineStr); @@ -811,6 +812,7 @@ private void GetSourceFileIncludeFileDecl( { bool useCStringH = false; bool useAlgorithmH = false; + bool useSStreamH = false; bool useBrickredMacroInternalH = false; { @@ -831,6 +833,7 @@ private void GetSourceFileIncludeFileDecl( } if (structDef.Fields.Count > 0) { + useSStreamH = true; useBrickredMacroInternalH = true; } @@ -859,6 +862,10 @@ private void GetSourceFileIncludeFileDecl( sb.AppendFormat("#include {0}", this.newLineStr); } + if (useSStreamH) { + sb.AppendFormat("#include {0}", + this.newLineStr); + } systemHeaderDecl = sb.ToString(); } @@ -919,6 +926,7 @@ private void GetSourceFileStructImpl( string swapFuncImpl; string encodeFuncImpl; string decodeFuncImpl; + string dumpFuncImpl; GetSourceFileStructImplConstructor( structDef, out constructorImpl); @@ -930,6 +938,8 @@ private void GetSourceFileStructImpl( structDef, out encodeFuncImpl); GetSourceFileStructImplDecodeFunc( structDef, out decodeFuncImpl); + GetSourceFileStructImplDumpFunc( + structDef, out dumpFuncImpl); sb.Append(constructorImpl); sb.Append(this.newLineStr); @@ -940,6 +950,8 @@ private void GetSourceFileStructImpl( sb.Append(encodeFuncImpl); sb.Append(this.newLineStr); sb.Append(decodeFuncImpl); + sb.Append(this.newLineStr); + sb.Append(dumpFuncImpl); output = sb.ToString(); } @@ -1540,6 +1552,167 @@ private void GetSourceFileEnumMapImpl( output = sb.ToString(); } + private void GetSourceFileStructImplDumpFunc( + ProtocolDescriptor.StructDef structDef, out string output) + { + StringBuilder sb = new StringBuilder(); + + string start = string.Format( + "std::string {0}::dump() const{1}" + + "{{{1}", + structDef.Name, this.newLineStr); + string end = string.Format( + "}}{0}", this.newLineStr); + string indent = " "; + + sb.Append(start); + + if (structDef.Fields.Count == 0) { + sb.AppendFormat( + "{0}return \"\";{1}", + indent, this.newLineStr); + } else { + sb.AppendFormat( + "{0}std::stringstream ss;{1}" + + "{1}", + indent, this.newLineStr); + + for (int i = 0; i < structDef.Fields.Count; ++i) { + string writeStatement; + GetSourceFileStructImplDumpFuncWriteStatement( + structDef.Fields[i], out writeStatement); + sb.Append(writeStatement); + } + + sb.AppendFormat( + "{1}" + + "{0}std::string s = ss.str();{1}" + + "{0}if (s.empty() == false) {{{1}" + + "{0} s.erase(s.end() - 1);{1}" + + "{0}}}{1}" + + "{1}" + + "{0}return s;{1}", + indent, this.newLineStr); + } + + sb.Append(end); + + output = sb.ToString(); + } + + private void GetSourceFileStructImplDumpFuncWriteStatement( + ProtocolDescriptor.StructDef.FieldDef fieldDef, out string output) + { + StringBuilder sb = new StringBuilder(); + + string indent = " "; + string optionalCheckStart = ""; + string optionalCheckEnd = ""; + + if (fieldDef.IsOptional) { + optionalCheckStart = string.Format( + "{0}if (has_{1}()) {{{2}", + indent, fieldDef.Name, this.newLineStr); + optionalCheckEnd = string.Format( + "{0}}}{1}", + indent, this.newLineStr); + indent += " "; + } + + sb.Append(optionalCheckStart); + + FieldType checkType; + if (fieldDef.Type == FieldType.List) { + checkType = fieldDef.ListType; + } else { + checkType = fieldDef.Type; + } + bool isList = (fieldDef.Type == FieldType.List); + + if (checkType == FieldType.I8 || + checkType == FieldType.U8) { + if (isList) { + sb.AppendFormat( + "{0}for (size_t i = 0; i < this->{1}.size(); ++i) {{{2}" + + "{0} ss << \"{1}: \" << (int)this->{1}[i] << \" \";{2}" + + "{0}}}{2}", + indent, fieldDef.Name, this.newLineStr); + } else { + sb.AppendFormat( + "{0}ss << \"{1}: \" << (int)this->{1} << \" \";{2}", + indent, fieldDef.Name, this.newLineStr); + } + } else if (checkType == FieldType.I16 || + checkType == FieldType.U16 || + checkType == FieldType.I32 || + checkType == FieldType.U32 || + checkType == FieldType.I64 || + checkType == FieldType.U64 || + checkType == FieldType.I16V || + checkType == FieldType.U16V || + checkType == FieldType.I32V || + checkType == FieldType.U32V || + checkType == FieldType.I64V || + checkType == FieldType.U64V || + checkType == FieldType.Bool || + checkType == FieldType.Enum) { + if (isList) { + sb.AppendFormat( + "{0}for (size_t i = 0; i < this->{1}.size(); ++i) {{{2}" + + "{0} ss << \"{1}: \" << this->{1}[i] << \" \";{2}" + + "{0}}}{2}", + indent, fieldDef.Name, this.newLineStr); + } else { + sb.AppendFormat( + "{0}ss << \"{1}: \" << this->{1} << \" \";{2}", + indent, fieldDef.Name, this.newLineStr); + } + } else if (checkType == FieldType.String) { + if (isList) { + sb.AppendFormat( + "{0}for (size_t i = 0; i < this->{1}.size(); ++i) {{{2}" + + "{0} ss << \"{1}: \\\"\" << this->{1}[i] << \"\\\" \";{2}" + + "{0}}}{2}", + indent, fieldDef.Name, this.newLineStr); + } else { + sb.AppendFormat( + "{0}ss << \"{1}: \\\"\" << this->{1} << \"\\\" \";{2}", + indent, fieldDef.Name, this.newLineStr); + } + } else if (checkType == FieldType.Bytes) { + if (isList) { + sb.AppendFormat( + "{0}for (size_t i = 0; i < this->{1}.size(); ++i) {{{2}" + + "{0} ss << \"{1}: \\\"\" << " + + "dumpBytes(this->{1}[i]) << \"\\\" \";{2}" + + "{0}}}{2}", + indent, fieldDef.Name, this.newLineStr); + } else { + sb.AppendFormat( + "{0}ss << \"{1}: \\\"\" << " + + "dumpBytes(this->{1}) << \"\\\" \";{2}", + indent, fieldDef.Name, this.newLineStr); + } + } else if (checkType == FieldType.Struct) { + if (isList) { + sb.AppendFormat( + "{0}for (size_t i = 0; i < this->{1}.size(); ++i) {{{2}" + + "{0} ss << \"{1} {{ \" << " + + "this->{1}[i].dump() << \" }} \";{2}" + + "{0}}}{2}", + indent, fieldDef.Name, this.newLineStr); + } else { + sb.AppendFormat( + "{0}ss << \"{1} {{ \" << this->{1}.dump() << \" }} \";{2}", + indent, fieldDef.Name, this.newLineStr); + } + } + + sb.Append(optionalCheckEnd); + + output = sb.ToString(); + } + private void GetSourceFileEnumMapImplCreateFunc( ProtocolDescriptor.EnumMapDef enumMapDef, out string output) { diff --git a/cpp/src/brickred/exchange/base_struct.cc b/cpp/src/brickred/exchange/base_struct.cc index dd4deda..9f48586 100644 --- a/cpp/src/brickred/exchange/base_struct.cc +++ b/cpp/src/brickred/exchange/base_struct.cc @@ -1,5 +1,8 @@ #include +#include +#include + namespace brickred { namespace exchange { @@ -11,5 +14,21 @@ BaseStruct::~BaseStruct() { } +std::string BaseStruct::dumpBytes(const std::string &val) +{ + if (val.empty()) { + return ""; + } + + std::vector ret(val.size() * 3); + + for (size_t i = 0; i < val.size(); ++i) { + ::snprintf(&ret[i * 3], 4, "%02hhX-", val[i]); + } + ret.back() = '\0'; + + return std::string(&ret[0]); +} + } // namespace exchange } // namespace brickred diff --git a/cpp/src/brickred/exchange/base_struct.h b/cpp/src/brickred/exchange/base_struct.h index 191ef5f..a1e1438 100644 --- a/cpp/src/brickred/exchange/base_struct.h +++ b/cpp/src/brickred/exchange/base_struct.h @@ -2,6 +2,7 @@ #define BRICKRED_EXCHANGE_BASE_STRUCT_H #include +#include namespace brickred { namespace exchange { @@ -16,6 +17,10 @@ class BaseStruct { virtual int encode(char *buffer, size_t size) const = 0; virtual int decode(const char *buffer, size_t size) = 0; + virtual std::string dump() const = 0; + +protected: + static std::string dumpBytes(const std::string &val); }; } // namespace exchange diff --git a/csharp/src/Brickred.Exchange/BaseStruct.cs b/csharp/src/Brickred.Exchange/BaseStruct.cs index 4f6810c..00e3fc7 100644 --- a/csharp/src/Brickred.Exchange/BaseStruct.cs +++ b/csharp/src/Brickred.Exchange/BaseStruct.cs @@ -1,7 +1,5 @@ -using ArgumentException = System.ArgumentException; -using DecoderFallbackException = System.Text.DecoderFallbackException; -using EncoderFallbackException = System.Text.EncoderFallbackException; -using Exception = System.Exception; +using System; +using System.Text; namespace Brickred.Exchange { @@ -12,6 +10,7 @@ public abstract class BaseStruct protected abstract BaseStruct CloneInternal(); public abstract void EncodeToStream(CodecOutputStream s); public abstract void DecodeFromStream(CodecInputStream s); + public abstract string Dump(); public BaseStruct Clone() { diff --git a/csharp/src/Brickred.Exchange/CodecException.cs b/csharp/src/Brickred.Exchange/CodecException.cs index 82b5e53..57f219d 100644 --- a/csharp/src/Brickred.Exchange/CodecException.cs +++ b/csharp/src/Brickred.Exchange/CodecException.cs @@ -1,4 +1,4 @@ -using IOException = System.IO.IOException; +using System.IO; namespace Brickred.Exchange { diff --git a/csharp/src/Brickred.Exchange/CodecInputStream.cs b/csharp/src/Brickred.Exchange/CodecInputStream.cs index 9b1e44b..95c7bbc 100644 --- a/csharp/src/Brickred.Exchange/CodecInputStream.cs +++ b/csharp/src/Brickred.Exchange/CodecInputStream.cs @@ -1,6 +1,5 @@ -using Buffer = System.Buffer; -using Encoding = System.Text.Encoding; -using Math = System.Math; +using System; +using System.Text; namespace Brickred.Exchange { diff --git a/csharp/src/Brickred.Exchange/CodecOutputStream.cs b/csharp/src/Brickred.Exchange/CodecOutputStream.cs index 2474019..aec13aa 100644 --- a/csharp/src/Brickred.Exchange/CodecOutputStream.cs +++ b/csharp/src/Brickred.Exchange/CodecOutputStream.cs @@ -1,7 +1,5 @@ -using Buffer = System.Buffer; -using Encoding = System.Text.Encoding; -using Math = System.Math; -using SCG = System.Collections.Generic; +using System; +using System.Text; namespace Brickred.Exchange { diff --git a/example/main.cs b/example/main.cs index e8d2446..28ab512 100644 --- a/example/main.cs +++ b/example/main.cs @@ -1,8 +1,7 @@ using Brickred.Exchange; using Protocol.Client; -using Console = System.Console; -using Encoding = System.Text.Encoding; -using StringBuilder = System.Text.StringBuilder; +using System; +using System.Text; public class App {