generated from Nexus-Mods/NexusMods.App.Template
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Break out the serializer registry into its own class
- Loading branch information
Showing
10 changed files
with
200 additions
and
54 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
54 changes: 54 additions & 0 deletions
54
src/NexusMods.EventSourcing.Abstractions/EntityStructureRegistry.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
using System; | ||
using System.Collections.Concurrent; | ||
using System.Collections.Generic; | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.Security.Cryptography.X509Certificates; | ||
|
||
namespace NexusMods.EventSourcing.Abstractions; | ||
|
||
/// <summary> | ||
/// Contains structure information about entities (what attributes they have, etc). | ||
/// </summary> | ||
public static class EntityStructureRegistry | ||
{ | ||
private static readonly ConcurrentDictionary<Type, ConcurrentDictionary<string, IAttribute>> _entityStructures = new(); | ||
|
||
/// <summary> | ||
/// Register an attribute in the global registry. | ||
/// </summary> | ||
/// <param name="attribute"></param> | ||
public static void Register(IAttribute attribute) | ||
{ | ||
TOP: | ||
if (_entityStructures.TryGetValue(attribute.Owner, out var found)) | ||
{ | ||
found.TryAdd(attribute.Name, attribute); | ||
return; | ||
} | ||
|
||
var dict = new ConcurrentDictionary<string, IAttribute>(); | ||
dict.TryAdd(attribute.Name, attribute); | ||
if (!_entityStructures.TryAdd(attribute.Owner, dict)) | ||
{ | ||
goto TOP; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Returns all attributes for the given entity type. | ||
/// </summary> | ||
/// <param name="owner"></param> | ||
/// <returns></returns> | ||
public static bool TryGetAttributes(Type owner, [NotNullWhen(true)] out ConcurrentDictionary<string, IAttribute>? result) | ||
{ | ||
if (_entityStructures.TryGetValue(owner, out var found )) | ||
{ | ||
result = found; | ||
return true; | ||
} | ||
|
||
result = default!; | ||
return false; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
25 changes: 25 additions & 0 deletions
25
src/NexusMods.EventSourcing.Abstractions/Serialization/ISerializationRegistry.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using System; | ||
|
||
namespace NexusMods.EventSourcing.Abstractions.Serialization; | ||
|
||
/// <summary> | ||
/// A registry of serializers, this class can be queried at runtime to get a serializer for a given type. | ||
/// The registry is populated by the DI container, and the GetSerializer method is backed by a cache, so | ||
/// calling it in inner loops is not a problem. | ||
/// </summary> | ||
public interface ISerializationRegistry | ||
{ | ||
/// <summary> | ||
/// Gets a serializer that can serialize the given type. | ||
/// </summary> | ||
/// <param name="serializedType"></param> | ||
/// <returns></returns> | ||
public ISerializer GetSerializer(Type serializedType); | ||
|
||
/// <summary> | ||
/// Register a serializer for a given type, used to override the default serializers. | ||
/// </summary> | ||
/// <param name="serializedType"></param> | ||
/// <param name="serializer"></param> | ||
public void RegisterSerializer(Type serializedType, ISerializer serializer); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
82 changes: 82 additions & 0 deletions
82
src/NexusMods.EventSourcing/Serialization/SerializationRegistry.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
using System; | ||
using System.Collections.Concurrent; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using NexusMods.EventSourcing.Abstractions.Serialization; | ||
|
||
namespace NexusMods.EventSourcing.Serialization; | ||
|
||
/// <summary> | ||
/// Manages ISerializer instances, specializes them and manages a cache for them for serialized types. | ||
/// </summary> | ||
public class SerializationRegistry : ISerializationRegistry | ||
{ | ||
private ConcurrentDictionary<Type, ISerializer> _cachedSerializers = new(); | ||
private readonly ISerializer[] _diInjectedSerializers; | ||
private readonly IGenericSerializer[] _genericSerializers; | ||
private readonly GenericArraySerializer _arraySerializer; | ||
|
||
/// <summary> | ||
/// DI constructor. | ||
/// </summary> | ||
/// <param name="diInjectedSerializers"></param> | ||
public SerializationRegistry(IEnumerable<ISerializer> diInjectedSerializers) | ||
{ | ||
_diInjectedSerializers = diInjectedSerializers.ToArray(); | ||
_genericSerializers = _diInjectedSerializers.OfType<IGenericSerializer>().ToArray(); | ||
_arraySerializer = _diInjectedSerializers.OfType<GenericArraySerializer>().First(); | ||
} | ||
|
||
/// <summary> | ||
/// Gets a serializer that can serialize the given type. | ||
/// </summary> | ||
/// <param name="type"></param> | ||
/// <param name="recursiveGetSerializer">Called when the cache needs to recursively create another type serializer</param> | ||
/// <returns></returns> | ||
/// <exception cref="Exception"></exception> | ||
public ISerializer GetSerializer(Type type) | ||
{ | ||
TOP: | ||
if (_cachedSerializers.TryGetValue(type, out var found)) | ||
return found; | ||
|
||
var result = _diInjectedSerializers.FirstOrDefault(s => s.CanSerialize(type)); | ||
if (result != null) | ||
{ | ||
return result; | ||
} | ||
|
||
if (type.IsConstructedGenericType) | ||
{ | ||
foreach (var maker in _genericSerializers) | ||
{ | ||
if (maker.TrySpecialize(type.GetGenericTypeDefinition(), | ||
type.GetGenericArguments(), GetSerializer, out var serializer)) | ||
{ | ||
return serializer; | ||
} | ||
} | ||
} | ||
|
||
if (type.IsArray) | ||
{ | ||
_arraySerializer.TrySpecialize(type, [type.GetElementType()!], GetSerializer, out var serializer); | ||
|
||
if (!_cachedSerializers.TryAdd(type, serializer!)) | ||
goto TOP; | ||
return serializer!; | ||
} | ||
|
||
throw new Exception($"No serializer found for {type}"); | ||
} | ||
|
||
/// <summary> | ||
/// Adds a serializer to the registry. | ||
/// </summary> | ||
/// <param name="serializedType"></param> | ||
/// <param name="serializer"></param> | ||
public void RegisterSerializer(Type serializedType, ISerializer serializer) | ||
{ | ||
_cachedSerializers.TryAdd(serializedType, serializer); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters