< Summary

Information
Class: MyNet.Utilities.Progress.ProgressStep<T>
Assembly: MyNet.Utilities
File(s): https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.Utilities/Progress/ProgressStep.cs
Tag: 323_28699572109
Line coverage
100%
Covered lines: 39
Uncovered lines: 0
Coverable lines: 39
Total lines: 154
Line coverage: 100%
Branch coverage
85%
Covered branches: 17
Total branches: 20
Branch coverage: 85%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)75%44100%
AllocateChildSlot()100%22100%
SetChildProgress(...)100%44100%
UpdateMessage(...)50%22100%
UpdateProgress(...)100%44100%
Dispose()50%22100%
RecomputeProgress()100%22100%
.ctor(...)100%11100%

File(s)

https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.Utilities/Progress/ProgressStep.cs

#LineLine coverage
 1// -----------------------------------------------------------------------
 2// <copyright file="ProgressStep.cs" company="Stéphane ANDRE">
 3// Copyright (c) Stéphane ANDRE. All rights reserved.
 4// </copyright>
 5// -----------------------------------------------------------------------
 6
 7using System;
 8using System.Collections.Generic;
 9using System.Diagnostics;
 10using System.Linq;
 11using MyNet.Primitives;
 12
 13namespace MyNet.Utilities.Progress;
 14
 15/// <summary>
 16/// Internal implementation of <see cref="IProgressStep{T}"/>.
 17/// Each instance represents one node in the progress tree.
 18/// </summary>
 19internal sealed class ProgressStep<T> : IProgressStep<T>
 20{
 21    private readonly Progresser<T> _progresser;
 22
 23    /// <summary>Direct reference to the parent step (null for the root step).</summary>
 24    private readonly ProgressStep<T>? _parent;
 25
 26    /// <summary>
 27    /// Index of the child slot in <see cref="_parent"/> that this step occupies.
 28    /// -1 when there is no parent or when the parent has no pre-allocated slot for this step.
 29    /// </summary>
 30    private readonly int _parentSlotIndex;
 31
 32    /// <summary>Pre-allocated child slots with their relative weightings.</summary>
 9033    private readonly List<ProgressStepValue> _children = [];
 34
 35    /// <summary>Points to the next unallocated child slot index.</summary>
 36    private int _nextChildSlot;
 37
 38    /// <summary>
 39    /// Initializes a new instance of the <see cref="ProgressStep{T}"/> class, pushes it onto the progresser stack,
 40    /// and fires an initial report so subscribers see the new message immediately.
 41    /// </summary>
 42    internal ProgressStep(
 43        Progresser<T> progresser,
 44        ProgressStep<T>? parent,
 45        int parentSlotIndex,
 46        T? message,
 47        IEnumerable<double> subStepWeightings,
 48        Action? cancelAction,
 49        bool canCancel)
 50    {
 9051        _progresser = progresser;
 9052        _parent = parent;
 9053        _parentSlotIndex = parentSlotIndex;
 9054        CancelAction = cancelAction;
 9055        CanCancel = canCancel;
 9056        Message = message;
 57
 58        // Normalize and store sub-step weightings so they always sum to 1.
 9059        var weightings = subStepWeightings.ToList();
 9060        var total = weightings.Sum();
 36061        foreach (var w in weightings)
 9062            _children.Add(new(total > 0 ? w / total : 1.0 / weightings.Count));
 63
 9064        _progresser.Push(this);
 65
 66        // Fire an initial report so subscribers see the new message right away.
 9067        _progresser.Report();
 9068    }
 69
 70    /// <inheritdoc/>
 71    public double Progress { get; private set; }
 72
 73    /// <inheritdoc/>
 74    public bool IsCompleted { get; private set; }
 75
 76    /// <inheritdoc/>
 77    public T? Message { get; private set; }
 78
 79    /// <inheritdoc/>
 80    public bool CanCancel { get; }
 81
 82    /// <inheritdoc/>
 83    public Action? CancelAction { get; }
 84
 85    // ── Internal child-tracking API (used by Progresser<T>) ─────────────────
 86
 87    /// <summary>
 88    /// Allocates the next child slot and returns its index.
 89    /// Returns -1 when there are no more pre-allocated slots available.
 90    /// </summary>
 91    internal int AllocateChildSlot()
 3692        => _nextChildSlot < _children.Count ? _nextChildSlot++ : -1;
 93
 94    /// <summary>
 95    /// Updates the progress of the child slot at <paramref name="slotIndex"/> and recomputes
 96    /// this step's own aggregate progress.
 97    /// </summary>
 98    internal void SetChildProgress(int slotIndex, double progress)
 99    {
 84100        if (slotIndex < 0 || slotIndex >= _children.Count) return;
 18101        _children[slotIndex].Progress = progress;
 18102        RecomputeProgress();
 18103    }
 104
 105    // ── IProgressStep<T> ────────────────────────────────────────────────────
 106
 107    /// <inheritdoc/>
 108    public void UpdateMessage(T? message)
 109    {
 3110        if (Equals(Message, message)) return;
 3111        Message = message;
 3112        _progresser.Report();
 3113    }
 114
 115    /// <inheritdoc/>
 116    public void UpdateProgress(double value)
 117    {
 111118        var clamped = Math.Clamp(value, 0.0, 1.0);
 114119        if (Progress.IsCloseTo(clamped)) return;
 120
 108121        Progress = clamped;
 122
 108123        if (_parent is not null)
 51124            _parent.SetChildProgress(_parentSlotIndex, Progress);
 125        else
 57126            _progresser.Report();
 57127    }
 128
 129    /// <inheritdoc/>
 130    public void Dispose()
 131    {
 90132        if (IsCompleted) return;
 90133        IsCompleted = true;
 90134        UpdateProgress(1.0);
 90135        _progresser.Pop();
 90136    }
 137
 138    // ── Private helpers ──────────────────────────────────────────────────────
 139    private void RecomputeProgress()
 140    {
 18141        var aggregate = _children.Sum(c => c.Weighting * c.Progress);
 18142        UpdateProgress(aggregate);
 18143    }
 144
 145    // ── Nested type ──────────────────────────────────────────────────────────
 146    [DebuggerDisplay("Weighting={Weighting}, Progress={Progress}")]
 147    private sealed class ProgressStepValue(double weighting)
 148    {
 90149        public double Weighting { get; } = weighting;
 150
 151        public double Progress { get; set; }
 152    }
 153}
 154