diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:41:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:41:41 +0000 |
commit | 10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87 (patch) | |
tree | bdffd5d80c26cf4a7a518281a204be1ace85b4c1 /vendor/git2/src/signature.rs | |
parent | Releasing progress-linux version 1.70.0+dfsg1-9~progress7.99u1. (diff) | |
download | rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.tar.xz rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.zip |
Merging upstream version 1.70.0+dfsg2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/git2/src/signature.rs')
-rw-r--r-- | vendor/git2/src/signature.rs | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/vendor/git2/src/signature.rs b/vendor/git2/src/signature.rs new file mode 100644 index 000000000..83fbbf593 --- /dev/null +++ b/vendor/git2/src/signature.rs @@ -0,0 +1,189 @@ +use libc; +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}; + +/// 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` while the `now` constructor omits the timestamp. The +/// [`Repository::signature`] method can be used to create a default signature +/// with name and email values read from the configuration. +/// +/// [`Repository::signature`]: struct.Repository.html#method.signature +pub struct Signature<'a> { + raw: *mut raw::git_signature, + _marker: marker::PhantomData<&'a str>, + 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> { + 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)) + } + } + + /// 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: &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)) + } + } + + /// 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()).ok() + } + + /// Gets the name on the signature as a byte slice. + pub fn name_bytes(&self) -> &[u8] { + unsafe { crate::opt_bytes(self, (*self.raw).name).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()).ok() + } + + /// Gets the email on the signature as a byte slice. + pub fn email_bytes(&self) -> &[u8] { + unsafe { crate::opt_bytes(self, (*self.raw).email).unwrap() } + } + + /// Get the `when` of this signature. + pub fn when(&self) -> Time { + unsafe { Binding::from_raw((*self.raw).when) } + } + + /// Convert a signature of any lifetime into an owned signature with a + /// static lifetime. + 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 + } +} + +/// 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::PhantomData, + owned: false, + } +} + +impl Clone for Signature<'static> { + fn clone(&self) -> Signature<'static> { + // TODO: can this be defined for 'a and just do a plain old copy if the + // lifetime isn't 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()); + } +} |