You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

147 lines
6.2 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. #nullable enable
  2. using IPA.Config.Stores.Converters;
  3. using System;
  4. using System.ComponentModel;
  5. using System.Diagnostics.CodeAnalysis;
  6. using System.Linq;
  7. namespace IPA.Config.Stores.Attributes
  8. {
  9. /// <summary>
  10. /// Indicates that the generated subclass of the attribute's target should implement <see cref="INotifyPropertyChanged"/>.
  11. /// If the type this is applied to already inherits it, this is implied.
  12. /// </summary>
  13. [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
  14. public sealed class NotifyPropertyChangesAttribute : Attribute { }
  15. /// <summary>
  16. /// Causes a field or property in an object being wrapped by <see cref="GeneratedStore.Generated{T}(Config, bool)"/> to be
  17. /// ignored during serialization and deserialization.
  18. /// </summary>
  19. [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
  20. public sealed class IgnoreAttribute : Attribute { }
  21. /// <summary>
  22. /// Indicates that a field or property in an object being wrapped by <see cref="GeneratedStore.Generated{T}(Config, bool)"/>
  23. /// that would otherwise be nullable (i.e. a reference type or a <see cref="Nullable{T}"/> type) should never be null, and the
  24. /// member will be ignored if the deserialized value is <see langword="null"/>.
  25. /// </summary>
  26. [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
  27. public sealed class NonNullableAttribute : Attribute { }
  28. /// <summary>
  29. /// Indicates that a given field or property in an object being wrapped by <see cref="GeneratedStore.Generated{T}(Config, bool)"/>
  30. /// should be serialized and deserialized using the provided converter instead of the default mechanism.
  31. /// </summary>
  32. [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
  33. public sealed class UseConverterAttribute : Attribute
  34. {
  35. /// <summary>
  36. /// Gets whether or not to use the default converter for the member type instead of the specified type.
  37. /// </summary>
  38. [MemberNotNullWhen(false, nameof(ConverterType))]
  39. public bool UseDefaultConverterForType { get; }
  40. /// <summary>
  41. /// Gets the type of the converter to use.
  42. /// </summary>
  43. public Type? ConverterType { get; }
  44. /// <summary>
  45. /// Gets the target type of the converter if it is avaliable at instantiation time, otherwise
  46. /// <see langword="null"/>.
  47. /// </summary>
  48. public Type? ConverterTargetType { get; }
  49. /// <summary>
  50. /// Gets whether or not this converter is a generic <see cref="ValueConverter{T}"/>.
  51. /// </summary>
  52. [MemberNotNullWhen(true, nameof(ConverterTargetType))]
  53. public bool IsGenericConverter => ConverterTargetType is not null;
  54. /// <summary>
  55. /// Creates a new <see cref="UseConverterAttribute"/> specifying to use the default converter type for the target member.
  56. /// </summary>
  57. public UseConverterAttribute()
  58. => UseDefaultConverterForType = true;
  59. /// <summary>
  60. /// Creates a new <see cref="UseConverterAttribute"/> with a given <see cref="ConverterType"/>.
  61. /// </summary>
  62. /// <param name="converterType">the type to assign to <see cref="ConverterType"/></param>
  63. public UseConverterAttribute(Type converterType)
  64. {
  65. if (converterType is null)
  66. throw new ArgumentNullException(nameof(converterType));
  67. UseDefaultConverterForType = false;
  68. ConverterType = converterType;
  69. if (converterType.IsValueType)
  70. throw new ArgumentException("Type is not a value converter!");
  71. var baseT = ConverterType.BaseType;
  72. while (baseT != typeof(object) &&
  73. (!baseT.IsGenericType || baseT.GetGenericTypeDefinition() != typeof(ValueConverter<>)))
  74. baseT = baseT.BaseType;
  75. if (baseT == typeof(object)) ConverterTargetType = null;
  76. else ConverterTargetType = baseT.GetGenericArguments()[0];
  77. var implInterface = ConverterType.GetInterfaces().Contains(typeof(IValueConverter));
  78. if (ConverterTargetType == null && !implInterface) throw new ArgumentException("Type is not a value converter!");
  79. }
  80. }
  81. /// <summary>
  82. /// Specifies a name for the serialized field or property in an object being wrapped by
  83. /// <see cref="GeneratedStore.Generated{T}(Config, bool)"/> that is different from the member name itself.
  84. /// </summary>
  85. /// <example>
  86. /// <para>
  87. /// When serializing the following object, we might get the JSON that follows.
  88. /// <code>
  89. /// public class PluginConfig
  90. /// {
  91. /// public virtual bool BooleanField { get; set; } = true;
  92. /// }
  93. /// </code>
  94. /// <code>
  95. /// {
  96. /// "BooleanField": true
  97. /// }
  98. /// </code>
  99. /// </para>
  100. /// <para>
  101. /// However, if we were to add a <see cref="SerializedNameAttribute"/> to that field, we would get the following.
  102. /// <code>
  103. /// public class PluginConfig
  104. /// {
  105. /// [SerializedName("bool")]
  106. /// public virtual bool BooleanField { get; set; } = true;
  107. /// }
  108. /// </code>
  109. /// <code>
  110. /// {
  111. /// "bool": true
  112. /// }
  113. /// </code>
  114. /// </para>
  115. /// </example>
  116. [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
  117. public sealed class SerializedNameAttribute : Attribute
  118. {
  119. /// <summary>
  120. /// Gets the name to replace the member name with.
  121. /// </summary>
  122. public string Name { get; private set; }
  123. /// <summary>
  124. /// Creates a new <see cref="SerializedNameAttribute"/> with the given <see cref="Name"/>.
  125. /// </summary>
  126. /// <param name="name">the value to assign to <see cref="Name"/></param>
  127. public SerializedNameAttribute(string name)
  128. {
  129. Name = name;
  130. }
  131. }
  132. }