Skip to content

Commit 5c970a9

Browse files
authored
Create Release 1.2.0 (#36)
* [FEATURE]: Binder base (#31) * Implement abstract binders * Refactor existing binders to use abstract base --------- Co-authored-by: Brenton Farmer <brent.farmer@wagglebee.net> * [FEATURE]: Implement dedicated builder and binder for CallIfBlock and PipeIfBlock (#33) * Factor CallIfBlock* and PipeIfBlock* into their own builders and binders. --------- Co-authored-by: Brenton Farmer <brent.farmer@wagglebee.net> * [FEATURE]: Improve builder pattern (#35) * Refactor builders to eliminate reliance on partial interfaces and classes --------- Co-authored-by: Brenton Farmer <brent.farmer@wagglebee.net> * Fix footer * Previous version was 'v1.1.6'. Version now 'v1.2.0'. --------- Co-authored-by: Brenton Farmer <brent.farmer@wagglebee.net>
1 parent b11d002 commit 5c970a9

37 files changed

+766
-506
lines changed

Directory.Build.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
<!-- Solution version numbers -->
33
<PropertyGroup>
44
<MajorVersion>1</MajorVersion>
5-
<MinorVersion>1</MinorVersion>
6-
<PatchVersion>6</PatchVersion>
5+
<MinorVersion>2</MinorVersion>
6+
<PatchVersion>0</PatchVersion>
77
</PropertyGroup>
88
<!-- Disable automatic package publishing -->
99
<PropertyGroup>

Hyperbee.Pipeline.sln

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
77
ProjectSection(SolutionItems) = preProject
88
Directory.Build.props = Directory.Build.props
99
Directory.Build.targets = Directory.Build.targets
10-
LICENSE = LICENSE
11-
README.md = README.md
1210
solution-helper.psm1 = solution-helper.psm1
1311
EndProjectSection
1412
EndProject
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
<footer class="site-footer">
2-
Hyperbee Json Docs
2+
Hyperbee Pipeline Docs
33
</footer>

docs/syntax.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ var count = 0;
101101
var command = PipelineFactory
102102
.Start<string>()
103103
.Pipe( ( ctx, arg ) => arg.Split( ' ' ) )
104-
.ForEach<string>( builder => builder
104+
.ForEach().Type<string>( builder => builder
105105
.Pipe( ( ctx, arg ) => count += 10 )
106106
)
107107
.Pipe( ( ctx, arg ) => count += 5 )
@@ -117,6 +117,21 @@ Assert.AreEqual( count, 25 );
117117
`Reduce` and `ReduceAync` allow you to transform an enumerable pipeline input to a single value. You can specify a reducer function
118118
that defines how the elements should be combined, and a builder function that creates the pipeline for processing the elements.### Cancel
119119

120+
```csharp
121+
var command = PipelineFactory
122+
.Start<string>()
123+
.Pipe( ( ctx, arg ) => arg.Split( ' ' ) )
124+
.Reduce().Type<string, int>( ( aggregate, value ) => aggregate + value, builder => builder
125+
.Pipe( ( ctx, arg ) => int.Parse( arg ) + 10 )
126+
)
127+
.Pipe( ( ctx, arg ) => arg + 5 )
128+
.Build();
129+
130+
var result = await command( new PipelineContext(), "1 2 3 4 5" );
131+
132+
Assert.AreEqual( result, 70 );
133+
```
134+
120135
### WaitAll
121136

122137
`WaitAll` allows you to wait for concurrent pipelines to complete before continuing. You can specify a set of builders that create
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using Hyperbee.Pipeline.Context;
2+
using Hyperbee.Pipeline.Extensions.Implementation;
3+
4+
namespace Hyperbee.Pipeline.Binders.Abstractions;
5+
6+
internal abstract class Binder<TInput, TOutput>
7+
{
8+
protected FunctionAsync<TInput, TOutput> Pipeline { get; }
9+
protected Action<IPipelineContext> Configure { get; }
10+
11+
protected Binder( FunctionAsync<TInput, TOutput> function, Action<IPipelineContext> configure )
12+
{
13+
Pipeline = function;
14+
Configure = configure;
15+
}
16+
17+
protected virtual async Task<(TOutput Result, bool Canceled)> ProcessPipelineAsync( IPipelineContext context, TInput argument )
18+
{
19+
var result = await Pipeline( context, argument ).ConfigureAwait( false );
20+
21+
var contextControl = (IPipelineContextControl) context;
22+
var canceled = contextControl.HandleCancellationRequested( result );
23+
24+
return (canceled ? default : result, canceled);
25+
}
26+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using Hyperbee.Pipeline.Context;
2+
3+
namespace Hyperbee.Pipeline.Binders.Abstractions;
4+
5+
internal abstract class BlockBinder<TInput, TOutput> : Binder<TInput, TOutput>
6+
{
7+
protected BlockBinder( FunctionAsync<TInput, TOutput> function, Action<IPipelineContext> configure )
8+
: base( function, configure )
9+
{
10+
}
11+
12+
// Using TArgument instead of TOutput allows more capabilities for special
13+
// use cases where the next argument is not the same as the output type
14+
// like ReduceBlockBinder and ForEachBlockBinder
15+
16+
protected virtual async Task<TNext> ProcessBlockAsync<TArgument, TNext>( FunctionAsync<TArgument, TNext> blockFunction, IPipelineContext context, TArgument nextArgument )
17+
{
18+
return await blockFunction( context, nextArgument ).ConfigureAwait( false );
19+
}
20+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System.Runtime.CompilerServices;
2+
using Hyperbee.Pipeline.Context;
3+
4+
namespace Hyperbee.Pipeline.Binders.Abstractions;
5+
6+
internal abstract class ConditionalBlockBinder<TInput, TOutput> : BlockBinder<TInput, TOutput>
7+
{
8+
protected Function<TOutput, bool> Condition { get; }
9+
10+
protected ConditionalBlockBinder( Function<TOutput, bool> condition, FunctionAsync<TInput, TOutput> function, Action<IPipelineContext> configure )
11+
: base( function, configure )
12+
{
13+
Condition = condition;
14+
}
15+
16+
protected override async Task<TNext> ProcessBlockAsync<TArgument, TNext>( FunctionAsync<TArgument, TNext> blockFunction, IPipelineContext context, TArgument nextArgument )
17+
{
18+
if ( Condition != null && !Condition( context, CastTypeArg<TArgument, TOutput>( nextArgument ) ) )
19+
{
20+
return CastTypeArg<TArgument, TNext>( nextArgument );
21+
}
22+
23+
return await base.ProcessBlockAsync( blockFunction, context, nextArgument ).ConfigureAwait( false );
24+
}
25+
26+
[MethodImpl( MethodImplOptions.AggressiveInlining )]
27+
private static TResult CastTypeArg<TType, TResult>( TType input )
28+
{
29+
return (TResult) (object) input;
30+
}
31+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using Hyperbee.Pipeline.Context;
2+
using Hyperbee.Pipeline.Extensions.Implementation;
3+
4+
namespace Hyperbee.Pipeline.Binders.Abstractions;
5+
6+
internal abstract class StatementBinder<TInput, TOutput> : Binder<TInput, TOutput>
7+
{
8+
protected MiddlewareAsync<object, object> Middleware { get; }
9+
10+
protected StatementBinder( FunctionAsync<TInput, TOutput> function, MiddlewareAsync<object, object> middleware, Action<IPipelineContext> configure )
11+
: base( function, configure )
12+
{
13+
Middleware = middleware;
14+
}
15+
16+
protected virtual async Task<TNext> ProcessStatementAsync<TNext>( FunctionAsync<TOutput, TNext> nextFunction, IPipelineContext context, TOutput nextArgument, string frameName )
17+
{
18+
var contextControl = (IPipelineContextControl) context;
19+
20+
using var _ = contextControl.CreateFrame( context, Configure, frameName );
21+
22+
if ( Middleware == null )
23+
return await nextFunction( context, nextArgument ).ConfigureAwait( false );
24+
25+
return (TNext) await Middleware(
26+
context,
27+
nextArgument,
28+
async ( context1, argument1 ) => await nextFunction( context1, (TOutput) argument1 ).ConfigureAwait( false )
29+
).ConfigureAwait( false );
30+
}
31+
}

src/Hyperbee.Pipeline/Binders/CallBlockBinder.cs

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,24 @@
1-
namespace Hyperbee.Pipeline.Binders;
1+
using Hyperbee.Pipeline.Binders.Abstractions;
22

3-
internal class CallBlockBinder<TInput, TOutput>
4-
{
5-
private FunctionAsync<TInput, TOutput> Pipeline { get; }
6-
private Function<TOutput, bool> Condition { get; }
3+
namespace Hyperbee.Pipeline.Binders;
74

5+
internal class CallBlockBinder<TInput, TOutput> : BlockBinder<TInput, TOutput>
6+
{
87
public CallBlockBinder( FunctionAsync<TInput, TOutput> function )
9-
: this( null, function )
10-
{
11-
}
12-
13-
public CallBlockBinder( Function<TOutput, bool> condition, FunctionAsync<TInput, TOutput> function )
8+
: base( function, default )
149
{
15-
Condition = condition;
16-
Pipeline = function;
1710
}
1811

1912
public FunctionAsync<TInput, TOutput> Bind( FunctionAsync<TOutput, object> next )
2013
{
2114
return async ( context, argument ) =>
2215
{
23-
var nextArgument = await Pipeline( context, argument ).ConfigureAwait( false );
16+
var (nextArgument, canceled) = await ProcessPipelineAsync( context, argument ).ConfigureAwait( false );
2417

25-
if ( Condition == null || Condition( context, nextArgument ) )
26-
await next( context, nextArgument ).ConfigureAwait( false );
18+
if ( canceled )
19+
return default;
2720

21+
await ProcessBlockAsync( next, context, nextArgument ).ConfigureAwait( false );
2822
return nextArgument;
2923
};
3024
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using Hyperbee.Pipeline.Binders.Abstractions;
2+
3+
namespace Hyperbee.Pipeline.Binders;
4+
5+
internal class CallIfBlockBinder<TInput, TOutput> : ConditionalBlockBinder<TInput, TOutput>
6+
{
7+
public CallIfBlockBinder( Function<TOutput, bool> condition, FunctionAsync<TInput, TOutput> function )
8+
: base( condition, function, default )
9+
{
10+
}
11+
12+
public FunctionAsync<TInput, TOutput> Bind( FunctionAsync<TOutput, object> next )
13+
{
14+
return async ( context, argument ) =>
15+
{
16+
var (nextArgument, canceled) = await ProcessPipelineAsync( context, argument ).ConfigureAwait( false );
17+
18+
if ( canceled )
19+
return default;
20+
21+
await ProcessBlockAsync( next, context, nextArgument ).ConfigureAwait( false );
22+
return nextArgument;
23+
};
24+
}
25+
}

0 commit comments

Comments
 (0)