< Summary

Information
Class: IceRpc.Slice.Operations.SliceProxyExtensions
Assembly: IceRpc.Slice
File(s): /home/runner/work/icerpc-csharp/icerpc-csharp/src/IceRpc.Slice/Operations/SliceProxyExtensions.cs
Tag: 2300_35243572715
Line coverage
77%
Covered lines: 60
Uncovered lines: 17
Coverable lines: 77
Total lines: 187
Line coverage: 77.9%
Branch coverage
37%
Covered branches: 6
Total branches: 16
Branch coverage: 37.5%
Method coverage
80%
Covered methods: 4
Fully covered methods: 2
Total methods: 5
Method coverage: 80%
Full method coverage: 40%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%210%
InvokeOperationAsync(...)37.5%11865.21%
ReadResponseAsync()100%11100%
InvokeOperationAsync(...)37.5%8883.33%
ReadResponseAsync()100%11100%

File(s)

/home/runner/work/icerpc-csharp/icerpc-csharp/src/IceRpc.Slice/Operations/SliceProxyExtensions.cs

#LineLine coverage
 1// Copyright (c) ZeroC, Inc.
 2
 3using IceRpc.Features;
 4using System.Collections.Immutable;
 5using System.IO.Pipelines;
 6
 7namespace IceRpc.Slice.Operations;
 8
 9/// <summary>Represents a delegate that decodes the return value from a Slice-encoded response.</summary>
 10/// <typeparam name="T">The type of the return value to read.</typeparam>
 11/// <param name="response">The incoming response.</param>
 12/// <param name="request">The outgoing request.</param>
 13/// <param name="sender">The proxy that sent the request.</param>
 14/// <param name="cancellationToken">A cancellation token that receives the cancellation requests.</param>
 15/// <returns>A value task that contains the decoded return value.</returns>
 16public delegate ValueTask<T> ResponseDecodeFunc<T>(
 17    IncomingResponse response,
 18    OutgoingRequest request,
 19    ISliceProxy sender,
 20    CancellationToken cancellationToken);
 21
 22/// <summary>Represents a delegate that decodes the "void" return value from a Slice-encoded response.</summary>
 23/// <param name="response">The incoming response.</param>
 24/// <param name="request">The outgoing request.</param>
 25/// <param name="sender">The proxy that sent the request.</param>
 26/// <param name="cancellationToken">A cancellation token that receives the cancellation requests.</param>
 27/// <returns>A value task.</returns>
 28public delegate ValueTask ResponseDecodeFunc(
 29    IncomingResponse response,
 30    OutgoingRequest request,
 31    ISliceProxy sender,
 32    CancellationToken cancellationToken);
 33
 34/// <summary>Provides extension methods for <see cref="ISliceProxy" /> and generated proxy structs that implement this
 35/// interface.</summary>
 36public static class SliceProxyExtensions
 37{
 038    private static readonly IDictionary<RequestFieldKey, OutgoingFieldValue> _idempotentFields =
 039        new Dictionary<RequestFieldKey, OutgoingFieldValue>
 040        {
 041            [RequestFieldKey.Idempotent] = default
 042        }.ToImmutableDictionary();
 43
 44    /// <summary>Sends a request to a service and decodes the response.</summary>
 45    /// <typeparam name="TProxy">The type of the proxy struct.</typeparam>
 46    /// <typeparam name="T">The response type.</typeparam>
 47    /// <param name="proxy">A proxy to the remote service.</param>
 48    /// <param name="operation">The name of the operation, as specified in Slice.</param>
 49    /// <param name="payload">The payload of the request.</param>
 50    /// <param name="payloadContinuation">The optional payload continuation of the request.</param>
 51    /// <param name="responseDecodeFunc">The decode function for the response payload.</param>
 52    /// <param name="features">The invocation features.</param>
 53    /// <param name="idempotent">When <see langword="true" />, the request is idempotent.</param>
 54    /// <param name="cancellationToken">A cancellation token that receives the cancellation requests.</param>
 55    /// <returns>The operation's return value.</returns>
 56    public static Task<T> InvokeOperationAsync<TProxy, T>(
 57        this TProxy proxy,
 58        string operation,
 59        PipeReader payload,
 60        PipeReader? payloadContinuation,
 61        ResponseDecodeFunc<T> responseDecodeFunc,
 62        IFeatureCollection? features = null,
 63        bool idempotent = false,
 64        CancellationToken cancellationToken = default) where TProxy : struct, ISliceProxy
 3065    {
 3066        if (proxy.Invoker is not IInvoker invoker)
 067        {
 068            payload.Complete();
 069            payloadContinuation?.Complete();
 070            throw new InvalidOperationException("Cannot send requests using a proxy with a null invoker.");
 71        }
 72
 3073        var request = new OutgoingRequest(proxy.ServiceAddress)
 3074        {
 3075            Features = features ?? FeatureCollection.Empty,
 3076            Fields = idempotent ? _idempotentFields : ImmutableDictionary<RequestFieldKey, OutgoingFieldValue>.Empty,
 3077            Operation = operation,
 3078            Payload = payload,
 3079            PayloadContinuation = payloadContinuation
 3080        };
 81
 82        Task<IncomingResponse> responseTask;
 83        try
 3084        {
 3085            responseTask = invoker.InvokeAsync(request, cancellationToken);
 3086        }
 087        catch
 088        {
 089            request.Dispose();
 090            throw;
 91        }
 92
 93        // ReadResponseAsync is responsible for disposing the request
 3094        return ReadResponseAsync(responseTask, request);
 95
 96        async Task<T> ReadResponseAsync(Task<IncomingResponse> responseTask, OutgoingRequest request)
 3097        {
 98            try
 3099            {
 30100                IncomingResponse response = await responseTask.ConfigureAwait(false);
 30101                return await responseDecodeFunc(
 30102                    response,
 30103                    request,
 30104                    proxy,
 30105                    cancellationToken).ConfigureAwait(false);
 106            }
 107            finally
 30108            {
 30109                request.Dispose();
 30110            }
 30111        }
 30112    }
 113
 114    /// <summary>Sends a request to a service and decodes the "void" response.</summary>
 115    /// <typeparam name="TProxy">The type of the proxy struct.</typeparam>
 116    /// <param name="proxy">A proxy for the remote service.</param>
 117    /// <param name="operation">The name of the operation, as specified in Slice.</param>
 118    /// <param name="payload">The payload of the request.</param>
 119    /// <param name="payloadContinuation">The payload continuation of the request.</param>
 120    /// <param name="responseDecodeFunc">The decode function for the response payload.</param>
 121    /// <param name="features">The invocation features.</param>
 122    /// <param name="idempotent">When <see langword="true" />, the request is idempotent.</param>
 123    /// <param name="oneway">When <see langword="true" />, the request is sent one-way and an empty response is returned
 124    /// immediately after sending the request.</param>
 125    /// <param name="cancellationToken">A cancellation token that receives the cancellation requests.</param>
 126    /// <returns>A task that completes when the void response is returned.</returns>
 127    public static Task InvokeOperationAsync<TProxy>(
 128        this TProxy proxy,
 129        string operation,
 130        PipeReader payload,
 131        PipeReader? payloadContinuation,
 132        ResponseDecodeFunc responseDecodeFunc,
 133        IFeatureCollection? features = null,
 134        bool idempotent = false,
 135        bool oneway = false,
 136        CancellationToken cancellationToken = default) where TProxy : struct, ISliceProxy
 21137    {
 21138        if (proxy.Invoker is not IInvoker invoker)
 0139        {
 0140            payload.Complete();
 0141            payloadContinuation?.Complete();
 0142            throw new InvalidOperationException("Cannot send requests using a proxy with a null invoker.");
 143        }
 144
 21145        var request = new OutgoingRequest(proxy.ServiceAddress)
 21146        {
 21147            Features = features ?? FeatureCollection.Empty,
 21148            Fields = idempotent ? _idempotentFields : ImmutableDictionary<RequestFieldKey, OutgoingFieldValue>.Empty,
 21149            IsOneway = oneway,
 21150            Operation = operation,
 21151            Payload = payload,
 21152            PayloadContinuation = payloadContinuation
 21153        };
 154
 155        Task<IncomingResponse> responseTask;
 156        try
 21157        {
 21158            responseTask = invoker.InvokeAsync(request, cancellationToken);
 20159        }
 1160        catch
 1161        {
 1162            request.Dispose();
 1163            throw;
 164        }
 165
 166        // ReadResponseAsync is responsible for disposing the request
 20167        return ReadResponseAsync(responseTask, request);
 168
 169        async Task ReadResponseAsync(Task<IncomingResponse> responseTask, OutgoingRequest request)
 20170        {
 171            try
 20172            {
 20173                IncomingResponse response = await responseTask.ConfigureAwait(false);
 174
 20175                await responseDecodeFunc(
 20176                    response,
 20177                    request,
 20178                    proxy,
 20179                    cancellationToken).ConfigureAwait(false);
 20180            }
 181            finally
 20182            {
 20183                request.Dispose();
 20184            }
 20185        }
 20186    }
 187}