< Summary

Information
Class: IceRpc.Pipeline
Assembly: IceRpc
File(s): /home/runner/work/icerpc-csharp/icerpc-csharp/src/IceRpc/Pipeline.cs
Tag: 275_13775359185
Line coverage
83%
Covered lines: 26
Uncovered lines: 5
Coverable lines: 31
Total lines: 89
Line coverage: 83.8%
Branch coverage
75%
Covered branches: 6
Total branches: 8
Branch coverage: 75%
Method coverage
100%
Covered methods: 5
Total methods: 5
Method coverage: 100%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor()100%11100%
InvokeAsync(...)100%11100%
Into(...)50%2.09271.42%
Use(...)100%22100%
CreateInvokerPipeline()75%4.2476.92%

File(s)

/home/runner/work/icerpc-csharp/icerpc-csharp/src/IceRpc/Pipeline.cs

#LineLine coverage
 1// Copyright (c) ZeroC, Inc.
 2
 3namespace IceRpc;
 4
 5/// <summary>A pipeline is an invoker created from zero or more interceptors installed by calling
 6/// <see cref="Use(Func{IInvoker, IInvoker})"/>, and a final invoker installed by calling <see cref="Into(IInvoker)"/>.
 7/// Requests using this pipeline flow through the interceptors into the final invoker. The final invoker then sends the
 8/// request over a connection.</summary>
 9/// <example>
 10/// The following example demonstrates how an application would typically create the pipeline and use it as the invoker
 11/// for a Slice proxy or Protobuf client.
 12/// <code source="../../docfx/examples/IceRpc.Examples/PipelineExamples.cs" region="CreatingThePipeline" lang="csharp" /
 13/// Create a Slice proxy that uses the pipeline as its invoker.
 14/// <code source="../../docfx/examples/IceRpc.Examples/PipelineExamples.cs" region="CreateSliceProxy" lang="csharp" />
 15/// Create a Protobuf client that uses the pipeline as its invoker.
 16/// <code source="../../docfx/examples/IceRpc.Examples/PipelineExamples.cs" region="CreateProtobufClient" lang="csharp" 
 17/// You can easily create your own interceptor and add it to the pipeline. The next example shows how you can create an
 18/// interceptor using an <see cref="InlineInvoker"/> and add it to the pipeline with
 19/// <see cref="Use(Func{IInvoker, IInvoker})"/>.
 20/// <code source="../../docfx/examples/IceRpc.Examples/PipelineExamples.cs" region="UseWithInlineInterceptor" lang="csha
 21/// </example>
 22/// <seealso cref="Router"/>
 23/// <seealso href="https://docs.icerpc.dev/icerpc/invocation/invocation-pipeline"/>
 24public sealed class Pipeline : IInvoker
 25{
 3526    private readonly Stack<Func<IInvoker, IInvoker>> _interceptorStack = new();
 27    private readonly Lazy<IInvoker> _invoker;
 28    private IInvoker? _lastInvoker;
 29
 30    /// <summary>Constructs a pipeline.</summary>
 7031    public Pipeline() => _invoker = new Lazy<IInvoker>(CreateInvokerPipeline);
 32
 33    /// <inheritdoc/>
 34    public Task<IncomingResponse> InvokeAsync(OutgoingRequest request, CancellationToken cancellationToken = default) =>
 11435        _invoker.Value.InvokeAsync(request, cancellationToken);
 36
 37    /// <summary>Sets the last invoker of this pipeline. The pipeline flows into this invoker.</summary>
 38    /// <param name="lastInvoker">The last invoker.</param>
 39    /// <returns>This pipeline.</returns>
 40    /// <exception cref="InvalidOperationException">Thrown if this method is called after the first call to
 41    /// <see cref="InvokeAsync" />.</exception>
 42    public Pipeline Into(IInvoker lastInvoker)
 3643    {
 3644        if (_invoker.IsValueCreated)
 045        {
 046            throw new InvalidOperationException($"{nameof(Into)} must be called before {nameof(InvokeAsync)}.");
 47        }
 48
 3649        _lastInvoker = lastInvoker;
 3650        return this;
 3651    }
 52
 53    /// <summary>Installs an interceptor at the end of the pipeline.</summary>
 54    /// <param name="interceptor">The interceptor to install.</param>
 55    /// <returns>This pipeline.</returns>
 56    /// <exception cref="InvalidOperationException">Thrown if this method is called after the first call to
 57    /// <see cref="InvokeAsync" />.</exception>
 58    public Pipeline Use(Func<IInvoker, IInvoker> interceptor)
 4659    {
 4660        if (_invoker.IsValueCreated)
 261        {
 262            throw new InvalidOperationException(
 263                $"The interceptors must be installed before the first call to {nameof(InvokeAsync)}.");
 64        }
 4465        _interceptorStack.Push(interceptor);
 4466        return this;
 4467    }
 68
 69    /// <summary>Creates a pipeline of invokers by starting with the last invoker installed. This method is called
 70    /// by the first call to <see cref="InvokeAsync" />.</summary>
 71    /// <returns>The pipeline of invokers.</returns>
 72    private IInvoker CreateInvokerPipeline()
 3473    {
 3474        if (_lastInvoker is null)
 075        {
 076            throw new InvalidOperationException(
 077                $"{nameof(Into)} must be called before calling {nameof(InvokeAsync)} on a Pipeline.");
 78        }
 79
 3480        IInvoker pipeline = _lastInvoker;
 81
 19082        foreach (Func<IInvoker, IInvoker> interceptor in _interceptorStack)
 4483        {
 4484            pipeline = interceptor(pipeline);
 4485        }
 3486        _interceptorStack.Clear(); // we no longer need these functions
 3487        return pipeline;
 3488    }
 89}