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 #55 from JacopoWolf/rel/2.0
Browse files Browse the repository at this point in the history
Release 2.0.0
  • Loading branch information
JacopoWolf authored May 18, 2020
2 parents c7b9de1 + 5167621 commit 2138484
Show file tree
Hide file tree
Showing 45 changed files with 998 additions and 524 deletions.
6 changes: 3 additions & 3 deletions StackInjector/Attributes/ServedAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ public sealed class ServedAttribute : Attribute
/// </summary>
public double TargetVersion { get; set; } = 0.0;


/// <summary>
/// targetting version method
/// <para>How the specified TargetVersion should be found.</para>
/// <para>could be overriden by <see cref="StackWrapperSettings"/></para>
/// </summary>
public ServedVersionTargetingMethod? TargetingMethod { get; set; } = null;

}

}
}
17 changes: 5 additions & 12 deletions StackInjector/Attributes/ServiceAttribute.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using StackInjector.Settings;

namespace StackInjector.Attributes
{
Expand All @@ -8,23 +9,15 @@ namespace StackInjector.Attributes
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
public sealed class ServiceAttribute : Attribute
{

/// <summary>
/// The version of this service implementation
/// </summary>
public double Version { get; set; } = -0.0;


/// <summary>
/// Indicates if the framework should use only one instance of this service across all clients.
/// Might be ignored by the settings.
/// How properties and fields of this service should be served
/// </summary>
public bool ReuseInstance { get; set; } = false;

/// <summary>
/// if set to true, members of this object will not be served even if marked as such
/// </summary>
public bool DoNotServeMembers { get; set; } = false;

public ServingMethods Serving { get; set; } = Injector.Defaults.ServingMethod;
}
}

}
1 change: 1 addition & 0 deletions StackInjector/Behaviours/IInstancesHolder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

namespace StackInjector.Behaviours
{
//? should this be documented internally
internal interface IInstancesHolder
{
IEnumerable<object> OfType ( Type type );
Expand Down
3 changes: 1 addition & 2 deletions StackInjector/Behaviours/SingleInstanceHolder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ public bool ContainsType ( Type type )
public IEnumerable<Type> GetAllTypes ()
=> this.Keys;



}

}
68 changes: 68 additions & 0 deletions StackInjector/Core/AsyncStackWrapperCore.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace StackInjector.Core
{
internal abstract partial class AsyncStackWrapperCore<T> : StackWrapperCore, 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 ( InjectionCore 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
}

}
96 changes: 96 additions & 0 deletions StackInjector/Core/AsyncStackWrapperCore.logic.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using StackInjector.Settings;

namespace StackInjector.Core
{
internal abstract partial class AsyncStackWrapperCore<T>
{
// call the semaphore
protected internal void ReleaseListAwaiter ()
{
this.emptyListAwaiter.Release();
}

public void Submit ( Task<T> work )
{
lock( this.listAccessLock )
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();
}

public async IAsyncEnumerable<T> Elaborated ()
{
while( !this.cancelPendingTasksSource.IsCancellationRequested )
{
// avoid deadlocks
if( this.AnyTaskLeft() )
{
var completed = await Task.WhenAny(this.tasks).ConfigureAwait(false);

lock( this.listAccessLock )
this.tasks.Remove(completed);

yield return completed.Result;
continue;
}
else
{
if( await this.OnNoTasksLeft().ConfigureAwait(true) )
break;
}
}
}

// true if outher loop is to break
private async Task<bool> OnNoTasksLeft ()
{
// to not repeat code
Task listAwaiter ()
=> this.emptyListAwaiter.WaitAsync();


switch( this.Settings.asyncWaitingMethod )
{

case AsyncWaitingMethod.Exit:
default:

return true;


case AsyncWaitingMethod.Wait:

// wait for a signal of the list not being empty anymore
await listAwaiter().ConfigureAwait(true);
return false;


case AsyncWaitingMethod.Timeout:
var list = listAwaiter();
var timeout = Task.Delay( this.Settings.asyncWaitTime );

// if the timeout elapses first, then stop waiting
return (await Task.WhenAny(list, timeout).ConfigureAwait(true)) == timeout;
}
}


public bool AnyTaskCompleted ()
=>
this.tasks.Any(t => t.IsCompleted);


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

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

private readonly InjectionCore clonedCore;

internal ClonedCore ( InjectionCore 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;
}

public IAsyncStackWrapper<TEntry, TIn, TOut> ToAsyncWrapper<TEntry, TIn, TOut> ( AsyncStackDigest<TEntry, TIn, TOut> digest )
{
var wrapper = new AsyncStackWrapper<TEntry,TIn,TOut>( this.clonedCore );

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

return wrapper;
}


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

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

return wrapper;
}
}
}
22 changes: 22 additions & 0 deletions StackInjector/Core/Cloning/ICloneableCore.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
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> ToAsyncWrapper<TEntry, TIn, TOut> ( AsyncStackDigest<TEntry, TIn, TOut> digest );

}

}
Loading

0 comments on commit 2138484

Please sign in to comment.