Coverage Report

Created: 2026-07-14 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gitoxide/gix-date/src/time/write.rs
Line
Count
Source
1
use crate::{SecondsSinceUnixEpoch, Time};
2
3
/// Serialize this instance as string, similar to what [`write_to()`](Self::write_to()) would do.
4
impl std::fmt::Display for Time {
5
0
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6
0
        let mut buf = Vec::with_capacity(Time::MIN.size());
7
0
        self.write_to(&mut buf).expect("write to memory cannot fail");
8
        // Time serializes as ASCII, which is a subset of UTF-8.
9
        // Use `from_utf8()` (validated) instead of `from_utf8_unchecked()` for safety,
10
        // with the option to switch to an unsafe version if 30% performance boost are needed here.
11
0
        let raw = std::str::from_utf8(&buf).expect("time serializes as valid UTF-8");
12
0
        f.write_str(raw)
13
0
    }
Unexecuted instantiation: <gix_date::Time as core::fmt::Display>::fmt
Unexecuted instantiation: <gix_date::Time as core::fmt::Display>::fmt
Unexecuted instantiation: <gix_date::Time as core::fmt::Display>::fmt
14
}
15
16
/// Serialization with standard `git` format
17
impl Time {
18
    /// Serialize this instance to `out` in a format suitable for use in header fields of serialized git commits or tags.
19
0
    pub fn write_to(&self, out: &mut dyn std::io::Write) -> std::io::Result<()> {
20
        const SECONDS_PER_HOUR: u32 = 60 * 60;
21
0
        let offset = self.offset.unsigned_abs();
22
0
        let hours = offset / SECONDS_PER_HOUR;
23
0
        let minutes = (offset - (hours * SECONDS_PER_HOUR)) / 60;
24
25
0
        if hours > 99 {
26
0
            return Err(std::io::Error::other("Cannot represent offsets larger than +-9900"));
27
0
        }
28
29
0
        let mut itoa = itoa::Buffer::new();
30
0
        out.write_all(itoa.format(self.seconds).as_bytes())?;
31
0
        out.write_all(b" ")?;
32
0
        out.write_all(if self.offset < 0 { b"-" } else { b"+" })?;
33
34
        const ZERO: &[u8; 1] = b"0";
35
36
0
        if hours < 10 {
37
0
            out.write_all(ZERO)?;
38
0
        }
39
0
        out.write_all(itoa.format(hours).as_bytes())?;
40
41
0
        if minutes < 10 {
42
0
            out.write_all(ZERO)?;
43
0
        }
44
0
        out.write_all(itoa.format(minutes).as_bytes()).map(|_| ())
45
0
    }
Unexecuted instantiation: <gix_date::Time>::write_to
Unexecuted instantiation: <gix_date::Time>::write_to
Unexecuted instantiation: <gix_date::Time>::write_to
46
47
    /// Computes the number of bytes necessary to write it using [`Time::write_to()`].
48
0
    pub const fn size(&self) -> usize {
49
0
        let is_negative = self.seconds < 0;
50
0
        Self::count_positive_digits(self.seconds.unsigned_abs()) + is_negative as usize + 6
51
        // space + offset sign + hours (2) + minutes (2)
52
0
    }
Unexecuted instantiation: <gix_date::Time>::size
Unexecuted instantiation: <gix_date::Time>::size
Unexecuted instantiation: <gix_date::Time>::size
53
54
    /// Count the number of decimal digits in a positive integer.
55
0
    const fn count_positive_digits(n: u64) -> usize {
56
        // Powers of 10 for comparison
57
        const POW10: [u64; 20] = [
58
            1,
59
            10,
60
            100,
61
            1_000,
62
            10_000,
63
            100_000,
64
            1_000_000,
65
            10_000_000,
66
            100_000_000,
67
            1_000_000_000,
68
            10_000_000_000,
69
            100_000_000_000,
70
            1_000_000_000_000,
71
            10_000_000_000_000,
72
            100_000_000_000_000,
73
            1_000_000_000_000_000,
74
            10_000_000_000_000_000,
75
            100_000_000_000_000_000,
76
            1_000_000_000_000_000_000,
77
            10_000_000_000_000_000_000,
78
        ];
79
80
        // Binary search would be nice but not const-fn friendly, so use simple loop
81
0
        let mut digits = 1;
82
0
        while digits < 20 && n >= POW10[digits] {
83
0
            digits += 1;
84
0
        }
85
0
        digits
86
0
    }
Unexecuted instantiation: <gix_date::Time>::count_positive_digits
Unexecuted instantiation: <gix_date::Time>::count_positive_digits
Unexecuted instantiation: <gix_date::Time>::count_positive_digits
87
88
    /// The numerically largest possible time instance.
89
    pub const MAX: Time = Time {
90
        seconds: SecondsSinceUnixEpoch::MAX,
91
        offset: 99 * 60 * 60 + 59 * 60 + 59,
92
    };
93
94
    /// The numerically smallest possible time instance.
95
    pub const MIN: Time = Time {
96
        seconds: SecondsSinceUnixEpoch::MIN,
97
        offset: -(99 * 60 * 60 + 59 * 60 + 59),
98
    };
99
}