diff --git a/MonkeyLoader/IdentifiableExtensions.cs b/MonkeyLoader/IdentifiableExtensions.cs index cbe400b..5a15f6e 100644 --- a/MonkeyLoader/IdentifiableExtensions.cs +++ b/MonkeyLoader/IdentifiableExtensions.cs @@ -1,56 +1,183 @@ using MonkeyLoader.Meta; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MonkeyLoader { + /// + /// Contains extension methods dealing with s. + /// public static class IdentifiableExtensions { + /// + /// Finds the nearest parent of this + /// that satisfies the given . + /// + /// The type of the parent to look for. + /// The to start looking from. + /// The predicate that a potential parent must satisfy. + /// The parent satisfying the . + /// When no suitable parent was found. + public static TParentIdentifiable FindNearestParent(this IIdentifiable identifiable, Predicate predicate) + where TParentIdentifiable : IIdentifiable + { + if (!identifiable.TryFindNearestParent(predicate, out var parentIdentifiable)) + throw new InvalidOperationException("No suitable parent found!"); + + return parentIdentifiable; + } + + /// + /// Finds the nearest parent of this . + /// + /// The type of the parent to look for. + /// The to start looking from. + /// The found parent. + /// When no suitable parent was found. + public static TParentIdentifiable FindNearestParent(this IIdentifiable identifiable) + where TParentIdentifiable : IIdentifiable + { + if (!identifiable.TryFindNearestParent(out TParentIdentifiable? parentIdentifiable)) + throw new InvalidOperationException("No suitable parent found!"); + + return parentIdentifiable; + } + + /// The identifiable collection to start from. + /// public static IIdentifiableSearch Get(this IIdentifiableCollection identifiableCollection) where TIdentifiable : IIdentifiable => new IdentifiableSearch(identifiableCollection.Items); + /// The nested identifiable collection to start from. + /// public static INestedIdentifiableSearch Get(this INestedIdentifiableCollection nestedIdentifiableCollection) where TIdentifiable : INestedIdentifiable => new NestedIdentifiableSearch(nestedIdentifiableCollection.Items); + /// + /// Starts a search for a child from this object. + /// + /// The type of the identifiable owner to start from. + /// The type of the nested to find. + /// The identifiable owner to start from. + /// The search object for it. public static IIdentifiableOwnerSearch Get(this IIdentifiableOwner identifiableOwner) where TOwner : IIdentifiableOwner where TIdentifiable : INestedIdentifiable => new NestedIdentifiableSearch(identifiableOwner.Items, identifiableOwner.FullId); + /// public static IIdentifiableOwnerSearch Get(this IIdentifiableOwner identifiableOwner) where TIdentifiable : INestedIdentifiable => new NestedIdentifiableSearch(identifiableOwner.Items, identifiableOwner.FullId); + /// The nested identifiable owner to start from. + /// public static INestedIdentifiableOwnerSearch Get(this INestedIdentifiableOwner nestedIdentifiableOwner) where TIdentifiable : INestedIdentifiable => new NestedIdentifiableSearch(nestedIdentifiableOwner.Items, nestedIdentifiableOwner.FullId); + /// The nested identifiable collection to start from. + /// public static IEnumerable GetAll(this INestedIdentifiableCollection nestedIdentifiableCollection) where TIdentifiable : INestedIdentifiable => nestedIdentifiableCollection.Items; + /// + /// Gets an enumerable of all child from this object. + /// + /// The type of the nested s to enumerate. + /// The identifiable collection to start from. + /// An enumerable of all child . + public static IEnumerable GetAll(this IIdentifiableCollection identifiableCollection) + where TIdentifiable : IIdentifiable + => identifiableCollection.Items; + + /// + /// Tries to find the nearest parent of this + /// that satisfies the given . + /// + /// The type of the parent to look for. + /// The to start looking from. + /// The predicate that a potential parent must satisfy. + /// The parent satisfying the if found; otherwise, default. + /// true if a parent satisfying the was found; otherwise, false. + public static bool TryFindNearestParent(this IIdentifiable identifiable, + Predicate predicate, [NotNullWhen(true)] out TParentIdentifiable? parentIdentifiable) + where TParentIdentifiable : IIdentifiable + { + while (identifiable.TryFindNearestParent(out parentIdentifiable)) + { + if (predicate(parentIdentifiable)) + return true; + + if (parentIdentifiable is not INestedIdentifiable) + break; + + identifiable = (INestedIdentifiable)parentIdentifiable; + } + + parentIdentifiable = default; + return false; + } + + /// + /// Tries to find the nearest parent of this . + /// + /// The type of the parent to look for. + /// The to start looking from. + /// The parent if found; otherwise, default. + /// true if a parent was found; otherwise, false. + public static bool TryFindNearestParent(this IIdentifiable identifiable, [NotNullWhen(true)] out TParentIdentifiable? parentIdentifiable) + where TParentIdentifiable : IIdentifiable + { + while (identifiable is not TParentIdentifiable and INestedIdentifiable nestedCurrent) + identifiable = nestedCurrent.Parent; + + if (identifiable is TParentIdentifiable parent) + { + parentIdentifiable = parent; + return true; + } + + parentIdentifiable = default; + return false; + } + + /// The nested identifiable owner to start from. + /// public static INestedIdentifiableOwnerTrySearch TryGet(this INestedIdentifiableOwner nestedIdentifiableOwner) where TIdentifiable : INestedIdentifiable => new NestedIdentifiableSearch(nestedIdentifiableOwner.Items, nestedIdentifiableOwner.FullId); + /// + /// Starts a try-search for a child from this object. + /// + /// The try-search object for it. + /// public static IIdentifiableOwnerTrySearch TryGet(this IIdentifiableOwner identifiableOwner) where TOwner : IIdentifiableOwner where TIdentifiable : INestedIdentifiable => new NestedIdentifiableSearch(identifiableOwner.Items, identifiableOwner.FullId); + /// public static IIdentifiableOwnerTrySearch TryGet(this IIdentifiableOwner identifiableOwner) where TIdentifiable : INestedIdentifiable => new NestedIdentifiableSearch(identifiableOwner.Items, identifiableOwner.FullId); + /// The identifiable collection to start from. + /// public static IIdentifiableTrySearch TryGet(this IIdentifiableCollection identifiableCollection) where TIdentifiable : IIdentifiable => new IdentifiableSearch(identifiableCollection.Items); + /// The nested identifiable collection to start from. + /// public static INestedIdentifiableTrySearch TryGet(this INestedIdentifiableCollection nestedIdentifiableCollection) where TIdentifiable : INestedIdentifiable => new NestedIdentifiableSearch(nestedIdentifiableCollection.Items);