gix_features/
progress.rs

1//! Various `prodash` types along with various utilities for comfort.
2use std::io;
3
4#[cfg(feature = "progress-unit-bytes")]
5pub use bytesize;
6pub use prodash::{
7    self,
8    messages::MessageLevel,
9    progress::{
10        AtomicStep, Discard, DoOrDiscard, Either, Id, Step, StepShared, Task, ThroughputOnDrop, Value, UNKNOWN,
11    },
12    unit, BoxedDynNestedProgress, Count, DynNestedProgress, DynNestedProgressToNestedProgress, NestedProgress,
13    Progress, Unit,
14};
15/// A stub for the portions of the `bytesize` crate that we use internally in `gitoxide`.
16#[cfg(not(feature = "progress-unit-bytes"))]
17pub mod bytesize {
18    /// A stub for the `ByteSize` wrapper.
19    pub struct ByteSize(pub u64);
20
21    impl std::fmt::Display for ByteSize {
22        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23            self.0.fmt(f)
24        }
25    }
26}
27
28/// A unit for displaying bytes with throughput and progress percentage.
29#[cfg(feature = "progress-unit-bytes")]
30pub fn bytes() -> Option<Unit> {
31    Some(unit::dynamic_and_mode(
32        unit::Bytes,
33        unit::display::Mode::with_throughput().and_percentage(),
34    ))
35}
36
37/// A unit for displaying bytes with throughput and progress percentage.
38#[cfg(not(feature = "progress-unit-bytes"))]
39pub fn bytes() -> Option<Unit> {
40    Some(unit::label_and_mode(
41        "B",
42        unit::display::Mode::with_throughput().and_percentage(),
43    ))
44}
45
46/// A unit for displaying human readable numbers with throughput and progress percentage, and a single decimal place.
47pub fn count(name: &'static str) -> Option<Unit> {
48    count_with_decimals(name, 1)
49}
50
51/// A unit for displaying human readable numbers with `name` suffix,
52/// with throughput and progress percentage, and `decimals` decimal places.
53#[cfg(feature = "progress-unit-human-numbers")]
54pub fn count_with_decimals(name: &'static str, decimals: usize) -> Option<Unit> {
55    Some(unit::dynamic_and_mode(
56        unit::Human::new(
57            {
58                let mut f = unit::human::Formatter::new();
59                f.with_decimals(decimals);
60                f
61            },
62            name,
63        ),
64        unit::display::Mode::with_throughput().and_percentage(),
65    ))
66}
67
68/// A unit for displaying human readable numbers with `name` suffix,
69/// with throughput and progress percentage, and `decimals` decimal places.
70#[cfg(not(feature = "progress-unit-human-numbers"))]
71pub fn count_with_decimals(name: &'static str, _decimals: usize) -> Option<Unit> {
72    Some(unit::label_and_mode(
73        name,
74        unit::display::Mode::with_throughput().and_percentage(),
75    ))
76}
77
78/// A predefined unit for displaying a multi-step progress
79pub fn steps() -> Option<Unit> {
80    Some(unit::dynamic(unit::Range::new("steps")))
81}
82
83/// A structure passing every [`read`](std::io::Read::read()) call through to the contained Progress instance using [`inc_by(bytes_read)`](Count::inc_by()).
84pub struct Read<T, P> {
85    /// The implementor of [`std::io::Read`] to which progress is added
86    pub inner: T,
87    /// The progress instance receiving progress information on each invocation of `reader`
88    pub progress: P,
89}
90
91impl<T, P> io::Read for Read<T, P>
92where
93    T: io::Read,
94    P: Progress,
95{
96    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
97        let bytes_read = self.inner.read(buf)?;
98        self.progress.inc_by(bytes_read);
99        Ok(bytes_read)
100    }
101}
102
103impl<T, P> io::BufRead for Read<T, P>
104where
105    T: io::BufRead,
106    P: Progress,
107{
108    fn fill_buf(&mut self) -> io::Result<&[u8]> {
109        self.inner.fill_buf()
110    }
111
112    fn consume(&mut self, amt: usize) {
113        self.inner.consume(amt);
114    }
115}
116
117/// A structure passing every [`write`][std::io::Write::write()] call through to the contained Progress instance using [`inc_by(bytes_written)`](Count::inc_by()).
118///
119/// This is particularly useful if the final size of the bytes to write is known or can be estimated precisely enough.
120pub struct Write<T, P> {
121    /// The implementor of [`std::io::Write`] to which progress is added
122    pub inner: T,
123    /// The progress instance receiving progress information on each invocation of `reader`
124    pub progress: P,
125}
126
127impl<T, P> io::Write for Write<T, P>
128where
129    T: io::Write,
130    P: Progress,
131{
132    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
133        let written = self.inner.write(buf)?;
134        self.progress.inc_by(written);
135        Ok(written)
136    }
137
138    fn flush(&mut self) -> io::Result<()> {
139        self.inner.flush()
140    }
141}
142
143impl<T, P> io::Seek for Write<T, P>
144where
145    T: io::Seek,
146{
147    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
148        self.inner.seek(pos)
149    }
150}