use std::ffi::CString;
use std::fmt;
use std::marker;
use std::mem;
use std::ptr;
use std::str;
use crate::util::Binding;
use crate::{raw, Error, Time};
pub struct Signature<'a> {
raw: *mut raw::git_signature,
_marker: marker::PhantomData<&'a str>,
owned: bool,
}
impl<'a> Signature<'a> {
pub fn now(name: &str, email: &str) -> Result<Signature<'static>, Error> {
crate::init();
let mut ret = ptr::null_mut();
let name = CString::new(name)?;
let email = CString::new(email)?;
unsafe {
try_call!(raw::git_signature_now(&mut ret, name, email));
Ok(Binding::from_raw(ret))
}
}
pub fn new(name: &str, email: &str, time: &Time) -> Result<Signature<'static>, Error> {
crate::init();
let mut ret = ptr::null_mut();
let name = CString::new(name)?;
let email = CString::new(email)?;
unsafe {
try_call!(raw::git_signature_new(
&mut ret,
name,
email,
time.seconds() as raw::git_time_t,
time.offset_minutes() as libc::c_int
));
Ok(Binding::from_raw(ret))
}
}
pub fn name(&self) -> Option<&str> {
str::from_utf8(self.name_bytes()).ok()
}
pub fn name_bytes(&self) -> &[u8] {
unsafe { crate::opt_bytes(self, (*self.raw).name).unwrap() }
}
pub fn email(&self) -> Option<&str> {
str::from_utf8(self.email_bytes()).ok()
}
pub fn email_bytes(&self) -> &[u8] {
unsafe { crate::opt_bytes(self, (*self.raw).email).unwrap() }
}
pub fn when(&self) -> Time {
unsafe { Binding::from_raw((*self.raw).when) }
}
pub fn to_owned(&self) -> Signature<'static> {
unsafe {
let me = mem::transmute::<&Signature<'a>, &Signature<'static>>(self);
me.clone()
}
}
}
impl<'a> Binding for Signature<'a> {
type Raw = *mut raw::git_signature;
unsafe fn from_raw(raw: *mut raw::git_signature) -> Signature<'a> {
Signature {
raw,
_marker: marker::PhantomData,
owned: true,
}
}
fn raw(&self) -> *mut raw::git_signature {
self.raw
}
}
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::PhantomData,
owned: false,
}
}
impl Clone for Signature<'static> {
fn clone(&self) -> Signature<'static> {
let mut raw = ptr::null_mut();
let rc = unsafe { raw::git_signature_dup(&mut raw, &*self.raw) };
assert_eq!(rc, 0);
unsafe { Binding::from_raw(raw) }
}
}
impl<'a> Drop for Signature<'a> {
fn drop(&mut self) {
if self.owned {
unsafe { raw::git_signature_free(self.raw) }
}
}
}
impl<'a> fmt::Display for Signature<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{} <{}>",
String::from_utf8_lossy(self.name_bytes()),
String::from_utf8_lossy(self.email_bytes())
)
}
}
impl PartialEq for Signature<'_> {
fn eq(&self, other: &Self) -> bool {
self.when() == other.when()
&& self.email_bytes() == other.email_bytes()
&& self.name_bytes() == other.name_bytes()
}
}
impl Eq for Signature<'_> {}
#[cfg(test)]
mod tests {
use crate::{Signature, Time};
#[test]
fn smoke() {
Signature::new("foo", "bar", &Time::new(89, 0)).unwrap();
Signature::now("foo", "bar").unwrap();
assert!(Signature::new("<foo>", "bar", &Time::new(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());
drop(s.to_owned());
}
}