예제 #1
0
        public void WriteContext_WritesWithFlushes()
        {
            TestAllTypes message = SampleMessages.CreateFullTestAllTypes();

            MemoryStream      expectedOutput = new MemoryStream();
            CodedOutputStream output         = new CodedOutputStream(expectedOutput);

            output.WriteMessage(message);
            output.Flush();
            byte[] expectedBytes1 = expectedOutput.ToArray();

            output.WriteMessage(message);
            output.Flush();
            byte[] expectedBytes2 = expectedOutput.ToArray();

            var bufferWriter = new TestArrayBufferWriter <byte>();

            WriteContext.Initialize(bufferWriter, out WriteContext ctx);
            ctx.WriteMessage(message);
            ctx.Flush();
            Assert.AreEqual(expectedBytes1, bufferWriter.WrittenSpan.ToArray());

            ctx.WriteMessage(message);
            ctx.Flush();
            Assert.AreEqual(expectedBytes2, bufferWriter.WrittenSpan.ToArray());
        }
예제 #2
0
        public void LegacyGeneratedCodeThrowsWithIBufferWriter()
        {
            // if serialization started using IBufferWriter and we don't have a CodedOutputStream
            // instance at hand, we cannot fall back to the legacy WriteTo(CodedOutputStream)
            // method and serializatin will fail. As a consequence, one can only use serialization
            // to IBufferWriter if all the messages in the parsing tree have their generated
            // code up to date.
            var message = new ParseContextEnabledMessageB
            {
                A = new LegacyGeneratedCodeMessageA
                {
                    Bb = new ParseContextEnabledMessageB {
                        OptionalInt32 = 12345
                    }
                },
                OptionalInt32 = 6789
            };
            var exception = Assert.Throws <InvalidProtocolBufferException>(() =>
            {
                WriteContext.Initialize(new TestArrayBufferWriter <byte>(), out WriteContext writeCtx);
                ((IBufferMessage)message).InternalWriteTo(ref writeCtx);
            });

            Assert.AreEqual($"Message {typeof(LegacyGeneratedCodeMessageA).Name} doesn't provide the generated method that enables WriteContext-based serialization. You might need to regenerate the generated protobuf code.", exception.Message);
        }
예제 #3
0
        /// <summary>
        /// Parses the given bytes using WriteRawLittleEndian64() and checks
        /// that the result matches the given value.
        /// </summary>
        private static void AssertWriteLittleEndian64(byte[] data, ulong value)
        {
            {
                var rawOutput = new MemoryStream();
                var output    = new CodedOutputStream(rawOutput);
                output.WriteRawLittleEndian64(value);
                output.Flush();
                Assert.AreEqual(data, rawOutput.ToArray());

                var bufferWriter = new TestArrayBufferWriter <byte>();
                WriteContext.Initialize(bufferWriter, out WriteContext ctx);
                ctx.WriteFixed64(value);
                ctx.Flush();
                Assert.AreEqual(data, bufferWriter.WrittenSpan.ToArray());
            }

            // Try different block sizes.
            for (int blockSize = 1; blockSize <= 16; blockSize *= 2)
            {
                var rawOutput = new MemoryStream();
                var output    = new CodedOutputStream(rawOutput, blockSize);
                output.WriteRawLittleEndian64(value);
                output.Flush();
                Assert.AreEqual(data, rawOutput.ToArray());

                var bufferWriter = new TestArrayBufferWriter <byte> {
                    MaxGrowBy = blockSize
                };
                WriteContext.Initialize(bufferWriter, out WriteContext ctx);
                ctx.WriteFixed64(value);
                ctx.Flush();
                Assert.AreEqual(data, bufferWriter.WrittenSpan.ToArray());
            }
        }
예제 #4
0
 public void WriteTo(ref WriteContext ctx)
 {
     foreach (KeyValuePair <int, UnknownField> entry in fields)
     {
         entry.Value.WriteTo(entry.Key, ref ctx);
     }
 }
예제 #5
0
 internal static void Initialize(ref Span <byte> buffer, out WriteContext ctx)
 {
     ctx.buffer         = buffer;
     ctx.state          = default;
     ctx.state.limit    = ctx.buffer.Length;
     ctx.state.position = 0;
     WriteBufferHelper.InitializeNonRefreshable(out ctx.state.writeBufferHelper);
 }
예제 #6
0
 internal static void Initialize(IBufferWriter <byte> output, out WriteContext ctx)
 {
     ctx.buffer = default;
     ctx.state  = default;
     WriteBufferHelper.Initialize(output, out ctx.state.writeBufferHelper, out ctx.buffer);
     ctx.state.limit    = ctx.buffer.Length;
     ctx.state.position = 0;
 }
예제 #7
0
 internal static void Initialize(CodedOutputStream output, out WriteContext ctx)
 {
     ctx.buffer = new Span <byte>(output.InternalBuffer);
     // ideally we would use a reference to the original state, but that doesn't seem possible
     // so we just copy the struct that holds the state. We will need to later store the state back
     // into CodedOutputStream if we want to keep it usable.
     ctx.state = output.InternalState;
 }
예제 #8
0
        public static void WriteTo(this IMessage message, IBufferWriter <byte> output)
        {
            ProtoPreconditions.CheckNotNull(message, nameof(message));
            ProtoPreconditions.CheckNotNull(output, nameof(output));

            WriteContext.Initialize(output, out WriteContext ctx);
            WritingPrimitivesMessages.WriteRawMessage(ref ctx, message);
            ctx.Flush();
        }
예제 #9
0
 public void WriteTo(ref WriteContext ctx)
 {
     ctx.WriteTag(codec.Tag);
     codec.ValueWriter(ref ctx, field);
     if (codec.EndTag != 0)
     {
         ctx.WriteTag(codec.EndTag);
     }
 }
예제 #10
0
 /// <summary>
 /// Serializes the set and writes it to <paramref name="output"/>.
 /// </summary>
 public void WriteTo(CodedOutputStream output)
 {
     WriteContext.Initialize(output, out WriteContext ctx);
     try
     {
         WriteTo(ref ctx);
     }
     finally
     {
         ctx.CopyStateTo(output);
     }
 }
예제 #11
0
 /// <summary>
 /// Serializes the field, including the field number, and writes it to
 /// <paramref name="output"/>
 /// </summary>
 /// <param name="fieldNumber">The unknown field number.</param>
 /// <param name="output">The write context to write to.</param>
 internal void WriteTo(int fieldNumber, ref WriteContext output)
 {
     if (varintList != null)
     {
         foreach (ulong value in varintList)
         {
             output.WriteTag(fieldNumber, WireFormat.WireType.Varint);
             output.WriteUInt64(value);
         }
     }
     if (fixed32List != null)
     {
         foreach (uint value in fixed32List)
         {
             output.WriteTag(fieldNumber, WireFormat.WireType.Fixed32);
             output.WriteFixed32(value);
         }
     }
     if (fixed64List != null)
     {
         foreach (ulong value in fixed64List)
         {
             output.WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
             output.WriteFixed64(value);
         }
     }
     if (lengthDelimitedList != null)
     {
         foreach (ByteString value in lengthDelimitedList)
         {
             output.WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
             output.WriteBytes(value);
         }
     }
     if (groupList != null)
     {
         foreach (UnknownFieldSet value in groupList)
         {
             output.WriteTag(fieldNumber, WireFormat.WireType.StartGroup);
             value.WriteTo(ref output);
             output.WriteTag(fieldNumber, WireFormat.WireType.EndGroup);
         }
     }
 }
예제 #12
0
 void pb.IBufferMessage.InternalWriteTo(ref pb.WriteContext output)
 {
     if (ClientId.Length != 0)
     {
         output.WriteRawTag(10);
         output.WriteString(ClientId);
     }
     if (MessageId.Length != 0)
     {
         output.WriteRawTag(18);
         output.WriteString(MessageId);
     }
     if (Type != MessageType.Undefined)
     {
         output.WriteRawTag(24);
         output.WriteEnum((int)Type);
     }
     if (time_ != null)
     {
         output.WriteRawTag(34);
         output.WriteMessage(Time);
     }
     if (Status != MessageStatus.Undefined)
     {
         output.WriteRawTag(40);
         output.WriteEnum((int)Status);
     }
     if (Payload.Length != 0)
     {
         output.WriteRawTag(50);
         output.WriteBytes(Payload);
     }
     if (Response != ResponseType.Undefined)
     {
         output.WriteRawTag(56);
         output.WriteEnum((int)Response);
     }
     if (_unknownFields != null)
     {
         _unknownFields.WriteTo(ref output);
     }
 }
예제 #13
0
            public void TestDefaultValue()
            {
                // WriteTagAndValue ignores default values
                var stream = new MemoryStream();
                CodedOutputStream codedOutput;

#if !NET35
                codedOutput = new CodedOutputStream(stream);
                codec.WriteTagAndValue(codedOutput, codec.DefaultValue);
                codedOutput.Flush();
                Assert.AreEqual(0, stream.Position);
                Assert.AreEqual(0, codec.CalculateSizeWithTag(codec.DefaultValue));
                if (typeof(T).GetTypeInfo().IsValueType)
                {
                    Assert.AreEqual(default(T), codec.DefaultValue);
                }
#endif

                // The plain ValueWriter/ValueReader delegates don't.
                if (codec.DefaultValue != null) // This part isn't appropriate for message types.
                {
                    codedOutput = new CodedOutputStream(stream);
                    WriteContext.Initialize(codedOutput, out WriteContext ctx);
                    try
                    {
                        // only write the value using the codec
                        codec.ValueWriter(ref ctx, codec.DefaultValue);
                    }
                    finally
                    {
                        ctx.CopyStateTo(codedOutput);
                    }

                    codedOutput.Flush();
                    Assert.AreNotEqual(0, stream.Position);
                    Assert.AreEqual(stream.Position, codec.ValueSizeCalculator(codec.DefaultValue));
                    stream.Position = 0;
                    var codedInput = new CodedInputStream(stream);
                    Assert.AreEqual(codec.DefaultValue, codec.Read(codedInput));
                }
            }
예제 #14
0
        public static void WriteRawMessage(ref WriteContext ctx, IMessage message)
        {
            if (message is IBufferMessage bufferMessage)
            {
                bufferMessage.InternalWriteTo(ref ctx);
            }
            else
            {
                // If we reached here, it means we've ran into a nested message with older generated code
                // which doesn't provide the InternalWriteTo method that takes a WriteContext.
                // With a slight performance overhead, we can still serialize this message just fine,
                // but we need to find the original CodedOutputStream instance that initiated this
                // serialization process and make sure its internal state is up to date.
                // Note that this performance overhead is not very high (basically copying contents of a struct)
                // and it will only be incurred in case the application mixes older and newer generated code.
                // Regenerating the code from .proto files will remove this overhead because it will
                // generate the InternalWriteTo method we need.

                if (ctx.state.CodedOutputStream == null)
                {
                    // This can only happen when the serialization started without providing a CodedOutputStream instance
                    // (e.g. WriteContext was created directly from a IBufferWriter).
                    // That also means that one of the new parsing APIs was used at the top level
                    // and in such case it is reasonable to require that all the nested message provide
                    // up-to-date generated code with WriteContext support (and fail otherwise).
                    throw new InvalidProtocolBufferException($"Message {message.GetType().Name} doesn't provide the generated method that enables WriteContext-based serialization. You might need to regenerate the generated protobuf code.");
                }

                ctx.CopyStateTo(ctx.state.CodedOutputStream);
                try
                {
                    // fallback parse using the CodedOutputStream that started current serialization tree
                    message.WriteTo(ctx.state.CodedOutputStream);
                }
                finally
                {
                    ctx.LoadStateFrom(ctx.state.CodedOutputStream);
                }
            }
        }
예제 #15
0
            public void TestRoundTripRaw()
            {
                var stream      = new MemoryStream();
                var codedOutput = new CodedOutputStream(stream);

                WriteContext.Initialize(codedOutput, out WriteContext ctx);
                try
                {
                    // only write the value using the codec
                    codec.ValueWriter(ref ctx, sampleValue);
                }
                finally
                {
                    ctx.CopyStateTo(codedOutput);
                }
                codedOutput.Flush();
                stream.Position = 0;
                var codedInput = new CodedInputStream(stream);

                Assert.AreEqual(sampleValue, codec.Read(codedInput));
                Assert.IsTrue(codedInput.IsAtEnd);
            }
예제 #16
0
 public static void WriteMessage(ref WriteContext ctx, IMessage value)
 {
     WritingPrimitives.WriteLength(ref ctx.buffer, ref ctx.state, value.CalculateSize());
     WriteRawMessage(ref ctx, value);
 }
예제 #17
0
 internal static void Initialize(ref Span <byte> buffer, ref WriterInternalState state, out WriteContext ctx)
 {
     ctx.buffer = buffer;
     ctx.state  = state;
 }
예제 #18
0
 public void WriteTo(ref WriteContext ctx)
 {
     field.WriteTo(ref ctx, codec);
 }
예제 #19
0
 internal static void Write <T>(ref WriteContext ctx, T value, FieldCodec <T> codec)
 {
     ctx.WriteLength(codec.CalculateSizeWithTag(value));
     codec.WriteTagAndValue(ref ctx, value);
 }
예제 #20
0
        /// <summary>
        /// Writes the given value using WriteRawVarint32() and WriteRawVarint64() and
        /// checks that the result matches the given bytes
        /// </summary>
        private static void AssertWriteVarint(byte[] data, ulong value)
        {
            // Only do 32-bit write if the value fits in 32 bits.
            if ((value >> 32) == 0)
            {
                // CodedOutputStream
                MemoryStream      rawOutput = new MemoryStream();
                CodedOutputStream output    = new CodedOutputStream(rawOutput);
                output.WriteRawVarint32((uint)value);
                output.Flush();
                Assert.AreEqual(data, rawOutput.ToArray());

                // IBufferWriter
                var bufferWriter = new TestArrayBufferWriter <byte>();
                WriteContext.Initialize(bufferWriter, out WriteContext ctx);
                ctx.WriteUInt32((uint)value);
                ctx.Flush();
                Assert.AreEqual(data, bufferWriter.WrittenSpan.ToArray());

                // Also try computing size.
                Assert.AreEqual(data.Length, CodedOutputStream.ComputeRawVarint32Size((uint)value));
            }

            {
                // CodedOutputStream
                MemoryStream      rawOutput = new MemoryStream();
                CodedOutputStream output    = new CodedOutputStream(rawOutput);
                output.WriteRawVarint64(value);
                output.Flush();
                Assert.AreEqual(data, rawOutput.ToArray());

                // IBufferWriter
                var bufferWriter = new TestArrayBufferWriter <byte>();
                WriteContext.Initialize(bufferWriter, out WriteContext ctx);
                ctx.WriteUInt64(value);
                ctx.Flush();
                Assert.AreEqual(data, bufferWriter.WrittenSpan.ToArray());

                // Also try computing size.
                Assert.AreEqual(data.Length, CodedOutputStream.ComputeRawVarint64Size(value));
            }

            // Try different buffer sizes.
            for (int bufferSize = 1; bufferSize <= 16; bufferSize *= 2)
            {
                // Only do 32-bit write if the value fits in 32 bits.
                if ((value >> 32) == 0)
                {
                    MemoryStream      rawOutput = new MemoryStream();
                    CodedOutputStream output    = new CodedOutputStream(rawOutput, bufferSize);
                    output.WriteRawVarint32((uint)value);
                    output.Flush();
                    Assert.AreEqual(data, rawOutput.ToArray());

                    var bufferWriter = new TestArrayBufferWriter <byte> {
                        MaxGrowBy = bufferSize
                    };
                    WriteContext.Initialize(bufferWriter, out WriteContext ctx);
                    ctx.WriteUInt32((uint)value);
                    ctx.Flush();
                    Assert.AreEqual(data, bufferWriter.WrittenSpan.ToArray());
                }

                {
                    MemoryStream      rawOutput = new MemoryStream();
                    CodedOutputStream output    = new CodedOutputStream(rawOutput, bufferSize);
                    output.WriteRawVarint64(value);
                    output.Flush();
                    Assert.AreEqual(data, rawOutput.ToArray());

                    var bufferWriter = new TestArrayBufferWriter <byte> {
                        MaxGrowBy = bufferSize
                    };
                    WriteContext.Initialize(bufferWriter, out WriteContext ctx);
                    ctx.WriteUInt64(value);
                    ctx.Flush();
                    Assert.AreEqual(data, bufferWriter.WrittenSpan.ToArray());
                }
            }
        }
예제 #21
0
 public static void WriteGroup(ref WriteContext ctx, IMessage value)
 {
     WriteRawMessage(ref ctx, value);
 }