-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b7c87e7
commit 5c4998c
Showing
37 changed files
with
1,016 additions
and
317 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,94 @@ | ||
using Hyperbee.Pipeline.Context; | ||
using Hyperbee.Pipeline.Extensions.Implementation; | ||
using System.Linq.Expressions; | ||
using Hyperbee.Pipeline.Context; | ||
|
||
using static System.Linq.Expressions.Expression; | ||
using static Hyperbee.Expressions.AsyncExpression; | ||
|
||
|
||
namespace Hyperbee.Pipeline.Binders.Abstractions; | ||
|
||
internal abstract class Binder<TInput, TOutput> | ||
{ | ||
protected FunctionAsync<TInput, TOutput> Pipeline { get; } | ||
protected Action<IPipelineContext> Configure { get; } | ||
protected Expression<FunctionAsync<TInput, TOutput>> Pipeline { get; } | ||
protected Expression<Action<IPipelineContext>> Configure { get; } | ||
|
||
protected Binder( FunctionAsync<TInput, TOutput> function, Action<IPipelineContext> configure ) | ||
protected Binder( Expression<FunctionAsync<TInput, TOutput>> function, Expression<Action<IPipelineContext>> configure ) | ||
{ | ||
Pipeline = function; | ||
Configure = configure; | ||
} | ||
|
||
protected virtual async Task<(TOutput Result, bool Canceled)> ProcessPipelineAsync( IPipelineContext context, TInput argument ) | ||
// protected virtual Task<(TOutput Result, bool Canceled)> ProcessPipelineAsync( IPipelineContext context, TInput argument ) | ||
// { | ||
// var result = await Pipeline( context, argument ).ConfigureAwait( false ); | ||
// | ||
// var contextControl = (IPipelineContextControl) context; | ||
// var canceled = contextControl.HandleCancellationRequested( result ); | ||
// | ||
// return (canceled ? default : result, canceled); | ||
// } | ||
|
||
protected virtual Expression ProcessPipelineAsync( ParameterExpression context, ParameterExpression argument ) | ||
{ | ||
var result = await Pipeline( context, argument ).ConfigureAwait( false ); | ||
var tupleCtor = typeof(ValueTuple<TOutput, bool>).GetConstructor( [typeof(TOutput), typeof(bool)] )!; | ||
|
||
var resultVariable = Variable( typeof( TOutput ), "result" ); | ||
var canceledVariable = Variable( typeof( bool ), "canceled" ); | ||
|
||
var contextControl = Convert( context , typeof( IPipelineContextControl ) ); | ||
|
||
var contextControl = (IPipelineContextControl) context; | ||
var canceled = contextControl.HandleCancellationRequested( result ); | ||
var body = BlockAsync( | ||
[resultVariable, canceledVariable], | ||
Assign( resultVariable, Await( Invoke( Pipeline, context, argument ), configureAwait: false ) ), | ||
Assign( canceledVariable, HandleCancellationRequested( contextControl, resultVariable ) ), | ||
|
||
return (canceled ? default : result, canceled); | ||
Condition( | ||
canceledVariable, | ||
New( tupleCtor, Default( typeof( TOutput ) ), canceledVariable ), | ||
New( tupleCtor, resultVariable, canceledVariable ) | ||
) | ||
); | ||
|
||
return body; | ||
} | ||
|
||
|
||
|
||
/* | ||
public static bool HandleCancellationRequested<TOutput>( this IPipelineContextControl control, TOutput value ) | ||
{ | ||
if ( !control.CancellationToken.IsCancellationRequested ) | ||
return false; | ||
if ( !control.HasCancellationValue ) | ||
control.CancellationValue = value; | ||
return true; | ||
} | ||
*/ | ||
|
||
|
||
private Expression HandleCancellationRequested( Expression contextControl, Expression resultVariable ) | ||
{ | ||
var hasCancellationValue = Property( contextControl, "HasCancellationValue" ); | ||
var cancellationTokenProperty = Property( contextControl, "CancellationToken" ); | ||
var cancellationValueProperty = Property( contextControl, "CancellationValue" ); | ||
|
||
var conditionalExpression = Condition( | ||
Not( Property( cancellationTokenProperty, "IsCancellationRequested" ) ), | ||
Constant( false ), | ||
|
||
Block( | ||
IfThen( | ||
Not( hasCancellationValue ), | ||
Assign( cancellationValueProperty, resultVariable ) | ||
), | ||
// After the assignment, return true | ||
Constant( true ) | ||
) | ||
); | ||
|
||
return conditionalExpression; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
48 changes: 34 additions & 14 deletions
48
src/Hyperbee.Pipeline/Binders/Abstractions/ConditionalBlockBinder.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,51 @@ | ||
using System.Runtime.CompilerServices; | ||
using System.Linq.Expressions; | ||
using Hyperbee.Pipeline.Context; | ||
using static System.Linq.Expressions.Expression; | ||
|
||
namespace Hyperbee.Pipeline.Binders.Abstractions; | ||
|
||
internal abstract class ConditionalBlockBinder<TInput, TOutput> : BlockBinder<TInput, TOutput> | ||
{ | ||
protected Function<TOutput, bool> Condition { get; } | ||
protected Expression<Function<TOutput, bool>> Condition { get; } | ||
|
||
protected ConditionalBlockBinder( Function<TOutput, bool> condition, FunctionAsync<TInput, TOutput> function, Action<IPipelineContext> configure ) | ||
protected ConditionalBlockBinder( Expression<Function<TOutput, bool>> condition, Expression<FunctionAsync<TInput, TOutput>> function, Expression<Action<IPipelineContext>> configure ) | ||
: base( function, configure ) | ||
{ | ||
Condition = condition; | ||
} | ||
|
||
protected override async Task<TNext> ProcessBlockAsync<TArgument, TNext>( FunctionAsync<TArgument, TNext> blockFunction, IPipelineContext context, TArgument nextArgument ) | ||
{ | ||
if ( Condition != null && !Condition( context, CastTypeArg<TArgument, TOutput>( nextArgument ) ) ) | ||
{ | ||
return CastTypeArg<TArgument, TNext>( nextArgument ); | ||
} | ||
// protected override async Task<TNext> ProcessBlockAsync<TArgument, TNext>( FunctionAsync<TArgument, TNext> blockFunction, IPipelineContext context, TArgument nextArgument ) | ||
// { | ||
// if ( Condition != null && !Condition( context, CastTypeArg<TArgument, TOutput>( nextArgument ) ) ) | ||
// { | ||
// return CastTypeArg<TArgument, TNext>( nextArgument ); | ||
// } | ||
// | ||
// return await base.ProcessBlockAsync( blockFunction, context, nextArgument ).ConfigureAwait( false ); | ||
// } | ||
|
||
return await base.ProcessBlockAsync( blockFunction, context, nextArgument ).ConfigureAwait( false ); | ||
} | ||
// [MethodImpl( MethodImplOptions.AggressiveInlining )] | ||
// private static TResult CastTypeArg<TType, TResult>( TType input ) | ||
// { | ||
// return (TResult) (object) input; | ||
// } | ||
|
||
[MethodImpl( MethodImplOptions.AggressiveInlining )] | ||
private static TResult CastTypeArg<TType, TResult>( TType input ) | ||
protected override Expression<Task<TNext>> ProcessBlockAsync<TArgument, TNext>( | ||
Expression<FunctionAsync<TArgument, TNext>> blockFunction, | ||
ParameterExpression context, | ||
Expression nextArgument ) | ||
{ | ||
return (TResult) (object) input; | ||
if ( Condition == null ) | ||
return base.ProcessBlockAsync( blockFunction, context, nextArgument ); | ||
|
||
var nextArgumentExpression = Constant( nextArgument ); | ||
|
||
return Lambda<Task<TNext>>( | ||
IfThenElse( | ||
Not( Invoke( Condition, Constant( context ), | ||
Convert( Convert( nextArgumentExpression, typeof(object) ), typeof(TOutput) ) ) ), | ||
Convert( Convert( Constant( nextArgument ), typeof(object) ), typeof(TNext) ), | ||
base.ProcessBlockAsync( blockFunction, context, nextArgument ) | ||
) ); | ||
} | ||
} |
121 changes: 107 additions & 14 deletions
121
src/Hyperbee.Pipeline/Binders/Abstractions/StatementBinder.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,124 @@ | ||
using Hyperbee.Pipeline.Context; | ||
using Hyperbee.Pipeline.Extensions.Implementation; | ||
using System.Linq.Expressions; | ||
using Hyperbee.Pipeline.Context; | ||
using static System.Linq.Expressions.Expression; | ||
using static Hyperbee.Expressions.AsyncExpression; | ||
|
||
namespace Hyperbee.Pipeline.Binders.Abstractions; | ||
|
||
internal abstract class StatementBinder<TInput, TOutput> : Binder<TInput, TOutput> | ||
{ | ||
protected MiddlewareAsync<object, object> Middleware { get; } | ||
protected Expression<MiddlewareAsync<object, object>> Middleware { get; } | ||
|
||
protected StatementBinder( FunctionAsync<TInput, TOutput> function, MiddlewareAsync<object, object> middleware, Action<IPipelineContext> configure ) | ||
protected StatementBinder( Expression<FunctionAsync<TInput, TOutput>> function, Expression<MiddlewareAsync<object, object>> middleware, Expression<Action<IPipelineContext>> configure ) | ||
: base( function, configure ) | ||
{ | ||
Middleware = middleware; | ||
} | ||
|
||
protected virtual async Task<TNext> ProcessStatementAsync<TNext>( FunctionAsync<TOutput, TNext> nextFunction, IPipelineContext context, TOutput nextArgument, string frameName ) | ||
// protected MiddlewareAsync<object, object> Middleware1 { get; } | ||
// protected virtual async Task<TNext> ProcessStatementAsync<TNext>( FunctionAsync<TOutput, TNext> nextFunction, IPipelineContext context, TOutput nextArgument, string frameName ) | ||
// { | ||
// var contextControl = (IPipelineContextControl) context; | ||
// | ||
// using var _ = contextControl.CreateFrame( context, Configure, frameName ); | ||
// | ||
// if ( Middleware1 == null ) | ||
// return await nextFunction( context, nextArgument ).ConfigureAwait( false ); | ||
// | ||
// return (TNext) await Middleware1( | ||
// context, | ||
// nextArgument, | ||
// async ( context1, argument1 ) => await nextFunction( context1, (TOutput) argument1 ).ConfigureAwait( false ) | ||
// ).ConfigureAwait( false ); | ||
// } | ||
|
||
protected virtual Expression ProcessStatementAsync<TNext>( Expression<FunctionAsync<TOutput, TNext>> nextFunction, | ||
ParameterExpression context, Expression nextArgument, string frameName ) | ||
{ | ||
var contextControl = (IPipelineContextControl) context; | ||
// if ( Middleware == null ) | ||
// return await nextFunction( context, nextArgument ).ConfigureAwait( false ); | ||
if ( Middleware == null ) | ||
{ | ||
return Invoke( nextFunction, context, nextArgument ); //, configureAwait: false ); | ||
|
||
using var _ = contextControl.CreateFrame( context, Configure, frameName ); | ||
//using var _ = contextControl.CreateFrame( context, Configure, frameName ); | ||
// return CreateFrameExpression( | ||
// Convert( context, typeof(IPipelineContextControl) ), | ||
// context, | ||
// Configure, | ||
// Await( Invoke( nextFunction, context, nextArgument ), configureAwait: false ), | ||
// frameName ); | ||
} | ||
|
||
if ( Middleware == null ) | ||
return await nextFunction( context, nextArgument ).ConfigureAwait( false ); | ||
// async ( context1, argument1 ) => await nextFunction( context1, (TOutput) argument1 ).ConfigureAwait( false ) | ||
var context1 = Parameter( typeof(IPipelineContext), "context1" ); | ||
var argument1 = Parameter( typeof(object), "argument1" ); | ||
|
||
var middlewareNext = Lambda<FunctionAsync<object, object>>( | ||
BlockAsync( | ||
Convert( Await( | ||
Invoke( nextFunction, context1, Convert( argument1, typeof(TOutput) ) ), | ||
configureAwait: false ), | ||
typeof(object) ) | ||
), | ||
parameters: [context1, argument1] | ||
); | ||
|
||
// return (TNext) await Middleware( | ||
// context, | ||
// nextArgument, | ||
// middlewareNext | ||
// ).ConfigureAwait( false ); | ||
return | ||
//using var _ = contextControl.CreateFrame( context, Configure, frameName ); | ||
// CreateFrameExpression( | ||
// Convert( Constant( context ), typeof(IPipelineContextControl) ), | ||
// context, | ||
// Configure, | ||
BlockAsync( | ||
Convert( | ||
Await( | ||
Invoke( Middleware, | ||
context, | ||
nextArgument, | ||
middlewareNext | ||
), | ||
configureAwait: false ), | ||
typeof(TNext) )); //, | ||
// frameName ); //); | ||
} | ||
|
||
public static Expression CreateFrameExpression( | ||
Expression controlParam, | ||
Expression contextParam, | ||
Expression<Action<IPipelineContext>> config, | ||
Expression body, | ||
string defaultName = null | ||
) | ||
{ | ||
var nameVariable = Variable( typeof( string ), "originalName" ); | ||
var idVariable = Variable( typeof( int ), "originalId" ); | ||
|
||
var idProperty = Property( controlParam, "Id" ); | ||
var nameProperty = Property( controlParam, "Name" ); | ||
|
||
return (TNext) await Middleware( | ||
context, | ||
nextArgument, | ||
async ( context1, argument1 ) => await nextFunction( context1, (TOutput) argument1 ).ConfigureAwait( false ) | ||
).ConfigureAwait( false ); | ||
return BlockAsync( | ||
[nameVariable, idVariable], | ||
Assign( idVariable, idProperty ), | ||
Assign( nameVariable, nameProperty ), | ||
TryFinally( | ||
Block( | ||
Assign( idProperty, Call( controlParam, "GetNextId", Type.EmptyTypes ) ), | ||
Assign( nameProperty, Constant( defaultName ) ), | ||
config != null | ||
? Invoke( config, contextParam ) | ||
: Empty(), | ||
body | ||
), | ||
Block( | ||
Assign( idProperty, idVariable ), | ||
Assign( nameProperty, nameVariable ) | ||
) ) | ||
); | ||
} | ||
} |
Oops, something went wrong.