|
#nullable enable
|
|
using IPA.Config.Stores.Converters;
|
|
using System;
|
|
using System.ComponentModel;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Linq;
|
|
|
|
namespace IPA.Config.Stores.Attributes
|
|
{
|
|
/// <summary>
|
|
/// Indicates that the generated subclass of the attribute's target should implement <see cref="INotifyPropertyChanged"/>.
|
|
/// If the type this is applied to already inherits it, this is implied.
|
|
/// </summary>
|
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
|
|
public sealed class NotifyPropertyChangesAttribute : Attribute { }
|
|
|
|
/// <summary>
|
|
/// Causes a field or property in an object being wrapped by <see cref="GeneratedStore.Generated{T}(Config, bool)"/> to be
|
|
/// ignored during serialization and deserialization.
|
|
/// </summary>
|
|
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
|
|
public sealed class IgnoreAttribute : Attribute { }
|
|
|
|
/// <summary>
|
|
/// Indicates that a field or property in an object being wrapped by <see cref="GeneratedStore.Generated{T}(Config, bool)"/>
|
|
/// that would otherwise be nullable (i.e. a reference type or a <see cref="Nullable{T}"/> type) should never be null, and the
|
|
/// member will be ignored if the deserialized value is <see langword="null"/>.
|
|
/// </summary>
|
|
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
|
|
public sealed class NonNullableAttribute : Attribute { }
|
|
|
|
/// <summary>
|
|
/// Indicates that a given field or property in an object being wrapped by <see cref="GeneratedStore.Generated{T}(Config, bool)"/>
|
|
/// should be serialized and deserialized using the provided converter instead of the default mechanism.
|
|
/// </summary>
|
|
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
|
|
public sealed class UseConverterAttribute : Attribute
|
|
{
|
|
/// <summary>
|
|
/// Gets whether or not to use the default converter for the member type instead of the specified type.
|
|
/// </summary>
|
|
[MemberNotNullWhen(false, nameof(ConverterType))]
|
|
public bool UseDefaultConverterForType { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the type of the converter to use.
|
|
/// </summary>
|
|
public Type? ConverterType { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the target type of the converter if it is avaliable at instantiation time, otherwise
|
|
/// <see langword="null"/>.
|
|
/// </summary>
|
|
public Type? ConverterTargetType { get; }
|
|
|
|
/// <summary>
|
|
/// Gets whether or not this converter is a generic <see cref="ValueConverter{T}"/>.
|
|
/// </summary>
|
|
[MemberNotNullWhen(true, nameof(ConverterTargetType))]
|
|
public bool IsGenericConverter => ConverterTargetType is not null;
|
|
|
|
/// <summary>
|
|
/// Creates a new <see cref="UseConverterAttribute"/> specifying to use the default converter type for the target member.
|
|
/// </summary>
|
|
public UseConverterAttribute()
|
|
=> UseDefaultConverterForType = true;
|
|
|
|
/// <summary>
|
|
/// Creates a new <see cref="UseConverterAttribute"/> with a given <see cref="ConverterType"/>.
|
|
/// </summary>
|
|
/// <param name="converterType">the type to assign to <see cref="ConverterType"/></param>
|
|
public UseConverterAttribute(Type converterType)
|
|
{
|
|
if (converterType is null)
|
|
throw new ArgumentNullException(nameof(converterType));
|
|
|
|
UseDefaultConverterForType = false;
|
|
ConverterType = converterType;
|
|
|
|
if (converterType.IsValueType)
|
|
throw new ArgumentException("Type is not a value converter!");
|
|
|
|
var baseT = ConverterType.BaseType;
|
|
while (baseT != typeof(object) &&
|
|
(!baseT.IsGenericType || baseT.GetGenericTypeDefinition() != typeof(ValueConverter<>)))
|
|
baseT = baseT.BaseType;
|
|
if (baseT == typeof(object)) ConverterTargetType = null;
|
|
else ConverterTargetType = baseT.GetGenericArguments()[0];
|
|
|
|
var implInterface = ConverterType.GetInterfaces().Contains(typeof(IValueConverter));
|
|
|
|
if (ConverterTargetType == null && !implInterface) throw new ArgumentException("Type is not a value converter!");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Specifies a name for the serialized field or property in an object being wrapped by
|
|
/// <see cref="GeneratedStore.Generated{T}(Config, bool)"/> that is different from the member name itself.
|
|
/// </summary>
|
|
/// <example>
|
|
/// <para>
|
|
/// When serializing the following object, we might get the JSON that follows.
|
|
/// <code>
|
|
/// public class PluginConfig
|
|
/// {
|
|
/// public virtual bool BooleanField { get; set; } = true;
|
|
/// }
|
|
/// </code>
|
|
/// <code>
|
|
/// {
|
|
/// "BooleanField": true
|
|
/// }
|
|
/// </code>
|
|
/// </para>
|
|
/// <para>
|
|
/// However, if we were to add a <see cref="SerializedNameAttribute"/> to that field, we would get the following.
|
|
/// <code>
|
|
/// public class PluginConfig
|
|
/// {
|
|
/// [SerializedName("bool")]
|
|
/// public virtual bool BooleanField { get; set; } = true;
|
|
/// }
|
|
/// </code>
|
|
/// <code>
|
|
/// {
|
|
/// "bool": true
|
|
/// }
|
|
/// </code>
|
|
/// </para>
|
|
/// </example>
|
|
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
|
|
public sealed class SerializedNameAttribute : Attribute
|
|
{
|
|
/// <summary>
|
|
/// Gets the name to replace the member name with.
|
|
/// </summary>
|
|
public string Name { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Creates a new <see cref="SerializedNameAttribute"/> with the given <see cref="Name"/>.
|
|
/// </summary>
|
|
/// <param name="name">the value to assign to <see cref="Name"/></param>
|
|
public SerializedNameAttribute(string name)
|
|
{
|
|
Name = name;
|
|
}
|
|
}
|
|
}
|