Commit 6c6f2fb8 authored by Ray Koopa's avatar Ray Koopa

Add WriteEnum.

parent b0d66a0c
......@@ -222,6 +222,35 @@ namespace Syroot.BinaryData.Memory
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe void WriteDouble(Double value) => WriteUInt64(*(UInt64*)&value);
/// <summary>
/// Write an <see cref="Enum"/> at the current position, using the size of the underlying type.
/// </summary>
/// <param name="value">The value to be written at the current position.</param>
/// <exception cref="ArgumentOutOfRangeException">There are less bytes available than required.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe void WriteEnum<T>(T value) where T : Enum
{
Span<byte> raw = new Span<byte>(Unsafe.AsPointer(ref value), Unsafe.SizeOf<T>());
if (_byteConverter != ByteConverter.System)
raw.Reverse();
WriteBytes(raw);
}
/// <summary>
/// Write an <see cref="Enum"/> at the current position, using the size of the underlying type. The value is
/// validated, throwing an exception if it is not defined in the enum.
/// </summary>
/// <param name="value">The value to be written at the current position.</param>
/// <exception cref="ArgumentException">The value is not defined in the enum.</exception>
/// <exception cref="ArgumentOutOfRangeException">There are less bytes available than required.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteEnumSafe<T>(T value) where T : Enum
{
if (!Tools.ValidateEnumValue(value))
throw new ArgumentException($"Value {value} is not valid for enum {typeof(T)}.");
WriteEnum(value);
}
/// <summary>
/// Write an <see cref="Int16"/> at the current position.
/// </summary>
......
......@@ -14,10 +14,11 @@
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://gitlab.com/Syroot/BinaryData</RepositoryUrl>
<TargetFrameworks>net452;netcoreapp2.1;netstandard2.0</TargetFrameworks>
<VersionPrefix>5.1.0-alpha2</VersionPrefix>
<VersionPrefix>5.1.0-alpha3</VersionPrefix>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Memory" Version="4.5.2" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.5.2" />
<ProjectReference Include="..\Syroot.BinaryData\Syroot.BinaryData.csproj" />
</ItemGroup>
</Project>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
namespace Syroot.BinaryData.Memory
......@@ -11,6 +13,7 @@ namespace Syroot.BinaryData.Memory
// ---- FIELDS -------------------------------------------------------------------------------------------------
private static readonly DateTime _timeTBase = new DateTime(1970, 1, 1);
private static readonly Dictionary<Type, bool> _flagEnums = new Dictionary<Type, bool>();
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
......@@ -41,5 +44,30 @@ namespace Syroot.BinaryData.Memory
throw new ArgumentOutOfRangeException($"Date {value} cannot be represented by time_t.");
return (value - _timeTBase).TotalSeconds;
}
internal static bool ValidateEnumValue<T>(T value) where T : Enum
{
// Check if a simple value is defined in the enum.
Type enumType = typeof(T);
bool valid = Enum.IsDefined(enumType, value);
if (!valid)
{
// For enums decorated with the FlagsAttribute, allow sets of flags.
if (!_flagEnums.TryGetValue(enumType, out bool isFlag))
{
isFlag = enumType.GetCustomAttributes(typeof(FlagsAttribute), false)?.Any() == true;
_flagEnums.Add(enumType, isFlag);
}
if (isFlag)
{
long mask = 0;
foreach (object definedValue in Enum.GetValues(enumType))
mask |= Convert.ToInt64(definedValue);
long longValue = Convert.ToInt64(value);
valid = (mask & longValue) == longValue;
}
}
return valid;
}
}
}
......@@ -22,8 +22,8 @@ namespace Syroot.BinaryData
/// defined in the enum type.</param>
/// <param name="converter">The <see cref="ByteConverter"/> to use for converting multibyte data.</param>
/// <returns>The value read from the current stream.</returns>
public static object ReadEnum(this Stream stream, Type type,
bool strict = false, ByteConverter converter = null)
public static object ReadEnum(this Stream stream, Type type, bool strict = false,
ByteConverter converter = null)
{
converter = converter ?? ByteConverter.System;
......@@ -92,8 +92,8 @@ namespace Syroot.BinaryData
/// <param name="converter">The <see cref="ByteConverter"/> to use for converting multibyte data.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>The value read from the current stream.</returns>
public static async Task<object> ReadEnumAsync(this Stream stream, Type type,
bool strict = false, ByteConverter converter = null,
public static async Task<object> ReadEnumAsync(this Stream stream, Type type, bool strict = false,
ByteConverter converter = null,
CancellationToken cancellationToken = default)
{
converter = converter ?? ByteConverter.System;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment