Skip to content
This repository has been archived by the owner on Feb 28, 2024. It is now read-only.

Commit

Permalink
Apply change requests from pull request
Browse files Browse the repository at this point in the history
  • Loading branch information
Banane9 committed May 24, 2022
1 parent f6f2485 commit 6953a42
Showing 1 changed file with 52 additions and 31 deletions.
83 changes: 52 additions & 31 deletions NeosModLoader/Utility/EnumerableInjector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,38 @@
namespace NeosModLoader.Utility
{
/// <summary>
/// Provides the ability to inject actions into the execution of an enumeration while transforming it.
/// Provides the ability to inject actions into the execution of an enumeration while transforming it.<br/><br/>
/// This example shows how to apply the <see cref="EnumerableInjector{TIn, TOut}"/> when patching a function.<br/>
/// Of course you typically wouldn't patch with a generic method, that's just for illustrating the Type usage.
/// <code>
/// private static void Postfix&lt;Original, Transformed&gt;(ref IEnumerable&lt;Original&gt; __result) where Transformed : Original
/// {
/// __result = new EnumerableInjector&lt;Original, Transformed&gt;(__result,
/// item =&gt; { Msg("Change what the item is exactly"); return new Transformed(item); })
/// {
/// Prefix = () =&gt; Msg("Before the first item is returned"),
/// PreItem = item =&gt; { Msg("Decide if an item gets returned"); return true; },
/// PostItem = (original, transformed, returned) =&gt; Msg("After control would come back to the generator after a yield return"),
/// Postfix = () =&gt; Msg("When the generator stopped returning items")
/// };
/// }
/// </code>
/// </summary>
/// <typeparam name="TIn">The type of the original enumeration.</typeparam>
/// <typeparam name="TOut">The type of the transformed enumeration.</typeparam>
public class EnumerableInjector<TIn, TOut> : IEnumerable<TOut>
/// <typeparam name="TOriginal">The type of the original enumeration's items.</typeparam>
/// <typeparam name="TTransformed">The type of the transformed enumeration's items.<br/>Must be assignable to <c>TOriginal</c> for compatibility.</typeparam>
public class EnumerableInjector<TOriginal, TTransformed> : IEnumerable<TTransformed>
where TTransformed : TOriginal
{
/// <summary>
/// Internal enumerator for iteration.
/// </summary>
private readonly IEnumerator<TIn> enumerator;
private readonly IEnumerator<TOriginal> enumerator;

private Action postfix = nothing;
private Action<TIn, TOut, bool> postItem = nothing;
private Action prefix = nothing;
private Func<TIn, bool> preItem = yes;
private Func<TIn, TOut> transformItem;
private Action postfix = () => { };
private Action<TOriginal, TTransformed, bool> postItem = (original, transformed, returned) => { };
private Action prefix = () => { };
private Func<TOriginal, bool> preItem = item => true;
private Func<TOriginal, TTransformed> transformItem = item => throw new NotImplementedException("You're supposed to inser your own transformation function here!");

/// <summary>
/// Gets called when the wrapped enumeration returned the last item.
Expand All @@ -38,7 +54,7 @@ public Action Postfix
/// Gets called for each item, with the transformed item, and whether it was passed through.
/// First thing to be called after execution returns to the enumerator after a yield return.
/// </summary>
public Action<TIn, TOut, bool> PostItem
public Action<TOriginal, TTransformed, bool> PostItem
{
get => postItem;
set => postItem = value ?? throw new ArgumentNullException(nameof(value), "PostItem can't be null!");
Expand All @@ -56,7 +72,7 @@ public Action Prefix
/// <summary>
/// Gets called for each item to determine whether it should be passed through.
/// </summary>
public Func<TIn, bool> PreItem
public Func<TOriginal, bool> PreItem
{
get => preItem;
set => preItem = value ?? throw new ArgumentNullException(nameof(value), "PreItem can't be null!");
Expand All @@ -65,27 +81,27 @@ public Func<TIn, bool> PreItem
/// <summary>
/// Gets called for each item to transform it, even if it won't be passed through.
/// </summary>
public Func<TIn, TOut> TransformItem
public Func<TOriginal, TTransformed> TransformItem
{
get => transformItem;
set => transformItem = value ?? throw new ArgumentNullException(nameof(value), "TransforItem can't be null!");
set => transformItem = value ?? throw new ArgumentNullException(nameof(value), "TransformItem can't be null!");
}

/// <summary>
/// Creates a new instance of the <see cref="EnumerableInjector{TIn, TOut}"/> class using the supplied input enumerable and transform function.
/// </summary>
/// <param name="enumerable">The enumerable to inject into and transform.</param>
/// <param name="transformItem">The transformation function.</param>
public EnumerableInjector(IEnumerable<TIn> enumerable, Func<TIn, TOut> transformItem)
public EnumerableInjector(IEnumerable<TOriginal> enumerable, Func<TOriginal, TTransformed> transformItem)
: this(enumerable.GetEnumerator(), transformItem)
{ }

/// <summary>
/// Creates a new instance of the <see cref="EnumerableInjector{TIn, TOut}"/> class using the supplied input enumerator and transform function.
/// </summary>
/// <param name="enumerable">The enumerator to inject into and transform.</param>
/// <param name="enumerator">The enumerator to inject into and transform.</param>
/// <param name="transformItem">The transformation function.</param>
public EnumerableInjector(IEnumerator<TIn> enumerator, Func<TIn, TOut> transformItem)
public EnumerableInjector(IEnumerator<TOriginal> enumerator, Func<TOriginal, TTransformed> transformItem)
{
this.enumerator = enumerator;
TransformItem = transformItem;
Expand All @@ -95,7 +111,7 @@ public EnumerableInjector(IEnumerator<TIn> enumerator, Func<TIn, TOut> transform
/// Injects into and transforms the input enumeration.
/// </summary>
/// <returns>The injected and transformed enumeration.</returns>
public IEnumerator<TOut> GetEnumerator()
public IEnumerator<TTransformed> GetEnumerator()
{
Prefix();

Expand All @@ -122,20 +138,27 @@ IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

private static void nothing()
{ }

private static void nothing(TIn _, TOut __, bool ___)
{ }

private static bool yes(TIn _) => true;
}

/// <summary>
/// Provides the ability to inject actions into the execution of an enumeration without transforming it.
/// Provides the ability to inject actions into the execution of an enumeration without transforming it.<br/><br/>
/// This example shows how to apply the <see cref="EnumerableInjector{T}"/> when patching a function.<br/>
/// Of course you typically wouldn't patch with a generic method, that's just for illustrating the Type usage.
/// <code>
/// static void Postfix&lt;T&gt;(ref IEnumerable&lt;T&gt; __result)
/// {
/// __result = new EnumerableInjector&lt;T&gt;(__result)
/// {
/// Prefix = () => Msg("Before the first item is returned"),
/// PreItem = item => { Msg("Decide if an item gets returned"); return true; },
/// TransformItem = item => { Msg("Change what the item is exactly"); return item; },
/// PostItem = (original, transformed, returned) => Msg("After control would come back to the generator after a yield return"),
/// Postfix = () => Msg("When the generator stopped returning items")
/// };
/// }
/// </code>
/// </summary>
/// <typeparam name="T">The type of the enumeration.</typeparam>
/// <typeparam name="T">The type of the enumeration's items.</typeparam>
public class EnumerableInjector<T> : EnumerableInjector<T, T>
{
/// <summary>
Expand All @@ -151,9 +174,7 @@ public EnumerableInjector(IEnumerable<T> enumerable)
/// </summary>
/// <param name="enumerable">The enumerator to inject into.</param>
public EnumerableInjector(IEnumerator<T> enumerator)
: base(enumerator, identity)
: base(enumerator, item => item)
{ }

private static T identity(T item) => item;
}
}

0 comments on commit 6953a42

Please sign in to comment.