use std::ffi::CString; use std::ptr; use crate::util::Binding; use crate::{raw, Error, Signature}; /// A structure to represent a repository's .mailmap file. /// /// The representation cannot be written to disk. pub struct Mailmap { raw: *mut raw::git_mailmap, } impl Binding for Mailmap { type Raw = *mut raw::git_mailmap; unsafe fn from_raw(ptr: *mut raw::git_mailmap) -> Mailmap { Mailmap { raw: ptr } } fn raw(&self) -> *mut raw::git_mailmap { self.raw } } impl Drop for Mailmap { fn drop(&mut self) { unsafe { raw::git_mailmap_free(self.raw); } } } impl Mailmap { /// Creates an empty, in-memory mailmap object. pub fn new() -> Result { crate::init(); let mut ret = ptr::null_mut(); unsafe { try_call!(raw::git_mailmap_new(&mut ret)); Ok(Binding::from_raw(ret)) } } /// Creates an in-memory mailmap object representing the given buffer. pub fn from_buffer(buf: &str) -> Result { crate::init(); let mut ret = ptr::null_mut(); let len = buf.len(); let buf = CString::new(buf)?; unsafe { try_call!(raw::git_mailmap_from_buffer(&mut ret, buf, len)); Ok(Binding::from_raw(ret)) } } /// Adds a new entry to this in-memory mailmap object. pub fn add_entry( &mut self, real_name: Option<&str>, real_email: Option<&str>, replace_name: Option<&str>, replace_email: &str, ) -> Result<(), Error> { let real_name = crate::opt_cstr(real_name)?; let real_email = crate::opt_cstr(real_email)?; let replace_name = crate::opt_cstr(replace_name)?; let replace_email = CString::new(replace_email)?; unsafe { try_call!(raw::git_mailmap_add_entry( self.raw, real_name, real_email, replace_name, replace_email )); Ok(()) } } /// Resolves a signature to its real name and email address. pub fn resolve_signature(&self, sig: &Signature<'_>) -> Result, Error> { let mut ret = ptr::null_mut(); unsafe { try_call!(raw::git_mailmap_resolve_signature( &mut ret, &*self.raw, sig.raw() )); Ok(Binding::from_raw(ret)) } } } #[cfg(test)] mod tests { use super::*; #[test] fn smoke() { let sig_name = "name"; let sig_email = "email"; let sig = t!(Signature::now(sig_name, sig_email)); let mut mm = t!(Mailmap::new()); let mailmapped_sig = t!(mm.resolve_signature(&sig)); assert_eq!(mailmapped_sig.name(), Some(sig_name)); assert_eq!(mailmapped_sig.email(), Some(sig_email)); t!(mm.add_entry(None, None, None, sig_email)); t!(mm.add_entry( Some("real name"), Some("real@email"), Some(sig_name), sig_email, )); let mailmapped_sig = t!(mm.resolve_signature(&sig)); assert_eq!(mailmapped_sig.name(), Some("real name")); assert_eq!(mailmapped_sig.email(), Some("real@email")); } #[test] fn from_buffer() { let buf = " "; let mm = t!(Mailmap::from_buffer(&buf)); let sig = t!(Signature::now("name", "email")); let mailmapped_sig = t!(mm.resolve_signature(&sig)); assert_eq!(mailmapped_sig.name(), Some("name")); assert_eq!(mailmapped_sig.email(), Some("prøper@emæil")); } }