1 #region Copyright notice and license 2 // Protocol Buffers - Google's data interchange format 3 // Copyright 2008 Google Inc. All rights reserved. 4 // 5 // Use of this source code is governed by a BSD-style 6 // license that can be found in the LICENSE file or at 7 // https://developers.google.com/open-source/licenses/bsd 8 #endregion 9 10 using System; 11 using System.Buffers; 12 using System.Runtime.CompilerServices; 13 using System.Security; 14 15 namespace Google.Protobuf 16 { 17 /// <summary> 18 /// An opaque struct that represents the current serialization state and is passed along 19 /// as the serialization proceeds. 20 /// All the public methods are intended to be invoked only by the generated code, 21 /// users should never invoke them directly. 22 /// </summary> 23 [SecuritySafeCritical] 24 public ref struct WriteContext 25 { 26 internal Span<byte> buffer; 27 internal WriterInternalState state; 28 29 [MethodImpl(MethodImplOptions.AggressiveInlining)] InitializeGoogle.Protobuf.WriteContext30 internal static void Initialize(ref Span<byte> buffer, ref WriterInternalState state, out WriteContext ctx) 31 { 32 ctx.buffer = buffer; 33 ctx.state = state; 34 } 35 36 /// <summary> 37 /// Creates a WriteContext instance from CodedOutputStream. 38 /// WARNING: internally this copies the CodedOutputStream's state, so after done with the WriteContext, 39 /// the CodedOutputStream's state needs to be updated. 40 /// </summary> 41 [MethodImpl(MethodImplOptions.AggressiveInlining)] InitializeGoogle.Protobuf.WriteContext42 internal static void Initialize(CodedOutputStream output, out WriteContext ctx) 43 { 44 ctx.buffer = new Span<byte>(output.InternalBuffer); 45 // ideally we would use a reference to the original state, but that doesn't seem possible 46 // so we just copy the struct that holds the state. We will need to later store the state back 47 // into CodedOutputStream if we want to keep it usable. 48 ctx.state = output.InternalState; 49 } 50 51 [MethodImpl(MethodImplOptions.AggressiveInlining)] InitializeGoogle.Protobuf.WriteContext52 internal static void Initialize(IBufferWriter<byte> output, out WriteContext ctx) 53 { 54 ctx.buffer = default; 55 ctx.state = default; 56 WriteBufferHelper.Initialize(output, out ctx.state.writeBufferHelper, out ctx.buffer); 57 ctx.state.limit = ctx.buffer.Length; 58 ctx.state.position = 0; 59 } 60 61 [MethodImpl(MethodImplOptions.AggressiveInlining)] InitializeGoogle.Protobuf.WriteContext62 internal static void Initialize(ref Span<byte> buffer, out WriteContext ctx) 63 { 64 ctx.buffer = buffer; 65 ctx.state = default; 66 ctx.state.limit = ctx.buffer.Length; 67 ctx.state.position = 0; 68 WriteBufferHelper.InitializeNonRefreshable(out ctx.state.writeBufferHelper); 69 } 70 71 /// <summary> 72 /// Writes a double field value, without a tag. 73 /// </summary> 74 /// <param name="value">The value to write</param> WriteDoubleGoogle.Protobuf.WriteContext75 public void WriteDouble(double value) => WritingPrimitives.WriteDouble(ref buffer, ref state, value); 76 77 /// <summary> 78 /// Writes a float field value, without a tag. 79 /// </summary> 80 /// <param name="value">The value to write</param> WriteFloatGoogle.Protobuf.WriteContext81 public void WriteFloat(float value) => WritingPrimitives.WriteFloat(ref buffer, ref state, value); 82 83 /// <summary> 84 /// Writes a uint64 field value, without a tag. 85 /// </summary> 86 /// <param name="value">The value to write</param> WriteUInt64Google.Protobuf.WriteContext87 public void WriteUInt64(ulong value) => WritingPrimitives.WriteUInt64(ref buffer, ref state, value); 88 89 /// <summary> 90 /// Writes an int64 field value, without a tag. 91 /// </summary> 92 /// <param name="value">The value to write</param> WriteInt64Google.Protobuf.WriteContext93 public void WriteInt64(long value) => WritingPrimitives.WriteInt64(ref buffer, ref state, value); 94 95 /// <summary> 96 /// Writes an int32 field value, without a tag. 97 /// </summary> 98 /// <param name="value">The value to write</param> WriteInt32Google.Protobuf.WriteContext99 public void WriteInt32(int value) => WritingPrimitives.WriteInt32(ref buffer, ref state, value); 100 101 /// <summary> 102 /// Writes a fixed64 field value, without a tag. 103 /// </summary> 104 /// <param name="value">The value to write</param> WriteFixed64Google.Protobuf.WriteContext105 public void WriteFixed64(ulong value) => WritingPrimitives.WriteFixed64(ref buffer, ref state, value); 106 107 /// <summary> 108 /// Writes a fixed32 field value, without a tag. 109 /// </summary> 110 /// <param name="value">The value to write</param> WriteFixed32Google.Protobuf.WriteContext111 public void WriteFixed32(uint value) => WritingPrimitives.WriteFixed32(ref buffer, ref state, value); 112 113 /// <summary> 114 /// Writes a bool field value, without a tag. 115 /// </summary> 116 /// <param name="value">The value to write</param> 117 public void WriteBool(bool value) => WritingPrimitives.WriteBool(ref buffer, ref state, value); 118 119 /// <summary> 120 /// Writes a string field value, without a tag. 121 /// The data is length-prefixed. 122 /// </summary> 123 /// <param name="value">The value to write</param> WriteStringGoogle.Protobuf.WriteContext124 public void WriteString(string value) => WritingPrimitives.WriteString(ref buffer, ref state, value); 125 126 /// <summary> 127 /// Writes a message, without a tag. 128 /// The data is length-prefixed. 129 /// </summary> 130 /// <param name="value">The value to write</param> 131 public void WriteMessage(IMessage value) => WritingPrimitivesMessages.WriteMessage(ref this, value); 132 133 /// <summary> 134 /// Writes a group, without a tag, to the stream. 135 /// </summary> 136 /// <param name="value">The value to write</param> 137 public void WriteGroup(IMessage value) => WritingPrimitivesMessages.WriteGroup(ref this, value); 138 139 /// <summary> 140 /// Write a byte string, without a tag, to the stream. 141 /// The data is length-prefixed. 142 /// </summary> 143 /// <param name="value">The value to write</param> 144 public void WriteBytes(ByteString value) => WritingPrimitives.WriteBytes(ref buffer, ref state, value); 145 146 /// <summary> 147 /// Writes a uint32 value, without a tag. 148 /// </summary> 149 /// <param name="value">The value to write</param> WriteUInt32Google.Protobuf.WriteContext150 public void WriteUInt32(uint value) => WritingPrimitives.WriteUInt32(ref buffer, ref state, value); 151 152 /// <summary> 153 /// Writes an enum value, without a tag. 154 /// </summary> 155 /// <param name="value">The value to write</param> WriteEnumGoogle.Protobuf.WriteContext156 public void WriteEnum(int value) => WritingPrimitives.WriteEnum(ref buffer, ref state, value); 157 158 /// <summary> 159 /// Writes an sfixed32 value, without a tag. 160 /// </summary> 161 /// <param name="value">The value to write.</param> WriteSFixed32Google.Protobuf.WriteContext162 public void WriteSFixed32(int value) => WritingPrimitives.WriteSFixed32(ref buffer, ref state, value); 163 164 /// <summary> 165 /// Writes an sfixed64 value, without a tag. 166 /// </summary> 167 /// <param name="value">The value to write</param> WriteSFixed64Google.Protobuf.WriteContext168 public void WriteSFixed64(long value) => WritingPrimitives.WriteSFixed64(ref buffer, ref state, value); 169 170 /// <summary> 171 /// Writes an sint32 value, without a tag. 172 /// </summary> 173 /// <param name="value">The value to write</param> WriteSInt32Google.Protobuf.WriteContext174 public void WriteSInt32(int value) => WritingPrimitives.WriteSInt32(ref buffer, ref state, value); 175 176 /// <summary> 177 /// Writes an sint64 value, without a tag. 178 /// </summary> 179 /// <param name="value">The value to write</param> WriteSInt64Google.Protobuf.WriteContext180 public void WriteSInt64(long value) => WritingPrimitives.WriteSInt64(ref buffer, ref state, value); 181 182 /// <summary> 183 /// Writes a length (in bytes) for length-delimited data. 184 /// </summary> 185 /// <remarks> 186 /// This method simply writes a rawint, but exists for clarity in calling code. 187 /// </remarks> 188 /// <param name="length">Length value, in bytes.</param> WriteLengthGoogle.Protobuf.WriteContext189 public void WriteLength(int length) => WritingPrimitives.WriteLength(ref buffer, ref state, length); 190 191 /// <summary> 192 /// Encodes and writes a tag. 193 /// </summary> 194 /// <param name="fieldNumber">The number of the field to write the tag for</param> 195 /// <param name="type">The wire format type of the tag to write</param> WriteTagGoogle.Protobuf.WriteContext196 public void WriteTag(int fieldNumber, WireFormat.WireType type) => WritingPrimitives.WriteTag(ref buffer, ref state, fieldNumber, type); 197 198 /// <summary> 199 /// Writes an already-encoded tag. 200 /// </summary> 201 /// <param name="tag">The encoded tag</param> WriteTagGoogle.Protobuf.WriteContext202 public void WriteTag(uint tag) => WritingPrimitives.WriteTag(ref buffer, ref state, tag); 203 204 /// <summary> 205 /// Writes the given single-byte tag. 206 /// </summary> 207 /// <param name="b1">The encoded tag</param> 208 public void WriteRawTag(byte b1) => WritingPrimitives.WriteRawTag(ref buffer, ref state, b1); 209 210 /// <summary> 211 /// Writes the given two-byte tag. 212 /// </summary> 213 /// <param name="b1">The first byte of the encoded tag</param> 214 /// <param name="b2">The second byte of the encoded tag</param> WriteRawTagGoogle.Protobuf.WriteContext215 public void WriteRawTag(byte b1, byte b2) => WritingPrimitives.WriteRawTag(ref buffer, ref state, b1, b2); 216 217 /// <summary> 218 /// Writes the given three-byte tag. 219 /// </summary> 220 /// <param name="b1">The first byte of the encoded tag</param> 221 /// <param name="b2">The second byte of the encoded tag</param> 222 /// <param name="b3">The third byte of the encoded tag</param> WriteRawTagGoogle.Protobuf.WriteContext223 public void WriteRawTag(byte b1, byte b2, byte b3) => WritingPrimitives.WriteRawTag(ref buffer, ref state, b1, b2, b3); 224 225 /// <summary> 226 /// Writes the given four-byte tag. 227 /// </summary> 228 /// <param name="b1">The first byte of the encoded tag</param> 229 /// <param name="b2">The second byte of the encoded tag</param> 230 /// <param name="b3">The third byte of the encoded tag</param> 231 /// <param name="b4">The fourth byte of the encoded tag</param> WriteRawTagGoogle.Protobuf.WriteContext232 public void WriteRawTag(byte b1, byte b2, byte b3, byte b4) => WritingPrimitives.WriteRawTag(ref buffer, ref state, b1, b2, b3, b4); 233 234 /// <summary> 235 /// Writes the given five-byte tag. 236 /// </summary> 237 /// <param name="b1">The first byte of the encoded tag</param> 238 /// <param name="b2">The second byte of the encoded tag</param> 239 /// <param name="b3">The third byte of the encoded tag</param> 240 /// <param name="b4">The fourth byte of the encoded tag</param> 241 /// <param name="b5">The fifth byte of the encoded tag</param> WriteRawTagGoogle.Protobuf.WriteContext242 public void WriteRawTag(byte b1, byte b2, byte b3, byte b4, byte b5) => WritingPrimitives.WriteRawTag(ref buffer, ref state, b1, b2, b3, b4, b5); 243 FlushGoogle.Protobuf.WriteContext244 internal void Flush() => WriteBufferHelper.Flush(ref buffer, ref state); 245 CheckNoSpaceLeftGoogle.Protobuf.WriteContext246 internal void CheckNoSpaceLeft() => WriteBufferHelper.CheckNoSpaceLeft(ref state); 247 CopyStateToGoogle.Protobuf.WriteContext248 internal void CopyStateTo(CodedOutputStream output) 249 { 250 output.InternalState = state; 251 } 252 LoadStateFromGoogle.Protobuf.WriteContext253 internal void LoadStateFrom(CodedOutputStream output) 254 { 255 state = output.InternalState; 256 } 257 } 258 }