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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
use std::str;
use std::kinds::marker;
use libc;
use {raw, Error};
/// A Signature is used to indicate authorship of various actions throughout the
/// library.
///
/// Signatures contain a name, email, and timestamp. All fields can be specified
/// with `new`, the `now` constructor omits the timestamp, and the `default`
/// constructor reads configuration from the given repository.
pub struct Signature<'a> {
raw: *mut raw::git_signature,
marker: marker::ContravariantLifetime<'a>,
owned: bool,
}
impl<'a> Signature<'a> {
/// Create a new action signature with a timestamp of 'now'.
///
/// See `new` for more information
pub fn now(name: &str, email: &str) -> Result<Signature<'static>, Error> {
::init();
let mut ret = 0 as *mut raw::git_signature;
unsafe {
try_call!(raw::git_signature_now(&mut ret, name.to_c_str(),
email.to_c_str()));
Ok(Signature::from_raw(ret))
}
}
/// Create a new action signature.
///
/// The `time` specified is in seconds since the epoch, and the `offset` is
/// the time zone offset in minutes.
///
/// Returns error if either `name` or `email` contain angle brackets.
pub fn new(name: &str, email: &str, time: u64,
offset: int) -> Result<Signature<'static>, Error> {
::init();
let mut ret = 0 as *mut raw::git_signature;
unsafe {
try_call!(raw::git_signature_new(&mut ret, name.to_c_str(),
email.to_c_str(),
time as raw::git_time_t,
offset as libc::c_int));
Ok(Signature::from_raw(ret))
}
}
/// Consumes ownership of a raw signature pointer
///
/// This function is unsafe as the pointer is not guranteed to be valid.
pub unsafe fn from_raw(raw: *mut raw::git_signature) -> Signature<'static> {
Signature {
raw: raw,
marker: marker::ContravariantLifetime,
owned: true,
}
}
/// Creates a new signature from the give raw pointer, tied to the lifetime
/// of the given object.
///
/// This function is unsafe as there is no guarantee that `raw` is valid for
/// `'a` nor if it's a valid pointer.
pub unsafe fn from_raw_const<'b, T>(_lt: &'b T,
raw: *const raw::git_signature)
-> Signature<'b> {
Signature {
raw: raw as *mut raw::git_signature,
marker: marker::ContravariantLifetime,
owned: false,
}
}
/// Gets the name on the signature.
///
/// Returns `None` if the name is not valid utf-8
pub fn name(&self) -> Option<&str> {
str::from_utf8(self.name_bytes())
}
/// Gets the name on the signature as a byte slice.
pub fn name_bytes(&self) -> &[u8] {
unsafe { ::opt_bytes(self, (*self.raw).name as *const _).unwrap() }
}
/// Gets the email on the signature.
///
/// Returns `None` if the email is not valid utf-8
pub fn email(&self) -> Option<&str> {
str::from_utf8(self.email_bytes())
}
/// Gets the email on the signature as a byte slice.
pub fn email_bytes(&self) -> &[u8] {
unsafe { ::opt_bytes(self, (*self.raw).email as *const _).unwrap() }
}
/// Get the `when` of this signature in seconds since the epoch.
pub fn when(&self) -> u64 {
unsafe { (*self.raw).when.time as u64 }
}
/// Get the offset of `when`, in minutes, of the signature's time zone from
/// UTC.
pub fn when_offset(&self) -> int {
unsafe { (*self.raw).when.offset as int }
}
/// Get access to the underlying raw signature
pub fn raw(&self) -> *mut raw::git_signature { self.raw }
}
impl Clone for Signature<'static> {
fn clone(&self) -> Signature<'static> {
let mut raw = 0 as *mut raw::git_signature;
let rc = unsafe { raw::git_signature_dup(&mut raw, &*self.raw) };
assert_eq!(rc, 0);
unsafe { Signature::from_raw(raw) }
}
}
#[unsafe_destructor]
impl<'a> Drop for Signature<'a> {
fn drop(&mut self) {
if self.owned {
unsafe { raw::git_signature_free(self.raw) }
}
}
}
#[cfg(test)]
mod tests {
use Signature;
#[test]
fn smoke() {
Signature::new("foo", "bar", 89, 0).unwrap();
Signature::now("foo", "bar").unwrap();
assert!(Signature::new("<foo>", "bar", 89, 0).is_err());
assert!(Signature::now("<foo>", "bar").is_err());
let s = Signature::now("foo", "bar").unwrap();
assert_eq!(s.name(), Some("foo"));
assert_eq!(s.email(), Some("bar"));
drop(s.clone());
}
}