git_date/time/
write.rs

1use bstr::BString;
2
3use crate::{time::Sign, Time};
4
5/// Serialization with standard `git` format
6impl Time {
7    /// Serialize this instance into memory, similar to what [`write_to()`][Self::write_to()] would do with arbitrary `Write` implementations.
8    pub fn to_bstring(&self) -> BString {
9        let mut buf = Vec::with_capacity(64);
10        self.write_to(&mut buf).expect("write to memory cannot fail");
11        buf.into()
12    }
13
14    /// Serialize this instance to `out` in a format suitable for use in header fields of serialized git commits or tags.
15    pub fn write_to(&self, mut out: impl std::io::Write) -> std::io::Result<()> {
16        let mut itoa = itoa::Buffer::new();
17        out.write_all(itoa.format(self.seconds_since_unix_epoch).as_bytes())?;
18        out.write_all(b" ")?;
19        out.write_all(match self.sign {
20            Sign::Plus => b"+",
21            Sign::Minus => b"-",
22        })?;
23
24        const ZERO: &[u8; 1] = b"0";
25
26        const SECONDS_PER_HOUR: i32 = 60 * 60;
27        let offset = self.offset_in_seconds.abs();
28        let hours = offset / SECONDS_PER_HOUR;
29        assert!(hours < 25, "offset is more than a day: {hours}");
30        let minutes = (offset - (hours * SECONDS_PER_HOUR)) / 60;
31
32        if hours < 10 {
33            out.write_all(ZERO)?;
34        }
35        out.write_all(itoa.format(hours).as_bytes())?;
36
37        if minutes < 10 {
38            out.write_all(ZERO)?;
39        }
40        out.write_all(itoa.format(minutes).as_bytes()).map(|_| ())
41    }
42
43    /// Computes the number of bytes necessary to render this time.
44    pub fn size(&self) -> usize {
45        // TODO: this is not year 2038 safe…but we also can't parse larger numbers (or represent them) anyway. It's a trap nonetheless
46        //       that can be fixed by increasing the size to usize.
47        (if self.seconds_since_unix_epoch >= 1_000_000_000 {
48            10
49        } else if self.seconds_since_unix_epoch >= 100_000_000 {
50            9
51        } else if self.seconds_since_unix_epoch >= 10_000_000 {
52            8
53        } else if self.seconds_since_unix_epoch >= 1_000_000 {
54            7
55        } else if self.seconds_since_unix_epoch >= 100_000 {
56            6
57        } else if self.seconds_since_unix_epoch >= 10_000 {
58            5
59        } else if self.seconds_since_unix_epoch >= 1_000 {
60            4
61        } else if self.seconds_since_unix_epoch >= 100 {
62            3
63        } else if self.seconds_since_unix_epoch >= 10 {
64            2
65        } else {
66            1
67        }) + 2 /*space + sign*/ + 2 /*hours*/ + 2 /*minutes*/
68    }
69}