summaryrefslogtreecommitdiffstats
path: root/vendor/git2/src/oid.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--vendor/git2/src/oid.rs259
1 files changed, 259 insertions, 0 deletions
diff --git a/vendor/git2/src/oid.rs b/vendor/git2/src/oid.rs
new file mode 100644
index 0000000..145458a
--- /dev/null
+++ b/vendor/git2/src/oid.rs
@@ -0,0 +1,259 @@
+use libc;
+use std::cmp::Ordering;
+use std::fmt;
+use std::hash::{Hash, Hasher};
+use std::path::Path;
+use std::str;
+
+use crate::{raw, Error, IntoCString, ObjectType};
+
+use crate::util::{c_cmp_to_ordering, Binding};
+
+/// Unique identity of any object (commit, tree, blob, tag).
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct Oid {
+ raw: raw::git_oid,
+}
+
+impl Oid {
+ /// Parse a hex-formatted object id into an Oid structure.
+ ///
+ /// # Errors
+ ///
+ /// Returns an error if the string is empty, is longer than 40 hex
+ /// characters, or contains any non-hex characters.
+ pub fn from_str(s: &str) -> Result<Oid, Error> {
+ crate::init();
+ let mut raw = raw::git_oid {
+ id: [0; raw::GIT_OID_RAWSZ],
+ };
+ unsafe {
+ try_call!(raw::git_oid_fromstrn(
+ &mut raw,
+ s.as_bytes().as_ptr() as *const libc::c_char,
+ s.len() as libc::size_t
+ ));
+ }
+ Ok(Oid { raw })
+ }
+
+ /// Parse a raw object id into an Oid structure.
+ ///
+ /// If the array given is not 20 bytes in length, an error is returned.
+ pub fn from_bytes(bytes: &[u8]) -> Result<Oid, Error> {
+ crate::init();
+ let mut raw = raw::git_oid {
+ id: [0; raw::GIT_OID_RAWSZ],
+ };
+ if bytes.len() != raw::GIT_OID_RAWSZ {
+ Err(Error::from_str("raw byte array must be 20 bytes"))
+ } else {
+ unsafe {
+ try_call!(raw::git_oid_fromraw(&mut raw, bytes.as_ptr()));
+ }
+ Ok(Oid { raw })
+ }
+ }
+
+ /// Creates an all zero Oid structure.
+ pub fn zero() -> Oid {
+ let out = raw::git_oid {
+ id: [0; raw::GIT_OID_RAWSZ],
+ };
+ Oid { raw: out }
+ }
+
+ /// Hashes the provided data as an object of the provided type, and returns
+ /// an Oid corresponding to the result. This does not store the object
+ /// inside any object database or repository.
+ pub fn hash_object(kind: ObjectType, bytes: &[u8]) -> Result<Oid, Error> {
+ crate::init();
+
+ let mut out = raw::git_oid {
+ id: [0; raw::GIT_OID_RAWSZ],
+ };
+ unsafe {
+ try_call!(raw::git_odb_hash(
+ &mut out,
+ bytes.as_ptr() as *const libc::c_void,
+ bytes.len(),
+ kind.raw()
+ ));
+ }
+
+ Ok(Oid { raw: out })
+ }
+
+ /// Hashes the content of the provided file as an object of the provided type,
+ /// and returns an Oid corresponding to the result. This does not store the object
+ /// inside any object database or repository.
+ pub fn hash_file<P: AsRef<Path>>(kind: ObjectType, path: P) -> Result<Oid, Error> {
+ crate::init();
+
+ // Normal file path OK (does not need Windows conversion).
+ let rpath = path.as_ref().into_c_string()?;
+
+ let mut out = raw::git_oid {
+ id: [0; raw::GIT_OID_RAWSZ],
+ };
+ unsafe {
+ try_call!(raw::git_odb_hashfile(&mut out, rpath, kind.raw()));
+ }
+
+ Ok(Oid { raw: out })
+ }
+
+ /// View this OID as a byte-slice 20 bytes in length.
+ pub fn as_bytes(&self) -> &[u8] {
+ &self.raw.id
+ }
+
+ /// Test if this OID is all zeros.
+ pub fn is_zero(&self) -> bool {
+ unsafe { raw::git_oid_iszero(&self.raw) == 1 }
+ }
+}
+
+impl Binding for Oid {
+ type Raw = *const raw::git_oid;
+
+ unsafe fn from_raw(oid: *const raw::git_oid) -> Oid {
+ Oid { raw: *oid }
+ }
+ fn raw(&self) -> *const raw::git_oid {
+ &self.raw as *const _
+ }
+}
+
+impl fmt::Debug for Oid {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+impl fmt::Display for Oid {
+ /// Hex-encode this Oid into a formatter.
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut dst = [0u8; raw::GIT_OID_HEXSZ + 1];
+ unsafe {
+ raw::git_oid_tostr(
+ dst.as_mut_ptr() as *mut libc::c_char,
+ dst.len() as libc::size_t,
+ &self.raw,
+ );
+ }
+ let s = &dst[..dst.iter().position(|&a| a == 0).unwrap()];
+ str::from_utf8(s).unwrap().fmt(f)
+ }
+}
+
+impl str::FromStr for Oid {
+ type Err = Error;
+
+ /// Parse a hex-formatted object id into an Oid structure.
+ ///
+ /// # Errors
+ ///
+ /// Returns an error if the string is empty, is longer than 40 hex
+ /// characters, or contains any non-hex characters.
+ fn from_str(s: &str) -> Result<Oid, Error> {
+ Oid::from_str(s)
+ }
+}
+
+impl PartialEq for Oid {
+ fn eq(&self, other: &Oid) -> bool {
+ unsafe { raw::git_oid_equal(&self.raw, &other.raw) != 0 }
+ }
+}
+impl Eq for Oid {}
+
+impl PartialOrd for Oid {
+ fn partial_cmp(&self, other: &Oid) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for Oid {
+ fn cmp(&self, other: &Oid) -> Ordering {
+ c_cmp_to_ordering(unsafe { raw::git_oid_cmp(&self.raw, &other.raw) })
+ }
+}
+
+impl Hash for Oid {
+ fn hash<H: Hasher>(&self, into: &mut H) {
+ self.raw.id.hash(into)
+ }
+}
+
+impl AsRef<[u8]> for Oid {
+ fn as_ref(&self) -> &[u8] {
+ self.as_bytes()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use std::fs::File;
+ use std::io::prelude::*;
+
+ use super::Error;
+ use super::Oid;
+ use crate::ObjectType;
+ use tempfile::TempDir;
+
+ #[test]
+ fn conversions() {
+ assert!(Oid::from_str("foo").is_err());
+ assert!(Oid::from_str("decbf2be529ab6557d5429922251e5ee36519817").is_ok());
+ assert!(Oid::from_bytes(b"foo").is_err());
+ assert!(Oid::from_bytes(b"00000000000000000000").is_ok());
+ }
+
+ #[test]
+ fn comparisons() -> Result<(), Error> {
+ assert_eq!(Oid::from_str("decbf2b")?, Oid::from_str("decbf2b")?);
+ assert!(Oid::from_str("decbf2b")? <= Oid::from_str("decbf2b")?);
+ assert!(Oid::from_str("decbf2b")? >= Oid::from_str("decbf2b")?);
+ {
+ let o = Oid::from_str("decbf2b")?;
+ assert_eq!(o, o);
+ assert!(o <= o);
+ assert!(o >= o);
+ }
+ assert_eq!(
+ Oid::from_str("decbf2b")?,
+ Oid::from_str("decbf2b000000000000000000000000000000000")?
+ );
+ assert!(
+ Oid::from_bytes(b"00000000000000000000")? < Oid::from_bytes(b"00000000000000000001")?
+ );
+ assert!(Oid::from_bytes(b"00000000000000000000")? < Oid::from_str("decbf2b")?);
+ assert_eq!(
+ Oid::from_bytes(b"00000000000000000000")?,
+ Oid::from_str("3030303030303030303030303030303030303030")?
+ );
+ Ok(())
+ }
+
+ #[test]
+ fn zero_is_zero() {
+ assert!(Oid::zero().is_zero());
+ }
+
+ #[test]
+ fn hash_object() {
+ let bytes = "Hello".as_bytes();
+ assert!(Oid::hash_object(ObjectType::Blob, bytes).is_ok());
+ }
+
+ #[test]
+ fn hash_file() {
+ let td = TempDir::new().unwrap();
+ let path = td.path().join("hello.txt");
+ let mut file = File::create(&path).unwrap();
+ file.write_all("Hello".as_bytes()).unwrap();
+ assert!(Oid::hash_file(ObjectType::Blob, &path).is_ok());
+ }
+}