Slight style updates, make caches to structs.

This commit is contained in:
Ottermandias 2022-10-28 16:54:17 +02:00
parent 58192240ff
commit 293590bd51
3 changed files with 57 additions and 21 deletions

View file

@ -175,21 +175,21 @@ namespace Dalamud.Plugin
#region IPC
/// <inheritdoc cref="Ipc.Internal.DataShare.GetOrCreateData{T}"/>
/// <inheritdoc cref="DataShare.GetOrCreateData{T}"/>
public T GetOrCreateData<T>(string tag, Func<T> dataGenerator) where T : class
=> Service<Ipc.Internal.DataShare>.Get().GetOrCreateData(tag, dataGenerator);
=> Service<DataShare>.Get().GetOrCreateData(tag, dataGenerator);
/// <inheritdoc cref="Ipc.Internal.DataShare.RelinquishData"/>
/// <inheritdoc cref="DataShare.RelinquishData"/>
public void RelinquishData(string tag)
=> Service<Ipc.Internal.DataShare>.Get().RelinquishData(tag);
=> Service<DataShare>.Get().RelinquishData(tag);
/// <inheritdoc cref="Ipc.Internal.DataShare.TryGetData{T}"/>
/// <inheritdoc cref="DataShare.TryGetData{T}"/>
public bool TryGetData<T>(string tag, [NotNullWhen(true)] out T? data) where T : class
=> Service<Ipc.Internal.DataShare>.Get().TryGetData(tag, out data);
=> Service<DataShare>.Get().TryGetData(tag, out data);
/// <inheritdoc cref="Ipc.Internal.DataShare.GetData{T}"/>
/// <inheritdoc cref="DataShare.GetData{T}"/>
public T? GetData<T>(string tag) where T : class
=> Service<Ipc.Internal.DataShare>.Get().GetData<T>(tag);
=> Service<DataShare>.Get().GetData<T>(tag);
/// <summary>
/// Gets an IPC provider.

View file

@ -3,18 +3,34 @@ using System.Collections.Generic;
namespace Dalamud.Plugin.Ipc.Internal;
internal class DataCache
/// <summary>
/// A helper struct for reference-counted, type-safe shared access across plugin boundaries.
/// </summary>
internal readonly struct DataCache
{
internal readonly string CreatorAssemblyName;
internal readonly List<string> UserAssemblyNames;
internal readonly Type Type;
internal readonly object? Data;
/// <summary> The assembly name of the initial creator. </summary>
internal readonly string CreatorAssemblyName;
internal DataCache(string creatorAssemblyName, object? data, Type type)
/// <summary> A not-necessarily distinct list of current users. </summary>
internal readonly List<string> UserAssemblyNames;
/// <summary> The type the data was registered as. </summary>
internal readonly Type Type;
/// <summary> A reference to data. </summary>
internal readonly object? Data;
/// <summary>
/// Initializes a new instance of the <see cref="DataCache"/> struct.
/// </summary>
/// <param name="creatorAssemblyName">The assembly name of the initial creator.</param>
/// <param name="data">A reference to data.</param>
/// <param name="type">The type of the data.</param>
public DataCache(string creatorAssemblyName, object? data, Type type)
{
this.CreatorAssemblyName = creatorAssemblyName;
this.UserAssemblyNames = new List<string>{ creatorAssemblyName };
this.Data = data;
this.Type = type;
this.UserAssemblyNames = new List<string> { creatorAssemblyName };
this.Data = data;
this.Type = type;
}
}

View file

@ -2,10 +2,14 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using Dalamud.Plugin.Ipc.Exceptions;
namespace Dalamud.Plugin.Ipc.Internal;
/// <summary>
/// This class facilitates sharing data-references of standard types between plugins without using more expensive IPC.
/// </summary>
[ServiceManager.EarlyLoadedService]
internal class DataShare : IServiceType
{
@ -45,7 +49,7 @@ internal class DataShare : IServiceType
if (obj == null)
throw new Exception("Returned data was null.");
cache = new DataCache(callerName, obj, typeof(T));
cache = new DataCache(callerName, obj, typeof(T));
this.caches[tag] = cache;
return obj;
}
@ -104,7 +108,23 @@ internal class DataShare : IServiceType
/// </summary>
/// <typeparam name="T">The type for the requested data - needs to be a reference type.</typeparam>
/// <param name="tag">The name for the data cache.</param>
/// <returns>The requested data on success or null.</returns>
public T? GetData<T>(string tag) where T : class
=> TryGetData<T>(tag, out var data) ? data : null;
/// <returns>The requested data</returns>
/// <exception cref="KeyNotFoundException">Thrown if <paramref name="tag"/> is not registered.</exception>
/// <exception cref="DataCacheTypeMismatchError">Thrown if a cache for <paramref name="tag"/> exists, but contains data of a type not assignable to <typeparamref name="T>"/>.</exception>
/// <exception cref="DataCacheValueNullError">Thrown if the stored data for a cache is null.</exception>
public T GetData<T>(string tag) where T : class
{
if (!this.caches.TryGetValue(tag, out var cache))
throw new KeyNotFoundException($"The data cache {tag} is not registered.");
var callerName = Assembly.GetCallingAssembly().GetName().Name ?? string.Empty;
if (!cache.Type.IsAssignableTo(typeof(T)))
throw new DataCacheTypeMismatchError(tag, callerName, typeof(T), cache.Type);
if (cache.Data is not T data)
throw new DataCacheValueNullError(tag, typeof(T));
cache.UserAssemblyNames.Add(callerName);
return data;
}
}