// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Concurrent; using System.Reflection; namespace EpicGames.Core { /// /// Base interface for a binary converter. Implementations must derive from instead /// public interface IBinaryConverter { /// /// Converter version number /// int Version { get; } } /// /// Interface for converting serializing object to and from a binary format /// /// The value to serialize public interface IBinaryConverter : IBinaryConverter { /// /// Reads a value from the archive /// /// The archive reader /// New instance of the value TValue Read(BinaryArchiveReader reader); /// /// Writes a value to the archive /// /// The archive writer /// The value to write void Write(BinaryArchiveWriter writer, TValue value); } /// /// Registration of IBinaryConverter instances /// public static class BinaryConverter { /// /// Map from type to the converter type /// static readonly ConcurrentDictionary s_typeToConverterType = new ConcurrentDictionary(); /// /// Explicitly register the converter for a type. If Type is a generic type, the converter should also be a generic type with the same type arguments. /// /// Type to register a converter for /// The converter type public static void RegisterConverter(Type type, Type converterType) { if (!s_typeToConverterType.TryAdd(type, converterType)) { throw new Exception($"Type '{type.Name}' already has a registered converter ({s_typeToConverterType[type].Name})"); } } /// /// Attempts to get the converter for a particular type /// /// The type to use /// The converter type /// True if a converter was found public static bool TryGetConverterType(Type type, out Type? converterType) { if (s_typeToConverterType.TryGetValue(type, out Type? customConverterType)) { converterType = customConverterType; return true; } BinaryConverterAttribute? converterAttribute = type.GetCustomAttribute(); if (converterAttribute != null) { converterType = converterAttribute.Type; return true; } if (type.IsGenericType) { BinaryConverterAttribute? genericConverterAttribute = type.GetGenericTypeDefinition().GetCustomAttribute(); if (genericConverterAttribute != null) { converterType = genericConverterAttribute.Type.MakeGenericType(type.GetGenericArguments()); return true; } } converterType = null; return false; } } }