com.alicizax.kybernetik.ani.../Runtime/Data Types/StringAsset.cs

258 lines
11 KiB
C#
Raw Permalink Normal View History

2025-01-08 15:26:57 +08:00
// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
using UnityEngine;
using System;
using System.Runtime.CompilerServices;
using Object = UnityEngine.Object;
namespace Animancer
{
/// <summary>
/// A <see cref="ScriptableObject"/> which holds a <see cref="StringReference"/>
/// based on its <see cref="Object.name"/>.
/// </summary>
/// https://kybernetik.com.au/animancer/api/Animancer/StringAsset
[AnimancerHelpUrl(typeof(StringAsset))]
[CreateAssetMenu(
menuName = Strings.MenuPrefix + "String Asset",
order = Strings.AssetMenuOrder + 2)]
public class StringAsset : ScriptableObject,
IComparable<StringAsset>,
IConvertable<StringReference>,
IConvertable<string>,
IEquatable<StringAsset>,
IEquatable<StringReference>,
IEquatable<string>,
IHasKey
{
/************************************************************************************************************************/
private StringReference _Name;
/// <summary>A <see cref="StringReference"/> to the <see cref="Object.name"/>.</summary>
/// <remarks>
/// This value is gathered when first accessed, but will not be automatically updated after that
/// because doing so causes some garbage allocation (except in the Unity Editor for convenience).
/// </remarks>
public StringReference Name
{
#if UNITY_EDITOR
// Don't do this at runtime because it allocates garbage every time.
// But in the Unity Editor things could get renamed at any time.
get => _Name = this ? name : "";
#else
get => _Name ??= name;
#endif
set => _Name = name = value;
}
/// <inheritdoc/>
public object Key
=> Name;
/************************************************************************************************************************/
#region Equality
/************************************************************************************************************************/
/// <summary>Compares the <see cref="StringReference.String"/>s.</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Compare(StringAsset a, StringAsset b)
=> a == b
? 0
: a
? a.CompareTo(b)
: -1;
/// <summary>Compares the <see cref="StringReference.String"/>s.</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int CompareTo(StringAsset other)
=> other
? Name.String.CompareTo(other.Name.String)
: 1;
/************************************************************************************************************************/
/// <summary>Is the <see cref="Name"/> equal to the `other`?</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(StringAsset other)
=> other is not null
&& Name == other.Name;
/// <summary>Is the <see cref="Name"/> equal to the `other`?</summary>
/// <remarks>Uses <see cref="object.ReferenceEquals"/>.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(StringReference other)
=> Name == other;
/// <summary>Is the <see cref="Name"/> equal to the `value`?</summary>
/// <remarks>Checks regular string equality because the `value` might not be interned.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(string value)
=> Name.String == value;
/// <summary>Is the <see cref="Name"/> equal to the `other`?</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object other)
{
if (other is StringAsset asset)
return Equals(asset);
if (other is StringReference reference)
return Equals(reference);
if (other is string value)
return Equals(value);
return false;
}
/************************************************************************************************************************/
/// <summary>Are the <see cref="Name"/>s equal?</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(StringAsset a, StringAsset b)
=> a is null
? b is null
: a.Equals(b);
/// <summary>Are the <see cref="Name"/>s not equal?</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(StringAsset a, StringAsset b)
=> a is null
? b is not null
: !a.Equals(b);
/************************************************************************************************************************/
/// <summary>Is the <see cref="Name"/> equal to `b`?</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(StringAsset a, StringReference b)
=> a?.Name == b;
/// <summary>Is the <see cref="Name"/> not equal to `b`?</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(StringAsset a, StringReference b)
=> a?.Name != b;
/// <summary>Is the <see cref="Name"/> equal to `a`?</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(StringReference a, StringAsset b)
=> a == b?.Name;
/// <summary>Is the <see cref="Name"/> not equal to `a`?</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(StringReference a, StringAsset b)
=> a != b?.Name;
/************************************************************************************************************************/
/// <summary>Is the <see cref="Name"/> equal to `b`?</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(StringAsset a, string b)
=> a?.Name.String == b;
/// <summary>Is the <see cref="Name"/> not equal to `b`?</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(StringAsset a, string b)
=> a?.Name.String != b;
/// <summary>Is the <see cref="Name"/> equal to `a`?</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(string a, StringAsset b)
=> b?.Name.String == a;
/// <summary>Is the <see cref="Name"/> not equal to `a`?</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(string a, StringAsset b)
=> b?.Name.String != a;
/************************************************************************************************************************/
/// <summary>Returns the hash code of the <see cref="Name"/>.</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode()
=> Name.GetHashCode();
/************************************************************************************************************************/
#endregion
/************************************************************************************************************************/
#region Conversion
/************************************************************************************************************************/
/// <summary>Returns the <see cref="Name"/>.</summary>
public override string ToString()
=> Name;
/// <inheritdoc/>
StringReference IConvertable<StringReference>.Convert()
=> Name;
/// <inheritdoc/>
string IConvertable<string>.Convert()
=> Name;
/************************************************************************************************************************/
/// <summary>Returns the <see cref="Name"/>.</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator string(StringAsset key)
=> key?.Name;
/// <summary>Returns the <see cref="Name"/>.</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator StringReference(StringAsset key)
=> key?.Name;
/************************************************************************************************************************/
/// <summary>Creates a new array containing the <see cref="Name"/>s.</summary>
public static StringReference[] ToStringReferences(params StringAsset[] keys)
{
if (keys == null)
return null;
if (keys.Length == 0)
return Array.Empty<StringReference>();
var strings = new StringReference[keys.Length];
for (int i = 0; i < keys.Length; i++)
strings[i] = keys[i];
return strings;
}
/// <summary>Creates a new array containing the <see cref="Name"/>s.</summary>
public static string[] ToStrings(params StringAsset[] keys)
{
if (keys == null)
return null;
if (keys.Length == 0)
return Array.Empty<string>();
var strings = new string[keys.Length];
for (int i = 0; i < keys.Length; i++)
strings[i] = keys[i];
return strings;
}
/************************************************************************************************************************/
#endregion
/************************************************************************************************************************/
#if UNITY_EDITOR
/************************************************************************************************************************/
[Tooltip("An unused Editor-Only field where you can explain what this asset is used for")]
[SerializeField, TextArea(2, 25)]
private string _EditorComment;
/// <summary>[Editor-Only] [<see cref="SerializeField"/>]
/// An unused Editor-Only field where you can explain what this asset is used for.
/// </summary>
public ref string EditorComment
=> ref _EditorComment;
/************************************************************************************************************************/
#endif
}
}