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::new(
28                std::io::ErrorKind::Other,
29                "Cannot represent offsets larger than +-9900",
30            ));
31        }
32
33        let mut itoa = itoa::Buffer::new();
34        out.write_all(itoa.format(self.seconds).as_bytes())?;
35        out.write_all(b" ")?;
36        out.write_all(if self.offset < 0 { b"-" } else { b"+" })?;
37
38        const ZERO: &[u8; 1] = b"0";
39
40        if hours < 10 {
41            out.write_all(ZERO)?;
42        }
43        out.write_all(itoa.format(hours).as_bytes())?;
44
45        if minutes < 10 {
46            out.write_all(ZERO)?;
47        }
48        out.write_all(itoa.format(minutes).as_bytes()).map(|_| ())
49    }
50
51    /// Computes the number of bytes necessary to write it using [`Time::write_to()`].
52    pub const fn size(&self) -> usize {
53        (if self.seconds >= 1_000_000_000_000_000_000 {
54            19
55        } else if self.seconds >= 100_000_000_000_000_000 {
56            18
57        } else if self.seconds >= 10_000_000_000_000_000 {
58            17
59        } else if self.seconds >= 1_000_000_000_000_000 {
60            16
61        } else if self.seconds >= 100_000_000_000_000 {
62            15
63        } else if self.seconds >= 10_000_000_000_000 {
64            14
65        } else if self.seconds >= 1_000_000_000_000 {
66            13
67        } else if self.seconds >= 100_000_000_000 {
68            12
69        } else if self.seconds >= 10_000_000_000 {
70            11
71        } else if self.seconds >= 1_000_000_000 {
72            10
73        } else if self.seconds >= 100_000_000 {
74            9
75        } else if self.seconds >= 10_000_000 {
76            8
77        } else if self.seconds >= 1_000_000 {
78            7
79        } else if self.seconds >= 100_000 {
80            6
81        } else if self.seconds >= 10_000 {
82            5
83        } else if self.seconds >= 1_000 {
84            4
85        } else if self.seconds >= 100 {
86            3
87        } else if self.seconds >= 10 {
88            2
89        } else if self.seconds >= 0 {
90            1
91            // from here, it's sign + num-digits characters
92        } else if self.seconds >= -10 {
93            2
94        } else if self.seconds >= -100 {
95            3
96        } else if self.seconds >= -1_000 {
97            4
98        } else if self.seconds >= -10_000 {
99            5
100        } else if self.seconds >= -100_000 {
101            6
102        } else if self.seconds >= -1_000_000 {
103            7
104        } else if self.seconds >= -10_000_000 {
105            8
106        } else if self.seconds >= -100_000_000 {
107            9
108        } else if self.seconds >= -1_000_000_000 {
109            10
110        } else if self.seconds >= -10_000_000_000 {
111            11
112        } else if self.seconds >= -100_000_000_000 {
113            12
114        } else if self.seconds >= -1_000_000_000_000 {
115            13
116        } else if self.seconds >= -10_000_000_000_000 {
117            14
118        } else if self.seconds >= -100_000_000_000_000 {
119            15
120        } else if self.seconds >= -1_000_000_000_000_000 {
121            16
122        } else if self.seconds >= -10_000_000_000_000_000 {
123            17
124        } else if self.seconds >= -100_000_000_000_000_000 {
125            18
126        } else if self.seconds >= -1_000_000_000_000_000_000 {
127            19
128        } else {
129            20
130        }) + 2 /*space + offset sign*/ + 2 /*offset hours*/ + 2 /*offset minutes*/
131    }
132
133    /// The numerically largest possible time instance, whose [size()](Time::size) is the largest possible
134    /// number of bytes to write using [`Time::write_to()`].
135    pub const MAX: Time = Time {
136        seconds: SecondsSinceUnixEpoch::MAX,
137        offset: 99 * 60 * 60 + 59 * 60 + 59,
138    };
139}