1 #region Copyright notice and license 2 // Protocol Buffers - Google's data interchange format 3 // Copyright 2008 Google Inc. All rights reserved. 4 // https://developers.google.com/protocol-buffers/ 5 // 6 // Redistribution and use in source and binary forms, with or without 7 // modification, are permitted provided that the following conditions are 8 // met: 9 // 10 // * Redistributions of source code must retain the above copyright 11 // notice, this list of conditions and the following disclaimer. 12 // * Redistributions in binary form must reproduce the above 13 // copyright notice, this list of conditions and the following disclaimer 14 // in the documentation and/or other materials provided with the 15 // distribution. 16 // * Neither the name of Google Inc. nor the names of its 17 // contributors may be used to endorse or promote products derived from 18 // this software without specific prior written permission. 19 // 20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 #endregion 32 33 using System; 34 using System.Buffers; 35 using System.Buffers.Binary; 36 using System.Collections.Generic; 37 using System.IO; 38 using System.Runtime.CompilerServices; 39 using System.Runtime.InteropServices; 40 using System.Security; 41 using System.Text; 42 using Google.Protobuf.Collections; 43 44 namespace Google.Protobuf 45 { 46 /// <summary> 47 /// An opaque struct that represents the current serialization state and is passed along 48 /// as the serialization proceeds. 49 /// All the public methods are intended to be invoked only by the generated code, 50 /// users should never invoke them directly. 51 /// </summary> 52 [SecuritySafeCritical] 53 public ref struct WriteContext 54 { 55 internal Span<byte> buffer; 56 internal WriterInternalState state; 57 58 [MethodImpl(MethodImplOptions.AggressiveInlining)] InitializeGoogle.Protobuf.WriteContext59 internal static void Initialize(ref Span<byte> buffer, ref WriterInternalState state, out WriteContext ctx) 60 { 61 ctx.buffer = buffer; 62 ctx.state = state; 63 } 64 65 /// <summary> 66 /// Creates a WriteContext instance from CodedOutputStream. 67 /// WARNING: internally this copies the CodedOutputStream's state, so after done with the WriteContext, 68 /// the CodedOutputStream's state needs to be updated. 69 /// </summary> 70 [MethodImpl(MethodImplOptions.AggressiveInlining)] InitializeGoogle.Protobuf.WriteContext71 internal static void Initialize(CodedOutputStream output, out WriteContext ctx) 72 { 73 ctx.buffer = new Span<byte>(output.InternalBuffer); 74 // ideally we would use a reference to the original state, but that doesn't seem possible 75 // so we just copy the struct that holds the state. We will need to later store the state back 76 // into CodedOutputStream if we want to keep it usable. 77 ctx.state = output.InternalState; 78 } 79 80 [MethodImpl(MethodImplOptions.AggressiveInlining)] InitializeGoogle.Protobuf.WriteContext81 internal static void Initialize(IBufferWriter<byte> output, out WriteContext ctx) 82 { 83 ctx.buffer = default; 84 ctx.state = default; 85 WriteBufferHelper.Initialize(output, out ctx.state.writeBufferHelper, out ctx.buffer); 86 ctx.state.limit = ctx.buffer.Length; 87 ctx.state.position = 0; 88 } 89 90 [MethodImpl(MethodImplOptions.AggressiveInlining)] InitializeGoogle.Protobuf.WriteContext91 internal static void Initialize(ref Span<byte> buffer, out WriteContext ctx) 92 { 93 ctx.buffer = buffer; 94 ctx.state = default; 95 ctx.state.limit = ctx.buffer.Length; 96 ctx.state.position = 0; 97 WriteBufferHelper.InitializeNonRefreshable(out ctx.state.writeBufferHelper); 98 } 99 100 /// <summary> 101 /// Writes a double field value, without a tag. 102 /// </summary> 103 /// <param name="value">The value to write</param> WriteDoubleGoogle.Protobuf.WriteContext104 public void WriteDouble(double value) 105 { 106 WritingPrimitives.WriteDouble(ref buffer, ref state, value); 107 } 108 109 /// <summary> 110 /// Writes a float field value, without a tag. 111 /// </summary> 112 /// <param name="value">The value to write</param> WriteFloatGoogle.Protobuf.WriteContext113 public void WriteFloat(float value) 114 { 115 WritingPrimitives.WriteFloat(ref buffer, ref state, value); 116 } 117 118 /// <summary> 119 /// Writes a uint64 field value, without a tag. 120 /// </summary> 121 /// <param name="value">The value to write</param> WriteUInt64Google.Protobuf.WriteContext122 public void WriteUInt64(ulong value) 123 { 124 WritingPrimitives.WriteUInt64(ref buffer, ref state, value); 125 } 126 127 /// <summary> 128 /// Writes an int64 field value, without a tag. 129 /// </summary> 130 /// <param name="value">The value to write</param> WriteInt64Google.Protobuf.WriteContext131 public void WriteInt64(long value) 132 { 133 WritingPrimitives.WriteInt64(ref buffer, ref state, value); 134 } 135 136 /// <summary> 137 /// Writes an int32 field value, without a tag. 138 /// </summary> 139 /// <param name="value">The value to write</param> WriteInt32Google.Protobuf.WriteContext140 public void WriteInt32(int value) 141 { 142 WritingPrimitives.WriteInt32(ref buffer, ref state, value); 143 } 144 145 /// <summary> 146 /// Writes a fixed64 field value, without a tag. 147 /// </summary> 148 /// <param name="value">The value to write</param> WriteFixed64Google.Protobuf.WriteContext149 public void WriteFixed64(ulong value) 150 { 151 WritingPrimitives.WriteFixed64(ref buffer, ref state, value); 152 } 153 154 /// <summary> 155 /// Writes a fixed32 field value, without a tag. 156 /// </summary> 157 /// <param name="value">The value to write</param> WriteFixed32Google.Protobuf.WriteContext158 public void WriteFixed32(uint value) 159 { 160 WritingPrimitives.WriteFixed32(ref buffer, ref state, value); 161 } 162 163 /// <summary> 164 /// Writes a bool field value, without a tag. 165 /// </summary> 166 /// <param name="value">The value to write</param> WriteBoolGoogle.Protobuf.WriteContext167 public void WriteBool(bool value) 168 { 169 WritingPrimitives.WriteBool(ref buffer, ref state, value); 170 } 171 172 /// <summary> 173 /// Writes a string field value, without a tag. 174 /// The data is length-prefixed. 175 /// </summary> 176 /// <param name="value">The value to write</param> WriteStringGoogle.Protobuf.WriteContext177 public void WriteString(string value) 178 { 179 WritingPrimitives.WriteString(ref buffer, ref state, value); 180 } 181 182 /// <summary> 183 /// Writes a message, without a tag. 184 /// The data is length-prefixed. 185 /// </summary> 186 /// <param name="value">The value to write</param> WriteMessageGoogle.Protobuf.WriteContext187 public void WriteMessage(IMessage value) 188 { 189 WritingPrimitivesMessages.WriteMessage(ref this, value); 190 } 191 192 /// <summary> 193 /// Writes a group, without a tag, to the stream. 194 /// </summary> 195 /// <param name="value">The value to write</param> WriteGroupGoogle.Protobuf.WriteContext196 public void WriteGroup(IMessage value) 197 { 198 WritingPrimitivesMessages.WriteGroup(ref this, value); 199 } 200 201 /// <summary> 202 /// Write a byte string, without a tag, to the stream. 203 /// The data is length-prefixed. 204 /// </summary> 205 /// <param name="value">The value to write</param> WriteBytesGoogle.Protobuf.WriteContext206 public void WriteBytes(ByteString value) 207 { 208 WritingPrimitives.WriteBytes(ref buffer, ref state, value); 209 } 210 211 /// <summary> 212 /// Writes a uint32 value, without a tag. 213 /// </summary> 214 /// <param name="value">The value to write</param> WriteUInt32Google.Protobuf.WriteContext215 public void WriteUInt32(uint value) 216 { 217 WritingPrimitives.WriteUInt32(ref buffer, ref state, value); 218 } 219 220 /// <summary> 221 /// Writes an enum value, without a tag. 222 /// </summary> 223 /// <param name="value">The value to write</param> WriteEnumGoogle.Protobuf.WriteContext224 public void WriteEnum(int value) 225 { 226 WritingPrimitives.WriteEnum(ref buffer, ref state, value); 227 } 228 229 /// <summary> 230 /// Writes an sfixed32 value, without a tag. 231 /// </summary> 232 /// <param name="value">The value to write.</param> WriteSFixed32Google.Protobuf.WriteContext233 public void WriteSFixed32(int value) 234 { 235 WritingPrimitives.WriteSFixed32(ref buffer, ref state, value); 236 } 237 238 /// <summary> 239 /// Writes an sfixed64 value, without a tag. 240 /// </summary> 241 /// <param name="value">The value to write</param> WriteSFixed64Google.Protobuf.WriteContext242 public void WriteSFixed64(long value) 243 { 244 WritingPrimitives.WriteSFixed64(ref buffer, ref state, value); 245 } 246 247 /// <summary> 248 /// Writes an sint32 value, without a tag. 249 /// </summary> 250 /// <param name="value">The value to write</param> WriteSInt32Google.Protobuf.WriteContext251 public void WriteSInt32(int value) 252 { 253 WritingPrimitives.WriteSInt32(ref buffer, ref state, value); 254 } 255 256 /// <summary> 257 /// Writes an sint64 value, without a tag. 258 /// </summary> 259 /// <param name="value">The value to write</param> WriteSInt64Google.Protobuf.WriteContext260 public void WriteSInt64(long value) 261 { 262 WritingPrimitives.WriteSInt64(ref buffer, ref state, value); 263 } 264 265 /// <summary> 266 /// Writes a length (in bytes) for length-delimited data. 267 /// </summary> 268 /// <remarks> 269 /// This method simply writes a rawint, but exists for clarity in calling code. 270 /// </remarks> 271 /// <param name="length">Length value, in bytes.</param> WriteLengthGoogle.Protobuf.WriteContext272 public void WriteLength(int length) 273 { 274 WritingPrimitives.WriteLength(ref buffer, ref state, length); 275 } 276 277 /// <summary> 278 /// Encodes and writes a tag. 279 /// </summary> 280 /// <param name="fieldNumber">The number of the field to write the tag for</param> 281 /// <param name="type">The wire format type of the tag to write</param> WriteTagGoogle.Protobuf.WriteContext282 public void WriteTag(int fieldNumber, WireFormat.WireType type) 283 { 284 WritingPrimitives.WriteTag(ref buffer, ref state, fieldNumber, type); 285 } 286 287 /// <summary> 288 /// Writes an already-encoded tag. 289 /// </summary> 290 /// <param name="tag">The encoded tag</param> WriteTagGoogle.Protobuf.WriteContext291 public void WriteTag(uint tag) 292 { 293 WritingPrimitives.WriteTag(ref buffer, ref state, tag); 294 } 295 296 /// <summary> 297 /// Writes the given single-byte tag. 298 /// </summary> 299 /// <param name="b1">The encoded tag</param> WriteRawTagGoogle.Protobuf.WriteContext300 public void WriteRawTag(byte b1) 301 { 302 WritingPrimitives.WriteRawTag(ref buffer, ref state, b1); 303 } 304 305 /// <summary> 306 /// Writes the given two-byte tag. 307 /// </summary> 308 /// <param name="b1">The first byte of the encoded tag</param> 309 /// <param name="b2">The second byte of the encoded tag</param> WriteRawTagGoogle.Protobuf.WriteContext310 public void WriteRawTag(byte b1, byte b2) 311 { 312 WritingPrimitives.WriteRawTag(ref buffer, ref state, b1, b2); 313 } 314 315 /// <summary> 316 /// Writes the given three-byte tag. 317 /// </summary> 318 /// <param name="b1">The first byte of the encoded tag</param> 319 /// <param name="b2">The second byte of the encoded tag</param> 320 /// <param name="b3">The third byte of the encoded tag</param> WriteRawTagGoogle.Protobuf.WriteContext321 public void WriteRawTag(byte b1, byte b2, byte b3) 322 { 323 WritingPrimitives.WriteRawTag(ref buffer, ref state, b1, b2, b3); 324 } 325 326 /// <summary> 327 /// Writes the given four-byte tag. 328 /// </summary> 329 /// <param name="b1">The first byte of the encoded tag</param> 330 /// <param name="b2">The second byte of the encoded tag</param> 331 /// <param name="b3">The third byte of the encoded tag</param> 332 /// <param name="b4">The fourth byte of the encoded tag</param> WriteRawTagGoogle.Protobuf.WriteContext333 public void WriteRawTag(byte b1, byte b2, byte b3, byte b4) 334 { 335 WritingPrimitives.WriteRawTag(ref buffer, ref state, b1, b2, b3, b4); 336 } 337 338 /// <summary> 339 /// Writes the given five-byte tag. 340 /// </summary> 341 /// <param name="b1">The first byte of the encoded tag</param> 342 /// <param name="b2">The second byte of the encoded tag</param> 343 /// <param name="b3">The third byte of the encoded tag</param> 344 /// <param name="b4">The fourth byte of the encoded tag</param> 345 /// <param name="b5">The fifth byte of the encoded tag</param> WriteRawTagGoogle.Protobuf.WriteContext346 public void WriteRawTag(byte b1, byte b2, byte b3, byte b4, byte b5) 347 { 348 WritingPrimitives.WriteRawTag(ref buffer, ref state, b1, b2, b3, b4, b5); 349 } 350 FlushGoogle.Protobuf.WriteContext351 internal void Flush() 352 { 353 WriteBufferHelper.Flush(ref buffer, ref state); 354 } 355 CheckNoSpaceLeftGoogle.Protobuf.WriteContext356 internal void CheckNoSpaceLeft() 357 { 358 WriteBufferHelper.CheckNoSpaceLeft(ref state); 359 } 360 CopyStateToGoogle.Protobuf.WriteContext361 internal void CopyStateTo(CodedOutputStream output) 362 { 363 output.InternalState = state; 364 } 365 LoadStateFromGoogle.Protobuf.WriteContext366 internal void LoadStateFrom(CodedOutputStream output) 367 { 368 state = output.InternalState; 369 } 370 } 371 }