// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
using EpicGames.Core;
using EpicGames.Serialization;
namespace EpicGames.Horde
{
///
/// Base class for converting to and from types containing a . Useful pattern for reducing boilerplate with strongly typed records.
///
///
public abstract class BinaryIdConverter where T : struct
{
///
/// Converts a type to a
///
public abstract BinaryId ToBinaryId(T value);
///
/// Constructs a type from a
///
public abstract T FromBinaryId(BinaryId id);
}
///
/// Attribute declaring a for a particular type
///
[AttributeUsage(AttributeTargets.Struct)]
public sealed class BinaryIdConverterAttribute : Attribute
{
///
/// The converter type
///
public Type ConverterType { get; }
///
/// Constructor
///
public BinaryIdConverterAttribute(Type converterType) => ConverterType = converterType;
}
///
/// Converter to compact binary objects
///
public sealed class BinaryIdCbConverter : CbConverter where TValue : struct where TConverter : BinaryIdConverter, new()
{
readonly TConverter _converter = new TConverter();
///
public override TValue Read(CbField field)
{
return _converter.FromBinaryId(BinaryId.Parse(field.AsUtf8String()));
}
///
public override void Write(CbWriter writer, TValue value)
{
writer.WriteStringValue(_converter.ToBinaryId(value).ToString());
}
///
public override void WriteNamed(CbWriter writer, CbFieldName name, TValue value)
{
writer.WriteString(name, _converter.ToBinaryId(value).ToString());
}
}
///
/// Class which serializes types with a to Json
///
public sealed class BinaryIdTypeConverter : TypeConverter where TValue : struct where TConverter : BinaryIdConverter, new()
{
readonly TConverter _converter = new TConverter();
///
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
{
return sourceType == typeof(string) || sourceType == typeof(BinaryId);
}
///
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
{
if (value is string str)
{
return _converter.FromBinaryId(BinaryId.Parse(str));
}
if (value is BinaryId stringId)
{
return _converter.FromBinaryId(stringId);
}
return null;
}
///
public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destinationType) => destinationType == typeof(string) || destinationType == typeof(BinaryId);
///
public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType)
{
if (destinationType == typeof(string))
{
return _converter.ToBinaryId((TValue)value!).ToString();
}
if (destinationType == typeof(BinaryId))
{
return _converter.ToBinaryId((TValue)value!);
}
return null;
}
}
///
/// Class which serializes types with a to Json
///
public sealed class BinaryIdJsonConverter : JsonConverter where TValue : struct where TConverter : BinaryIdConverter, new()
{
readonly TConverter _converter = new TConverter();
///
public override TValue Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => _converter.FromBinaryId(BinaryId.Parse(reader.GetUtf8String()));
///
public override void Write(Utf8JsonWriter writer, TValue value, JsonSerializerOptions options)
{
BinaryId binaryId = _converter.ToBinaryId(value);
Span span = stackalloc byte[12 * 2];
binaryId.ToUtf8String(span);
writer.WriteStringValue(span);
}
}
///
/// Creates constructors for types with a to Json
///
public sealed class BinaryIdJsonConverterFactory : JsonConverterFactory
{
///
public override bool CanConvert(Type typeToConvert) => typeToConvert.GetCustomAttribute() != null;
///
public override JsonConverter? CreateConverter(Type type, JsonSerializerOptions options)
{
BinaryIdConverterAttribute? attribute = type.GetCustomAttribute();
if (attribute == null)
{
return null;
}
return (JsonConverter?)Activator.CreateInstance(typeof(BinaryIdJsonConverter<,>).MakeGenericType(type, attribute.ConverterType));
}
}
}