summaryrefslogtreecommitdiffstats
path: root/vendor/gix-features/src/progress.rs
blob: 6a8c9e1bdd0507738df782e806764bc236bdad9b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//! Various `prodash` types along with various utilities for comfort.
use std::io;

#[cfg(feature = "progress-unit-bytes")]
pub use bytesize;
pub use prodash::{
    self,
    messages::MessageLevel,
    progress::{
        AtomicStep, Discard, DoOrDiscard, Either, Id, Step, StepShared, Task, ThroughputOnDrop, Value, UNKNOWN,
    },
    unit, BoxedDynNestedProgress, Count, DynNestedProgress, DynNestedProgressToNestedProgress, NestedProgress,
    Progress, Unit,
};
/// A stub for the portions of the `bytesize` crate that we use internally in `gitoxide`.
#[cfg(not(feature = "progress-unit-bytes"))]
pub mod bytesize {
    /// A stub for the `ByteSize` wrapper.
    pub struct ByteSize(pub u64);

    impl std::fmt::Display for ByteSize {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            self.0.fmt(f)
        }
    }
}

/// A unit for displaying bytes with throughput and progress percentage.
#[cfg(feature = "progress-unit-bytes")]
pub fn bytes() -> Option<Unit> {
    Some(unit::dynamic_and_mode(
        unit::Bytes,
        unit::display::Mode::with_throughput().and_percentage(),
    ))
}

/// A unit for displaying bytes with throughput and progress percentage.
#[cfg(not(feature = "progress-unit-bytes"))]
pub fn bytes() -> Option<Unit> {
    Some(unit::label_and_mode(
        "B",
        unit::display::Mode::with_throughput().and_percentage(),
    ))
}

/// A unit for displaying human readable numbers with throughput and progress percentage, and a single decimal place.
pub fn count(name: &'static str) -> Option<Unit> {
    count_with_decimals(name, 1)
}

/// A unit for displaying human readable numbers with `name` suffix,
/// with throughput and progress percentage, and `decimals` decimal places.
#[cfg(feature = "progress-unit-human-numbers")]
pub fn count_with_decimals(name: &'static str, decimals: usize) -> Option<Unit> {
    Some(unit::dynamic_and_mode(
        unit::Human::new(
            {
                let mut f = unit::human::Formatter::new();
                f.with_decimals(decimals);
                f
            },
            name,
        ),
        unit::display::Mode::with_throughput().and_percentage(),
    ))
}

/// A unit for displaying human readable numbers with `name` suffix,
/// with throughput and progress percentage, and `decimals` decimal places.
#[cfg(not(feature = "progress-unit-human-numbers"))]
pub fn count_with_decimals(name: &'static str, _decimals: usize) -> Option<Unit> {
    Some(unit::label_and_mode(
        name,
        unit::display::Mode::with_throughput().and_percentage(),
    ))
}

/// A predefined unit for displaying a multi-step progress
pub fn steps() -> Option<Unit> {
    Some(unit::dynamic(unit::Range::new("steps")))
}

/// A structure passing every [`read`](std::io::Read::read()) call through to the contained Progress instance using [`inc_by(bytes_read)`](Count::inc_by()).
pub struct Read<T, P> {
    /// The implementor of [`std::io::Read`] to which progress is added
    pub inner: T,
    /// The progress instance receiving progress information on each invocation of `reader`
    pub progress: P,
}

impl<T, P> io::Read for Read<T, P>
where
    T: io::Read,
    P: Progress,
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let bytes_read = self.inner.read(buf)?;
        self.progress.inc_by(bytes_read);
        Ok(bytes_read)
    }
}

impl<T, P> io::BufRead for Read<T, P>
where
    T: io::BufRead,
    P: Progress,
{
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        self.inner.fill_buf()
    }

    fn consume(&mut self, amt: usize) {
        self.inner.consume(amt)
    }
}

/// A structure passing every [`write`][std::io::Write::write()] call through to the contained Progress instance using [`inc_by(bytes_written)`](Count::inc_by()).
///
/// This is particularly useful if the final size of the bytes to write is known or can be estimated precisely enough.
pub struct Write<T, P> {
    /// The implementor of [`std::io::Write`] to which progress is added
    pub inner: T,
    /// The progress instance receiving progress information on each invocation of `reader`
    pub progress: P,
}

impl<T, P> io::Write for Write<T, P>
where
    T: io::Write,
    P: Progress,
{
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let written = self.inner.write(buf)?;
        self.progress.inc_by(written);
        Ok(written)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.inner.flush()
    }
}

impl<T, P> io::Seek for Write<T, P>
where
    T: io::Seek,
{
    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
        self.inner.seek(pos)
    }
}