public ProtoPrepare(Options options) { if (options.PreserveNames) ConvertToCamelCase = false; this.options = options; }
public static void GenerateClass(ProtoMessage m, CodeWriter cw, Options options) { //Do not generate class code for external classes if (m.OptionExternal) { cw.Comment("Written elsewhere"); cw.Comment(m.OptionAccess + " " + m.OptionType + " " + m.CsType + " {}"); return; } //Default class cw.Summary(m.Comments); cw.Bracket(m.OptionAccess + " partial " + m.OptionType + " " + m.CsType); GenerateEnums(m, cw); GenerateProperties(m, cw); //if(options.GenerateToString... // ... if (m.OptionPreserveUnknown) { cw.Summary("Values for unknown fields."); cw.WriteLine("public List<global::SilentOrbit.ProtocolBuffers.KeyValue> PreservedFields;"); cw.WriteLine(); } if (m.OptionTriggers) { cw.Comment("protected virtual void BeforeSerialize() {}"); cw.Comment("protected virtual void AfterDeserialize() {}"); cw.WriteLine(); } foreach (ProtoMessage sub in m.Messages.Values) { GenerateClass(sub, cw, options); cw.WriteLine(); } cw.EndBracket(); return; }
public static void Build(Options options) { var parser = new FileParser(); var collection = parser.Import(options.InputProto); Console.WriteLine(collection); //Interpret and reformat try { var pp = new ProtoPrepare(options); pp.Prepare(collection); } catch (ProtoFormatException pfe) { Console.WriteLine(); Console.WriteLine(pfe.SourcePath.Path + "(" + pfe.SourcePath.Line + "," + pfe.SourcePath.Column + "): error CS001: " + pfe.Message); throw; } //Generate code ProtoCode.Save(collection, options); Console.WriteLine("Saved: " + options.OutputPath); }
public MessageSerializer(CodeWriter cw, Options options) { this.cw = cw; this.options = options; this.fieldSerializer = new FieldSerializer(cw, options); }
public MessageCode(CodeWriter cw, Options options) { this.cw = cw; this.options = options; }
/// <summary> /// Generates code for writing one field /// </summary> public void FieldWriter(ProtoMessage m, Field f, CodeWriter cw, Options options) { if (f.Rule == FieldRule.Repeated) { if (f.OptionPacked == true) { //Repeated packed cw.IfBracket("instance." + f.CsName + " != null"); KeyWriter("stream", f.ID, Wire.LengthDelimited, cw); if (f.ProtoType.WireSize < 0) { //Un-optimized, unknown size cw.WriteLine("msField.SetLength(0);"); if (f.IsUsingBinaryWriter) cw.WriteLine("BinaryWriter bw" + f.ID + " = new BinaryWriter(ms" + f.ID + ");"); cw.ForeachBracket("var i" + f.ID + " in instance." + f.CsName); FieldWriterType(f, "msField", "bw" + f.ID, "i" + f.ID, cw); cw.EndBracket(); BytesWriter(f, "stream", cw); } else { //Optimized with known size //No memorystream buffering, write size first at once //For constant size messages we can skip serializing to the MemoryStream cw.WriteLine(ProtocolParser.Base + ".WriteUInt32(stream, " + f.ProtoType.WireSize + "u * (uint)instance." + f.CsName + ".Count);"); cw.ForeachBracket("var i" + f.ID + " in instance." + f.CsName); FieldWriterType(f, "stream", "bw", "i" + f.ID, cw); cw.EndBracket(); } cw.EndBracket(); } else { //Repeated not packet cw.IfBracket("instance." + f.CsName + " != null"); cw.ForeachBracket("var i" + f.ID + " in instance." + f.CsName); KeyWriter("stream", f.ID, f.ProtoType.WireType, cw); FieldWriterType(f, "stream", "bw", "i" + f.ID, cw); cw.EndBracket(); cw.EndBracket(); } return; } else if (f.Rule == FieldRule.Optional) { bool skip = options.SkipSerializeDefault && f.OptionDefault != null; if (options.Nullable || f.ProtoType is ProtoMessage || f.ProtoType.ProtoName == ProtoBuiltin.String || f.ProtoType.ProtoName == ProtoBuiltin.Bytes) { if (f.ProtoType.Nullable || options.Nullable) //Struct always exist, not optional cw.IfBracket("instance." + f.CsName + " != null"); KeyWriter("stream", f.ID, f.ProtoType.WireType, cw); var needValue = !f.ProtoType.Nullable && options.Nullable; FieldWriterType(f, "stream", "bw", "instance." + f.CsName + (needValue ? ".Value" : ""), cw); if (f.ProtoType.Nullable || options.Nullable) //Struct always exist, not optional cw.EndBracket(); return; } if (f.ProtoType is ProtoEnum) { if (skip) cw.IfBracket("instance." + f.CsName + " != " + f.FormatDefaultForTypeAssignment()); KeyWriter("stream", f.ID, f.ProtoType.WireType, cw); FieldWriterType(f, "stream", "bw", "instance." + f.CsName, cw); if (skip) cw.EndBracket(); return; } if (skip) //Skip writing value if default cw.IfBracket("instance." + f.CsName + " != " + f.FormatDefaultForTypeAssignment()); KeyWriter("stream", f.ID, f.ProtoType.WireType, cw); FieldWriterType(f, "stream", "bw", "instance." + f.CsName, cw); if (skip) cw.EndBracket(); return; } else if (f.Rule == FieldRule.Required) { if (f.ProtoType is ProtoMessage && f.ProtoType.OptionType != "struct" || f.ProtoType.ProtoName == ProtoBuiltin.String || f.ProtoType.ProtoName == ProtoBuiltin.Bytes) { cw.WriteLine("if (instance." + f.CsName + " == null)"); cw.WriteIndent("throw new global::SilentOrbit.ProtocolBuffers.ProtocolBufferException(\"" + f.CsName + " is required by the proto specification.\");"); } KeyWriter("stream", f.ID, f.ProtoType.WireType, cw); FieldWriterType(f, "stream", "bw", "instance." + f.CsName, cw); return; } throw new NotImplementedException("Unknown rule: " + f.Rule); }
public FieldSerializer(CodeWriter cw, Options options) { this.cw = cw; this.options = options; }
/// <summary> /// Generate code for reading and writing protocol buffer messages /// </summary> public static void Save(ProtoCollection file, Options options) { string csPath = options.OutputPath; CodeWriter.DefaultIndentPrefix = options.UseTabs ? "\t" : " "; string ext = Path.GetExtension(csPath); string prefix = csPath.Substring(0, csPath.Length - ext.Length); string csDir = Path.GetDirectoryName(csPath); if (Directory.Exists(csDir) == false) Directory.CreateDirectory(csDir); //Basic structures using (var cw = new CodeWriter(csPath)) { cw.Comment(@"Classes and structures being serialized"); cw.WriteLine(); cw.Comment(@"Generated by ProtocolBuffer - a pure c# code generation implementation of protocol buffers Report bugs to: https://silentorbit.com/protobuf/"); cw.WriteLine(); cw.Comment(@"DO NOT EDIT This file will be overwritten when CodeGenerator is run. To make custom modifications, edit the .proto file and add //:external before the message line then write the code and the changes in a separate file."); cw.WriteLine("using System;"); cw.WriteLine("using System.Collections.Generic;"); cw.WriteLine(); string ns = null; //avoid writing namespace between classes if they belong to the same foreach (ProtoMessage m in file.Messages.Values) { if (ns != m.CsNamespace) { if (ns != null) //First time cw.EndBracket(); cw.Bracket("namespace " + m.CsNamespace); ns = m.CsNamespace; } MessageCode.GenerateClass(m, cw, options); cw.WriteLine(); } foreach (ProtoEnum e in file.Enums.Values) { if (ns != e.CsNamespace) { if (ns != null) //First time cw.EndBracket(); cw.Bracket("namespace " + e.CsNamespace); ns = e.CsNamespace; } MessageCode.GenerateEnum(e, cw); cw.WriteLine(); } cw.EndBracket(); } //.Serializer.cs //Code for Reading/Writing using (var cw = new CodeWriter(prefix + ".Serializer" + ext)) { cw.Comment(@"This is the backend code for reading and writing"); cw.WriteLine(); cw.Comment(@"Generated by ProtocolBuffer - a pure c# code generation implementation of protocol buffers Report bugs to: https://silentorbit.com/protobuf/"); cw.WriteLine(); cw.Comment(@"DO NOT EDIT This file will be overwritten when CodeGenerator is run."); cw.WriteLine("using System;"); cw.WriteLine("using System.IO;"); cw.WriteLine("using System.Text;"); cw.WriteLine("using System.Collections.Generic;"); cw.WriteLine(); string ns = null; //avoid writing namespace between classes if they belong to the same foreach (ProtoMessage m in file.Messages.Values) { if (ns != m.CsNamespace) { if (ns != null) //First time cw.EndBracket(); cw.Bracket("namespace " + m.CsNamespace); ns = m.CsNamespace; } MessageSerializer.GenerateClassSerializer(m, cw); } cw.EndBracket(); } string libPath = Path.Combine(Path.GetDirectoryName(csPath), "ProtocolParser.cs"); using (TextWriter codeWriter = new StreamWriter(libPath, false, Encoding.UTF8)) { codeWriter.NewLine = "\r\n"; ReadCode(codeWriter, "ProtocolParser", true); ReadCode(codeWriter, "ProtocolParserFixed", false); ReadCode(codeWriter, "ProtocolParserKey", false); ReadCode(codeWriter, "ProtocolParserVarInt", false); } }
public void FieldSizeWriter(ProtoMessage m, Field f, CodeWriter cw, Options options) { if (f.Rule == FieldRule.Repeated) { if (f.OptionPacked == true) { Console.WriteLine("not support"); } else { //Repeated not packet cw.IfBracket("this." + f.CsName + " != null"); cw.ForeachBracket("var i" + f.ID + " in this." + f.CsName); //KeyWriter("stream", f.ID, f.ProtoType.WireType, cw); FieldSizeWriterType(f, "i" + f.ID, cw); cw.EndBracket(); cw.EndBracket(); } return; } else if (f.Rule == FieldRule.Optional) { if (options.Nullable || f.ProtoType is ProtoMessage || f.ProtoType.ProtoName == ProtoBuiltin.String || f.ProtoType.ProtoName == ProtoBuiltin.Bytes) { if (f.ProtoType.Nullable || options.Nullable) //Struct always exist, not optional cw.IfBracket("this." + f.CsName + " != null"); FieldSizeWriterType(f, "this." + f.CsName, cw); if (f.ProtoType.Nullable || options.Nullable) //Struct always exist, not optional cw.EndBracket(); return; } if (f.ProtoType is ProtoEnum) { if (f.OptionDefault != null) cw.IfBracket("this." + f.CsName + " != " + f.ProtoType.CsType + "." + f.OptionDefault); FieldSizeWriterType(f, "this." + f.CsName, cw); if (f.OptionDefault != null) cw.EndBracket(); return; } KeyWriter("stream", f.ID, f.ProtoType.WireType, cw); FieldWriterType(f, "stream", "bw", "instance." + f.CsName, cw); return; } else if (f.Rule == FieldRule.Required) { if (f.ProtoType is ProtoMessage && f.ProtoType.OptionType != "struct" || f.ProtoType.ProtoName == ProtoBuiltin.String || f.ProtoType.ProtoName == ProtoBuiltin.Bytes) { cw.WriteLine("if (this." + f.CsName + " == null)"); cw.WriteIndent("throw new global::SilentOrbit.ProtocolBuffers.ProtocolBufferException(\"" + f.CsName + " is required by the proto specification.\");"); } cw.WriteLine(); FieldSizeWriterType(f, "this." + f.CsName, cw); return; } throw new NotImplementedException("Unknown rule: " + f.Rule); }