1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 using System
.Buffers
.Binary
;
6 using System
.Diagnostics
;
7 using System
.Runtime
.CompilerServices
;
8 using System
.Runtime
.InteropServices
;
9 using Internal
.Runtime
.CompilerServices
;
11 namespace System
.Buffers
14 public static partial class SequenceReaderExtensions
17 /// Try to read the given type out of the buffer if possible. Warning: this is dangerous to use with arbitrary
18 /// structs- see remarks for full details.
21 /// IMPORTANT: The read is a straight copy of bits. If a struct depends on specific state of it's members to
22 /// behave correctly this can lead to exceptions, etc. If reading endian specific integers, use the explicit
23 /// overloads such as <see cref="TryReadLittleEndian(ref SequenceReader{byte}, out short)"/>
26 /// True if successful. <paramref name="value"/> will be default if failed (due to lack of space).
28 [MethodImpl(MethodImplOptions
.AggressiveInlining
)]
29 internal static unsafe bool TryRead
<T
>(ref this SequenceReader
<byte> reader
, out T
value) where T
: unmanaged
31 ReadOnlySpan
<byte> span
= reader
.UnreadSpan
;
32 if (span
.Length
< sizeof(T
))
33 return TryReadMultisegment(ref reader
, out value);
35 value = Unsafe
.ReadUnaligned
<T
>(ref MemoryMarshal
.GetReference(span
));
36 reader
.Advance(sizeof(T
));
40 private static unsafe bool TryReadMultisegment
<T
>(ref SequenceReader
<byte> reader
, out T
value) where T
: unmanaged
42 Debug
.Assert(reader
.UnreadSpan
.Length
< sizeof(T
));
44 // Not enough data in the current segment, try to peek for the data we need.
46 Span
<byte> tempSpan
= new Span
<byte>(&buffer
, sizeof(T
));
48 if (!reader
.TryCopyTo(tempSpan
))
54 value = Unsafe
.ReadUnaligned
<T
>(ref MemoryMarshal
.GetReference(tempSpan
));
55 reader
.Advance(sizeof(T
));
60 /// Reads an <see cref="short"/> as little endian.
62 /// <returns>False if there wasn't enough data for an <see cref="short"/>.</returns>
63 public static bool TryReadLittleEndian(ref this SequenceReader
<byte> reader
, out short value)
65 if (BitConverter
.IsLittleEndian
)
67 return reader
.TryRead(out value);
70 return TryReadReverseEndianness(ref reader
, out value);
74 /// Reads an <see cref="short"/> as big endian.
76 /// <returns>False if there wasn't enough data for an <see cref="short"/>.</returns>
77 public static bool TryReadBigEndian(ref this SequenceReader
<byte> reader
, out short value)
79 if (!BitConverter
.IsLittleEndian
)
81 return reader
.TryRead(out value);
84 return TryReadReverseEndianness(ref reader
, out value);
87 private static bool TryReadReverseEndianness(ref SequenceReader
<byte> reader
, out short value)
89 if (reader
.TryRead(out value))
91 value = BinaryPrimitives
.ReverseEndianness(value);
99 /// Reads an <see cref="int"/> as little endian.
101 /// <returns>False if there wasn't enough data for an <see cref="int"/>.</returns>
102 public static bool TryReadLittleEndian(ref this SequenceReader
<byte> reader
, out int value)
104 if (BitConverter
.IsLittleEndian
)
106 return reader
.TryRead(out value);
109 return TryReadReverseEndianness(ref reader
, out value);
113 /// Reads an <see cref="int"/> as big endian.
115 /// <returns>False if there wasn't enough data for an <see cref="int"/>.</returns>
116 public static bool TryReadBigEndian(ref this SequenceReader
<byte> reader
, out int value)
118 if (!BitConverter
.IsLittleEndian
)
120 return reader
.TryRead(out value);
123 return TryReadReverseEndianness(ref reader
, out value);
126 private static bool TryReadReverseEndianness(ref SequenceReader
<byte> reader
, out int value)
128 if (reader
.TryRead(out value))
130 value = BinaryPrimitives
.ReverseEndianness(value);
138 /// Reads an <see cref="long"/> as little endian.
140 /// <returns>False if there wasn't enough data for an <see cref="long"/>.</returns>
141 public static bool TryReadLittleEndian(ref this SequenceReader
<byte> reader
, out long value)
143 if (BitConverter
.IsLittleEndian
)
145 return reader
.TryRead(out value);
148 return TryReadReverseEndianness(ref reader
, out value);
152 /// Reads an <see cref="long"/> as big endian.
154 /// <returns>False if there wasn't enough data for an <see cref="long"/>.</returns>
155 public static bool TryReadBigEndian(ref this SequenceReader
<byte> reader
, out long value)
157 if (!BitConverter
.IsLittleEndian
)
159 return reader
.TryRead(out value);
162 return TryReadReverseEndianness(ref reader
, out value);
165 private static bool TryReadReverseEndianness(ref SequenceReader
<byte> reader
, out long value)
167 if (reader
.TryRead(out value))
169 value = BinaryPrimitives
.ReverseEndianness(value);
177 public static partial class SequenceReaderExtensions
179 public static bool TryReadBigEndian(this System
.Buffers
.SequenceReader
<byte> reader
, out short value) => throw new PlatformNotSupportedException();
180 public static bool TryReadBigEndian(this System
.Buffers
.SequenceReader
<byte> reader
, out int value) => throw new PlatformNotSupportedException();
181 public static bool TryReadBigEndian(this System
.Buffers
.SequenceReader
<byte> reader
, out long value) => throw new PlatformNotSupportedException();
182 public static bool TryReadLittleEndian(this System
.Buffers
.SequenceReader
<byte> reader
, out short value) => throw new PlatformNotSupportedException();
183 public static bool TryReadLittleEndian(this System
.Buffers
.SequenceReader
<byte> reader
, out int value) => throw new PlatformNotSupportedException();
184 public static bool TryReadLittleEndian(this System
.Buffers
.SequenceReader
<byte> reader
, out long value) => throw new PlatformNotSupportedException();