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

Commit

Permalink
Merge pull request #44 from JacopoWolf/dev/generics
Browse files Browse the repository at this point in the history
Dev/generics
  • Loading branch information
JacopoWolf authored May 13, 2020
2 parents ca18f26 + cfacef5 commit c66cbd9
Show file tree
Hide file tree
Showing 36 changed files with 694 additions and 390 deletions.
72 changes: 72 additions & 0 deletions StackInjector/Core/AsyncStackWrapperCore.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using StackInjector.Wrappers;

namespace StackInjector.Core
{
internal abstract partial class AsyncStackWrapperCore<T> : AsyncStackWrapperCore, IAsyncStackWrapperCore<T>
{

// used to cancel everything
protected internal readonly CancellationTokenSource cancelPendingTasksSource = new CancellationTokenSource();

// exposes the token
public CancellationToken PendingTasksCancellationToken
=> this.cancelPendingTasksSource.Token;

// used to lock access to tasks
protected internal readonly object listAccessLock = new object();

// asyncronously waited for new events if TaskList is empty
protected internal readonly SemaphoreSlim emptyListAwaiter = new SemaphoreSlim(0);

// pending tasks
protected internal LinkedList<Task<T>> tasks = new LinkedList<Task<T>>();


internal AsyncStackWrapperCore ( WrapperCore core, Type toRegister ) : base(core, toRegister)
{
// register an event that in case the list is empty, release the empty event listener.
this.cancelPendingTasksSource.Token.Register(this.ReleaseListAwaiter);
}



#region IDisposable Support

private bool disposedValue = false;

public override void Dispose ()
{
if( !this.disposedValue )
{

// managed resources
this.cancelPendingTasksSource.Cancel();
this.ReleaseListAwaiter(); // in case it's waiting on the empty list

this.cancelPendingTasksSource.Dispose();
this.emptyListAwaiter.Dispose();


// big objects
this.tasks.Clear();
this.tasks = null;

// clean instantiated objects
this.Core.RemoveInstancesDiff();


this.disposedValue = true;
}
}

#endregion

}
}
Original file line number Diff line number Diff line change
@@ -1,35 +1,39 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace StackInjector
namespace StackInjector.Core
{

internal partial class AsyncStackWrapper
internal abstract partial class AsyncStackWrapperCore<T>
{

///<inheritdoc/>
public void Submit ( object submitted )
// call the semaphore
protected internal void ReleaseListAwaiter ()
{
var task = this.GetAsyncEntryPoint().Digest(submitted,this.cancelPendingTasksSource.Token);

this.emptyListAwaiter.Release();
}

public void Submit ( Task<T> work )
{
lock( this.listAccessLock )
this.tasks.AddLast(task);

this.tasks.AddLast( work );

// if the list was empty just an item ago, signal it's not anymore.
// this limit avoids useless cross thread calls that would slow everything down.
if( this.tasks.Count == 1 )
this.ReleaseListAwaiter();
}

public bool AnyTaskLeft ()
{
lock( this.listAccessLock )
return this.tasks.Any();
}


/// <inheritdoc/>
public async IAsyncEnumerable<T> Elaborated<T> ()
public async IAsyncEnumerable<T> Elaborated ()
{
while( !this.cancelPendingTasksSource.IsCancellationRequested )
while( ! this.cancelPendingTasksSource.IsCancellationRequested )
{
// avoid deadlocks
if( this.tasks.Any() )
Expand All @@ -39,7 +43,7 @@ public async IAsyncEnumerable<T> Elaborated<T> ()
lock( this.listAccessLock )
this.tasks.Remove(completed);

yield return (T)completed.Result;
yield return completed.Result;
continue;
}
else
Expand All @@ -51,30 +55,5 @@ public async IAsyncEnumerable<T> Elaborated<T> ()
}
}

/// <inheritdoc/>
public bool AnyTaskLeft ()
{
lock( this.listAccessLock )
return this.tasks.Any();
}


/// <summary>
/// gets the entry point for this stack
/// </summary>
/// <returns></returns>
internal IAsyncStackEntryPoint GetAsyncEntryPoint ()
{
return
(IAsyncStackEntryPoint)
this
.ServicesWithInstances
.OfType
(
this.ClassOrFromInterface(this.EntryPoint)
)
.First();
}

}
}
}
44 changes: 44 additions & 0 deletions StackInjector/Core/Cloning/ClonedCore.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Text;
using StackInjector.Wrappers;
using StackInjector.Wrappers.Generic;

namespace StackInjector.Core.Cloning
{
internal class ClonedCore : IClonedCore
{

private readonly WrapperCore clonedCore;

internal ClonedCore ( WrapperCore clonedCore )
=>
this.clonedCore = clonedCore;


public IAsyncStackWrapper ToAsyncWrapper<T> () where T : IAsyncStackEntryPoint
{
var wrapper = new AsyncStackWrapper( this.clonedCore );

this.clonedCore.entryPoint = typeof(T);
this.clonedCore.ServeAll();

return wrapper;
}

//todo implement
public IAsyncStackWrapper<TEntry, TIn, TOut> ToGenericAsync<TEntry, TIn, TOut> ( AsyncStackDigest<TEntry, TIn, TOut> digest )
=> throw new NotImplementedException();


public IStackWrapper ToWrapper<T> () where T : IStackEntryPoint
{
var wrapper = new StackWrapper( this.clonedCore );

this.clonedCore.entryPoint = typeof(T);
this.clonedCore.ServeAll();

return wrapper;
}
}
}
25 changes: 25 additions & 0 deletions StackInjector/Core/Cloning/ICloneableCore.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Text;
using StackInjector.Settings;

namespace StackInjector.Core.Cloning
{

/// <summary>
/// Allows for a wrapper to have its core cloned.
/// </summary>
public interface ICloneableCore
{

/// <summary>
/// Clone the core of this wrapper, copying the already existing structure
/// and making instantiation of objects faster.
/// </summary>
/// <param name="settings">if set, overrides the previus core settings.</param>
/// <returns>A generic object allowing conversion of the cloned core</returns>
IClonedCore CloneCore ( StackWrapperSettings settings = null );

}

}
40 changes: 40 additions & 0 deletions StackInjector/Core/Cloning/IClonedCore.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using StackInjector.Wrappers;
using StackInjector.Wrappers.Generic;

namespace StackInjector.Core.Cloning
{
/// <summary>
/// A cloned structure of a wrapper.
/// </summary>
public interface IClonedCore
{

/// <summary>
/// convert this to an <see cref="IStackWrapper"/>
/// </summary>
/// <typeparam name="T">entry point of the new wrapper</typeparam>
/// <returns>the new wrapper</returns>
IStackWrapper ToWrapper<T> () where T : IStackEntryPoint;


/// <summary>
/// convert this to an <see cref="IAsyncStackWrapper"/>
/// </summary>
/// <typeparam name="T">entry point of the new wrapper</typeparam>
/// <returns>the new wrapper</returns>
IAsyncStackWrapper ToAsyncWrapper<T> () where T : IAsyncStackEntryPoint;


/// <summary>
/// convert this to an <see cref="IAsyncStackWrapper{TEntry, TIn, TOut}"/>
/// </summary>
/// <typeparam name="TEntry">entry instantiation poin of the new wrapper</typeparam>
/// <typeparam name="TIn">type of input elements</typeparam>
/// <typeparam name="TOut">type of output elements</typeparam>
/// <param name="digest">action to perform on elements</param>
/// <returns>the new wrapper</returns>
IAsyncStackWrapper<TEntry, TIn, TOut> ToGenericAsync<TEntry, TIn, TOut> ( AsyncStackDigest<TEntry, TIn,TOut> digest );

}

}
Original file line number Diff line number Diff line change
@@ -1,43 +1,42 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace StackInjector
namespace StackInjector.Core
{
/// <summary>
/// Wraps a Stack of dependency-injected classes, and manages an <see cref="IAsyncEnumerable{T}"/> of completed tasks.
/// base interface for all asyncronous stackwrappers.
/// </summary>
public interface IAsyncStackWrapper : IStackWrapperStructure
/// <typeparam name="T">the type tasks will return</typeparam>
public interface IAsyncStackWrapperCore<T> : IStackWrapperCore
{

/// <summary>
/// Used to signal cancellation of every pending job.
/// Used to signal cancellation of every pending task
/// </summary>
public CancellationToken CancelPendingTasksToken { get; }
CancellationToken PendingTasksCancellationToken { get; }


/// <summary>
/// Submit a new object to be elaborated asyncronously in this stack
/// submit new work to this wrapper
/// </summary>
/// <param name="submitted">The object to elaborate</param>
void Submit ( object submitted );

/// <param name="work"></param>
void Submit ( Task<T> work );

/// <summary>
/// The loop you ca use to <c>await foreach</c> tasks in elaboration, converted to the specified type.
/// When the pending tasks list is empty, unless <see cref="IDisposable.Dispose"/> is explocitly called
/// this will wait indefinitively.
/// </summary>
/// <typeparam name="T">Type to cast the object returned by the entry point</typeparam>
/// <exception cref="InvalidCastException"></exception>
/// <returns>An asyncronous enumerable of completed tasks</returns>
IAsyncEnumerable<T> Elaborated<T> ();
IAsyncEnumerable<T> Elaborated ();

/// <summary>
/// check if there are tasks left to elaborate
/// </summary>
/// <returns>true if there are pending tasks</returns>
bool AnyTaskLeft ();

}
}
}
20 changes: 20 additions & 0 deletions StackInjector/Core/IStackWrapperCore.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using StackInjector.Core.Cloning;
using StackInjector.Settings;

namespace StackInjector.Core
{

/// <summary>
/// base interface for all stackwrappers
/// </summary>
public interface IStackWrapperCore : IDisposable, ICloneableCore
{

/// <summary>
/// the settings of this stackwrapper
/// </summary>
ref readonly StackWrapperSettings Settings { get; }

}
}
Loading

0 comments on commit c66cbd9

Please sign in to comment.