< 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: 1321_24790053727
Line coverage
82%
Covered lines: 60
Uncovered lines: 13
Coverable lines: 73
Total lines: 183
Line coverage: 82.1%
Branch coverage
66%
Covered branches: 8
Total branches: 12
Branch coverage: 66.6%
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(...)66.66%7671.42%
ReadResponseAsync()100%11100%
InvokeOperationAsync(...)66.66%6690.9%
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
 2265    {
 2266        if (proxy.Invoker is not IInvoker invoker)
 067        {
 068            throw new InvalidOperationException("Cannot send requests using a proxy with a null invoker.");
 69        }
 70
 2271        var request = new OutgoingRequest(proxy.ServiceAddress)
 2272        {
 2273            Features = features ?? FeatureCollection.Empty,
 2274            Fields = idempotent ? _idempotentFields : ImmutableDictionary<RequestFieldKey, OutgoingFieldValue>.Empty,
 2275            Operation = operation,
 2276            Payload = payload,
 2277            PayloadContinuation = payloadContinuation
 2278        };
 79
 80        Task<IncomingResponse> responseTask;
 81        try
 2282        {
 2283            responseTask = invoker.InvokeAsync(request, cancellationToken);
 2284        }
 085        catch
 086        {
 087            request.Dispose();
 088            throw;
 89        }
 90
 91        // ReadResponseAsync is responsible for disposing the request
 2292        return ReadResponseAsync(responseTask, request);
 93
 94        async Task<T> ReadResponseAsync(Task<IncomingResponse> responseTask, OutgoingRequest request)
 2295        {
 96            try
 2297            {
 2298                IncomingResponse response = await responseTask.ConfigureAwait(false);
 2299                return await responseDecodeFunc(
 22100                    response,
 22101                    request,
 22102                    proxy,
 22103                    cancellationToken).ConfigureAwait(false);
 104            }
 105            finally
 22106            {
 22107                request.Dispose();
 22108            }
 22109        }
 22110    }
 111
 112    /// <summary>Sends a request to a service and decodes the "void" response.</summary>
 113    /// <typeparam name="TProxy">The type of the proxy struct.</typeparam>
 114    /// <param name="proxy">A proxy for the remote service.</param>
 115    /// <param name="operation">The name of the operation, as specified in Slice.</param>
 116    /// <param name="payload">The payload of the request.</param>
 117    /// <param name="payloadContinuation">The payload continuation of the request.</param>
 118    /// <param name="responseDecodeFunc">The decode function for the response payload.</param>
 119    /// <param name="features">The invocation features.</param>
 120    /// <param name="idempotent">When <see langword="true" />, the request is idempotent.</param>
 121    /// <param name="oneway">When <see langword="true" />, the request is sent one-way and an empty response is returned
 122    /// immediately after sending the request.</param>
 123    /// <param name="cancellationToken">A cancellation token that receives the cancellation requests.</param>
 124    /// <returns>A task that completes when the void response is returned.</returns>
 125    public static Task InvokeOperationAsync<TProxy>(
 126        this TProxy proxy,
 127        string operation,
 128        PipeReader payload,
 129        PipeReader? payloadContinuation,
 130        ResponseDecodeFunc responseDecodeFunc,
 131        IFeatureCollection? features = null,
 132        bool idempotent = false,
 133        bool oneway = false,
 134        CancellationToken cancellationToken = default) where TProxy : struct, ISliceProxy
 15135    {
 15136        if (proxy.Invoker is not IInvoker invoker)
 0137        {
 0138            throw new InvalidOperationException("Cannot send requests using a proxy with a null invoker.");
 139        }
 140
 15141        var request = new OutgoingRequest(proxy.ServiceAddress)
 15142        {
 15143            Features = features ?? FeatureCollection.Empty,
 15144            Fields = idempotent ? _idempotentFields : ImmutableDictionary<RequestFieldKey, OutgoingFieldValue>.Empty,
 15145            IsOneway = oneway,
 15146            Operation = operation,
 15147            Payload = payload,
 15148            PayloadContinuation = payloadContinuation
 15149        };
 150
 151        Task<IncomingResponse> responseTask;
 152        try
 15153        {
 15154            responseTask = invoker.InvokeAsync(request, cancellationToken);
 14155        }
 1156        catch
 1157        {
 1158            request.Dispose();
 1159            throw;
 160        }
 161
 162        // ReadResponseAsync is responsible for disposing the request
 14163        return ReadResponseAsync(responseTask, request);
 164
 165        async Task ReadResponseAsync(Task<IncomingResponse> responseTask, OutgoingRequest request)
 14166        {
 167            try
 14168            {
 14169                IncomingResponse response = await responseTask.ConfigureAwait(false);
 170
 14171                await responseDecodeFunc(
 14172                    response,
 14173                    request,
 14174                    proxy,
 14175                    cancellationToken).ConfigureAwait(false);
 14176            }
 177            finally
 14178            {
 14179                request.Dispose();
 14180            }
 14181        }
 14182    }
 183}