1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use crate::owned::SPACE;
use quick_error::quick_error;
use std::{fmt, io};
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
#[allow(missing_docs)]
pub enum Sign {
Plus,
Minus,
}
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
pub struct Time {
pub time: u32,
pub offset: i32,
pub sign: Sign,
}
impl Time {
pub fn write_to(&self, mut out: impl io::Write) -> io::Result<()> {
itoa::write(&mut out, self.time)?;
out.write_all(SPACE)?;
out.write_all(&[match self.sign {
Sign::Plus => b'+',
Sign::Minus => b'-',
}])?;
const ZERO: &[u8; 1] = b"0";
const SECONDS_PER_HOUR: i32 = 60 * 60;
let offset = self.offset.abs();
let hours = offset / SECONDS_PER_HOUR;
assert!(hours < 25, "offset is more than a day: {}", hours);
let minutes = (offset - (hours * SECONDS_PER_HOUR)) / 60;
if hours < 10 {
out.write_all(ZERO)?;
}
itoa::write(&mut out, hours)?;
if minutes < 10 {
out.write_all(ZERO)?;
}
itoa::write(&mut out, minutes).map(|_| ())
}
}
pub const SHA1_SIZE: usize = 20;
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
#[allow(missing_docs)]
pub enum Kind {
Tree,
Blob,
Commit,
Tag,
}
quick_error! {
#[derive(Debug)]
#[allow(missing_docs)]
pub enum Error {
InvalidObjectKind(kind: crate::BString) {
display("Unknown object kind: {:?}", std::str::from_utf8(&kind))
}
}
}
impl Kind {
pub fn from_bytes(s: &[u8]) -> Result<Kind, Error> {
Ok(match s {
b"tree" => Kind::Tree,
b"blob" => Kind::Blob,
b"commit" => Kind::Commit,
b"tag" => Kind::Tag,
_ => return Err(Error::InvalidObjectKind(s.into())),
})
}
pub fn to_bytes(&self) -> &[u8] {
match self {
Kind::Tree => b"tree",
Kind::Commit => b"commit",
Kind::Blob => b"blob",
Kind::Tag => b"tag",
}
}
}
impl fmt::Display for Kind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(std::str::from_utf8(self.to_bytes()).expect("Converting Kind name to utf8"))
}
}
pub mod tree {
#[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash)]
#[repr(u16)]
#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
#[allow(missing_docs)]
pub enum Mode {
Tree = 0o040000u16,
Blob = 0o100644,
BlobExecutable = 0o100755,
Link = 0o120000,
Commit = 0o160000,
}
}