< Summary

Information
Class: IceRpc.Compressor.CompressorPipeWriter
Assembly: IceRpc.Compressor
File(s): /home/runner/work/icerpc-csharp/icerpc-csharp/src/IceRpc.Compressor/CompressorPipeWriter.cs
Tag: 2300_35243572715
Line coverage
78%
Covered lines: 40
Uncovered lines: 11
Coverable lines: 51
Total lines: 101
Line coverage: 78.4%
Branch coverage
75%
Covered branches: 9
Total branches: 12
Branch coverage: 75%
Method coverage
30%
Covered methods: 3
Fully covered methods: 2
Total methods: 10
Method coverage: 30%
Full method coverage: 20%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_CanGetUnflushedBytes()100%210%
get_UnflushedBytes()100%210%
Advance(...)100%210%
CancelPendingFlush()100%210%
Complete(...)75%8886.66%
FlushAsync(...)100%210%
GetMemory(...)100%210%
GetSpan(...)100%210%
WriteAsync(...)100%11100%
.ctor(...)75%44100%

File(s)

/home/runner/work/icerpc-csharp/icerpc-csharp/src/IceRpc.Compressor/CompressorPipeWriter.cs

#LineLine coverage
 1// Copyright (c) ZeroC, Inc.
 2
 3using System.Diagnostics;
 4using System.IO.Compression;
 5using System.IO.Pipelines;
 6
 7namespace IceRpc.Compressor;
 8
 9/// <summary>A payload writer decorator that compresses the data written to it. Unlike the pipe writer created by
 10/// <see cref="PipeWriter.Create(Stream, StreamPipeWriterOptions?)" /> over a compression stream, this decorator
 11/// implements the completion semantics of payload writers: completing it with an exception completes the decoratee
 12/// with this exception (and not gracefully), and completing it without an exception never throws — when the writing of
 13/// the last compressed bytes fails, the decoratee is completed with the exception.</summary>
 14internal class CompressorPipeWriter : PipeWriter
 15{
 016    public override bool CanGetUnflushedBytes => _compressedDataWriter.CanGetUnflushedBytes;
 17
 018    public override long UnflushedBytes => _compressedDataWriter.UnflushedBytes;
 19
 20    private readonly PipeWriter _compressedDataWriter;
 21    private readonly PipeWriter _decoratee;
 22    private bool _isCompleted;
 23
 024    public override void Advance(int bytes) => _compressedDataWriter.Advance(bytes);
 25
 026    public override void CancelPendingFlush() => _compressedDataWriter.CancelPendingFlush();
 27
 28    public override void Complete(Exception? exception = null)
 1229    {
 1230        if (!_isCompleted)
 1231        {
 1232            if (exception is null && _compressedDataWriter.UnflushedBytes > 0)
 033            {
 034                throw new InvalidOperationException(
 035                    $"Completing a {nameof(CompressorPipeWriter)} without an exception is not allowed when this pipe wri
 36            }
 37
 1238            _isCompleted = true;
 39
 1240            if (exception is null)
 1041            {
 42                try
 1043                {
 44                    // Writes the compression trailer into the decoratee.
 1045                    _compressedDataWriter.Complete();
 846                }
 247                catch (Exception completeException)
 248                {
 249                    exception = completeException;
 250                }
 51
 1052                _decoratee.Complete(exception);
 1053            }
 54            else
 255            {
 56                // Complete the decoratee first: this prevents the disposal of the compression stream below from
 57                // writing the compression trailer to the transport — such a write could block on flow control with no
 58                // cancellation. The trailer writes fail immediately on the completed decoratee.
 259                _decoratee.Complete(exception);
 60                try
 261                {
 62                    // Releases the compression stream.
 263                    _compressedDataWriter.Complete(exception);
 064                }
 265                catch
 266                {
 67                    // Expected: see comment above.
 268                }
 269            }
 1270        }
 1271    }
 72
 73    public override ValueTask<FlushResult> FlushAsync(CancellationToken cancellationToken = default) =>
 074        _compressedDataWriter.FlushAsync(cancellationToken);
 75
 076    public override Memory<byte> GetMemory(int sizeHint = 0) => _compressedDataWriter.GetMemory(sizeHint);
 77
 078    public override Span<byte> GetSpan(int sizeHint = 0) => _compressedDataWriter.GetSpan(sizeHint);
 79
 80    public override ValueTask<FlushResult> WriteAsync(
 81        ReadOnlyMemory<byte> source,
 82        CancellationToken cancellationToken = default) =>
 1283        _compressedDataWriter.WriteAsync(source, cancellationToken);
 84
 1285    internal CompressorPipeWriter(
 1286        PipeWriter decoratee,
 1287        CompressionFormat compressionFormat,
 1288        CompressionLevel compressionLevel)
 1289    {
 1290        Debug.Assert(compressionFormat is CompressionFormat.Brotli or CompressionFormat.Deflate);
 91
 1292        _decoratee = decoratee;
 93
 94        // leaveOpen: true so that the completion of the compressed data writer never completes the decoratee.
 1295        Stream decorateeStream = decoratee.AsStream(leaveOpen: true);
 1296        _compressedDataWriter = PipeWriter.Create(
 1297            compressionFormat == CompressionFormat.Brotli ?
 1298                new BrotliStream(decorateeStream, compressionLevel) :
 1299                new DeflateStream(decorateeStream, compressionLevel));
 12100    }
 101}