// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System.Buffers.Binary; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Internal.Runtime.CompilerServices; namespace System.Buffers { #if !__MonoCS__ public static partial class SequenceReaderExtensions { /// /// Try to read the given type out of the buffer if possible. Warning: this is dangerous to use with arbitrary /// structs- see remarks for full details. /// /// /// IMPORTANT: The read is a straight copy of bits. If a struct depends on specific state of it's members to /// behave correctly this can lead to exceptions, etc. If reading endian specific integers, use the explicit /// overloads such as /// /// /// True if successful. will be default if failed (due to lack of space). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static unsafe bool TryRead(ref this SequenceReader reader, out T value) where T : unmanaged { ReadOnlySpan span = reader.UnreadSpan; if (span.Length < sizeof(T)) return TryReadMultisegment(ref reader, out value); value = Unsafe.ReadUnaligned(ref MemoryMarshal.GetReference(span)); reader.Advance(sizeof(T)); return true; } private static unsafe bool TryReadMultisegment(ref SequenceReader reader, out T value) where T : unmanaged { Debug.Assert(reader.UnreadSpan.Length < sizeof(T)); // Not enough data in the current segment, try to peek for the data we need. T buffer = default; Span tempSpan = new Span(&buffer, sizeof(T)); if (!reader.TryCopyTo(tempSpan)) { value = default; return false; } value = Unsafe.ReadUnaligned(ref MemoryMarshal.GetReference(tempSpan)); reader.Advance(sizeof(T)); return true; } /// /// Reads an as little endian. /// /// False if there wasn't enough data for an . public static bool TryReadLittleEndian(ref this SequenceReader reader, out short value) { if (BitConverter.IsLittleEndian) { return reader.TryRead(out value); } return TryReadReverseEndianness(ref reader, out value); } /// /// Reads an as big endian. /// /// False if there wasn't enough data for an . public static bool TryReadBigEndian(ref this SequenceReader reader, out short value) { if (!BitConverter.IsLittleEndian) { return reader.TryRead(out value); } return TryReadReverseEndianness(ref reader, out value); } private static bool TryReadReverseEndianness(ref SequenceReader reader, out short value) { if (reader.TryRead(out value)) { value = BinaryPrimitives.ReverseEndianness(value); return true; } return false; } /// /// Reads an as little endian. /// /// False if there wasn't enough data for an . public static bool TryReadLittleEndian(ref this SequenceReader reader, out int value) { if (BitConverter.IsLittleEndian) { return reader.TryRead(out value); } return TryReadReverseEndianness(ref reader, out value); } /// /// Reads an as big endian. /// /// False if there wasn't enough data for an . public static bool TryReadBigEndian(ref this SequenceReader reader, out int value) { if (!BitConverter.IsLittleEndian) { return reader.TryRead(out value); } return TryReadReverseEndianness(ref reader, out value); } private static bool TryReadReverseEndianness(ref SequenceReader reader, out int value) { if (reader.TryRead(out value)) { value = BinaryPrimitives.ReverseEndianness(value); return true; } return false; } /// /// Reads an as little endian. /// /// False if there wasn't enough data for an . public static bool TryReadLittleEndian(ref this SequenceReader reader, out long value) { if (BitConverter.IsLittleEndian) { return reader.TryRead(out value); } return TryReadReverseEndianness(ref reader, out value); } /// /// Reads an as big endian. /// /// False if there wasn't enough data for an . public static bool TryReadBigEndian(ref this SequenceReader reader, out long value) { if (!BitConverter.IsLittleEndian) { return reader.TryRead(out value); } return TryReadReverseEndianness(ref reader, out value); } private static bool TryReadReverseEndianness(ref SequenceReader reader, out long value) { if (reader.TryRead(out value)) { value = BinaryPrimitives.ReverseEndianness(value); return true; } return false; } } #else public static partial class SequenceReaderExtensions { public static bool TryReadBigEndian(this System.Buffers.SequenceReader reader, out short value) => throw new PlatformNotSupportedException(); public static bool TryReadBigEndian(this System.Buffers.SequenceReader reader, out int value) => throw new PlatformNotSupportedException(); public static bool TryReadBigEndian(this System.Buffers.SequenceReader reader, out long value) => throw new PlatformNotSupportedException(); public static bool TryReadLittleEndian(this System.Buffers.SequenceReader reader, out short value) => throw new PlatformNotSupportedException(); public static bool TryReadLittleEndian(this System.Buffers.SequenceReader reader, out int value) => throw new PlatformNotSupportedException(); public static bool TryReadLittleEndian(this System.Buffers.SequenceReader reader, out long value) => throw new PlatformNotSupportedException(); } #endif }