gix_date/time/
write.rs

1use bstr::ByteSlice;
2
3use crate::{SecondsSinceUnixEpoch, Time};
4
5/// Serialize this instance as string, similar to what [`write_to()`](Self::write_to()) would do.
6impl std::fmt::Display for Time {
7    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
8        let mut buf = Vec::with_capacity(Time::MAX.size());
9        self.write_to(&mut buf).expect("write to memory cannot fail");
10        // SAFETY: We know time serializes as ASCII, as subset of UTF8.
11        #[allow(unsafe_code)]
12        let raw = unsafe { buf.to_str_unchecked() };
13        f.write_str(raw)
14    }
15}
16
17/// Serialization with standard `git` format
18impl Time {
19    /// Serialize this instance to `out` in a format suitable for use in header fields of serialized git commits or tags.
20    pub fn write_to(&self, out: &mut dyn std::io::Write) -> std::io::Result<()> {
21        const SECONDS_PER_HOUR: u32 = 60 * 60;
22        let offset = self.offset.unsigned_abs();
23        let hours = offset / SECONDS_PER_HOUR;
24        let minutes = (offset - (hours * SECONDS_PER_HOUR)) / 60;
25
26        if hours > 99 {
27            return Err(std::io::Error::other("Cannot represent offsets larger than +-9900"));
28        }
29
30        let mut itoa = itoa::Buffer::new();
31        out.write_all(itoa.format(self.seconds).as_bytes())?;
32        out.write_all(b" ")?;
33        out.write_all(if self.offset < 0 { b"-" } else { b"+" })?;
34
35        const ZERO: &[u8; 1] = b"0";
36
37        if hours < 10 {
38            out.write_all(ZERO)?;
39        }
40        out.write_all(itoa.format(hours).as_bytes())?;
41
42        if minutes < 10 {
43            out.write_all(ZERO)?;
44        }
45        out.write_all(itoa.format(minutes).as_bytes()).map(|_| ())
46    }
47
48    /// Computes the number of bytes necessary to write it using [`Time::write_to()`].
49    pub const fn size(&self) -> usize {
50        (if self.seconds >= 1_000_000_000_000_000_000 {
51            19
52        } else if self.seconds >= 100_000_000_000_000_000 {
53            18
54        } else if self.seconds >= 10_000_000_000_000_000 {
55            17
56        } else if self.seconds >= 1_000_000_000_000_000 {
57            16
58        } else if self.seconds >= 100_000_000_000_000 {
59            15
60        } else if self.seconds >= 10_000_000_000_000 {
61            14
62        } else if self.seconds >= 1_000_000_000_000 {
63            13
64        } else if self.seconds >= 100_000_000_000 {
65            12
66        } else if self.seconds >= 10_000_000_000 {
67            11
68        } else if self.seconds >= 1_000_000_000 {
69            10
70        } else if self.seconds >= 100_000_000 {
71            9
72        } else if self.seconds >= 10_000_000 {
73            8
74        } else if self.seconds >= 1_000_000 {
75            7
76        } else if self.seconds >= 100_000 {
77            6
78        } else if self.seconds >= 10_000 {
79            5
80        } else if self.seconds >= 1_000 {
81            4
82        } else if self.seconds >= 100 {
83            3
84        } else if self.seconds >= 10 {
85            2
86        } else if self.seconds >= 0 {
87            1
88            // from here, it's sign + num-digits characters
89        } else if self.seconds >= -10 {
90            2
91        } else if self.seconds >= -100 {
92            3
93        } else if self.seconds >= -1_000 {
94            4
95        } else if self.seconds >= -10_000 {
96            5
97        } else if self.seconds >= -100_000 {
98            6
99        } else if self.seconds >= -1_000_000 {
100            7
101        } else if self.seconds >= -10_000_000 {
102            8
103        } else if self.seconds >= -100_000_000 {
104            9
105        } else if self.seconds >= -1_000_000_000 {
106            10
107        } else if self.seconds >= -10_000_000_000 {
108            11
109        } else if self.seconds >= -100_000_000_000 {
110            12
111        } else if self.seconds >= -1_000_000_000_000 {
112            13
113        } else if self.seconds >= -10_000_000_000_000 {
114            14
115        } else if self.seconds >= -100_000_000_000_000 {
116            15
117        } else if self.seconds >= -1_000_000_000_000_000 {
118            16
119        } else if self.seconds >= -10_000_000_000_000_000 {
120            17
121        } else if self.seconds >= -100_000_000_000_000_000 {
122            18
123        } else if self.seconds >= -1_000_000_000_000_000_000 {
124            19
125        } else {
126            20
127        }) + 2 /*space + offset sign*/ + 2 /*offset hours*/ + 2 /*offset minutes*/
128    }
129
130    /// The numerically largest possible time instance, whose [size()](Time::size) is the largest possible
131    /// number of bytes to write using [`Time::write_to()`].
132    pub const MAX: Time = Time {
133        seconds: SecondsSinceUnixEpoch::MAX,
134        offset: 99 * 60 * 60 + 59 * 60 + 59,
135    };
136}