Skip to content

Commit

Permalink
Misc. cleanups and fixes. (#91)
Browse files Browse the repository at this point in the history
The commit does a few things:

- Deletes the builder (it's extra complexity for minimal benefit)
- Deletes the HashRef type in favor of methods directly
  on GitOid.
- Slightly reorganizes imports to be cleaner / clearer.
- Manually impls traits on GitOid because the derives
  were silently not working.
- Makes the ObjectType trait sealed

Plus a few other little cleanup changes.

Signed-off-by: Andrew Lilley Brinker <[email protected]>
  • Loading branch information
alilleybrinker authored Feb 12, 2024
1 parent 5bfe454 commit cc66d61
Show file tree
Hide file tree
Showing 9 changed files with 227 additions and 173 deletions.
64 changes: 0 additions & 64 deletions gitoid/src/builder.rs

This file was deleted.

13 changes: 6 additions & 7 deletions gitoid/src/ffi/gitoid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ use crate::ffi::error::Error;
use crate::ffi::status::Status;
use crate::ffi::util::check_null;
use crate::ffi::util::write_to_c_buf;
use crate::Blob;
use crate::Commit;
use crate::object::Blob;
use crate::object::Commit;
use crate::object::Tag;
use crate::object::Tree;
use crate::GitOid;
use crate::Tag;
use crate::Tree;
use core::ffi::c_char;
use core::ffi::c_int;
use core::ffi::CStr;
Expand Down Expand Up @@ -299,7 +299,7 @@ macro_rules! generate_gitoid_ffi_for_hash {
let output = catch_panic(|| {
check_null(ptr, Error::GitOidPtrIsNull)?;
let gitoid = unsafe { &*ptr };
let hash = gitoid.0.hash();
let hash = gitoid.0.as_bytes();
Ok(hash.as_ptr())
});

Expand All @@ -319,8 +319,7 @@ macro_rules! generate_gitoid_ffi_for_hash {
let output = catch_panic(|| {
check_null(ptr, Error::GitOidPtrIsNull)?;
let gitoid = unsafe { &*ptr };
let hash = gitoid.0.hash();
let hash_str = hash.as_hex();
let hash_str = gitoid.0.as_hex();
let hash_c_str = CString::new(hash_str)?;
Ok(hash_c_str.into_raw())
});
Expand Down
182 changes: 151 additions & 31 deletions gitoid/src/gitoid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@
use crate::Error;
use crate::HashAlgorithm;
use crate::HashRef;
use crate::ObjectType;
use crate::Result;
use core::fmt;
use core::fmt::Display;
use core::fmt::Formatter;
use core::hash::Hash;
use core::marker::PhantomData;
Expand All @@ -15,18 +12,21 @@ use digest::OutputSizeUser;
use generic_array::sequence::GenericSequence;
use generic_array::ArrayLength;
use generic_array::GenericArray;
use std::io::BufReader;
use std::cmp::Ordering;
use std::fmt::Debug;
use std::fmt::Display;
use std::fmt::Result as FmtResult;
use std::io::Read;
use std::io::Seek;
use std::io::SeekFrom;
use std::str::Split;
use std::{hash::Hasher, io::BufReader};
use url::Url;

/// A struct that computes [gitoids][g] based on the selected algorithm
///
/// [g]: https://git-scm.com/book/en/v2/Git-Internals-Git-Objects
#[repr(C)]
#[derive(Clone, Copy, PartialOrd, Eq, Ord, Debug, Hash, PartialEq)]
pub struct GitOid<H, O>
where
H: HashAlgorithm,
Expand All @@ -41,18 +41,6 @@ where
value: GenericArray<u8, H::OutputSize>,
}

impl<H, O> Display for GitOid<H, O>
where
H: HashAlgorithm,
O: ObjectType,
<H as OutputSizeUser>::OutputSize: ArrayLength<u8>,
GenericArray<u8, H::OutputSize>: Copy,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}", H::NAME, self.hash())
}
}

impl<H, O> GitOid<H, O>
where
H: HashAlgorithm,
Expand All @@ -73,18 +61,38 @@ where
}

/// Create a new `GitOid` based on a slice of bytes.
pub fn new_from_bytes(content: &[u8]) -> GitOid<H, O> {
let digester = H::new();
let reader = BufReader::new(content);
let expected_length = content.len();
pub fn new_from_bytes<B: AsRef<[u8]>>(content: B) -> GitOid<H, O> {
fn inner<H, O>(content: &[u8]) -> GitOid<H, O>
where
H: HashAlgorithm,
O: ObjectType,
<H as OutputSizeUser>::OutputSize: ArrayLength<u8>,
GenericArray<u8, H::OutputSize>: Copy,
{
let digester = H::new();
let reader = BufReader::new(content);
let expected_length = content.len();

// PANIC SAFETY: We're reading from an in-memory buffer, so no IO errors can arise.
gitoid_from_buffer(digester, reader, expected_length).unwrap()
}

// PANIC SAFETY: We're reading from an in-memory buffer, so no IO errors can arise.
gitoid_from_buffer(digester, reader, expected_length).unwrap()
inner(content.as_ref())
}

/// Create a `GitOid` from a UTF-8 string slice.
pub fn new_from_str(s: &str) -> GitOid<H, O> {
GitOid::new_from_bytes(s.as_bytes())
pub fn new_from_str<S: AsRef<str>>(s: S) -> GitOid<H, O> {
fn inner<H, O>(s: &str) -> GitOid<H, O>
where
H: HashAlgorithm,
O: ObjectType,
<H as OutputSizeUser>::OutputSize: ArrayLength<u8>,
GenericArray<u8, H::OutputSize>: Copy,
{
GitOid::new_from_bytes(s.as_bytes())
}

inner(s.as_ref())
}

/// Create a `GitOid` from a reader.
Expand All @@ -108,23 +116,28 @@ where

/// Get a URL for the current `GitOid`.
pub fn url(&self) -> Url {
let s = format!("gitoid:{}:{}:{}", O::NAME, H::NAME, self.hash());
let s = format!("gitoid:{}:{}:{}", O::NAME, H::NAME, self.as_hex());
// PANIC SAFETY: We know that this is a valid URL.
Url::parse(&s).unwrap()
}

/// Get the hash data as a slice of bytes.
pub fn hash(&self) -> HashRef<'_> {
HashRef::new(&self.value[..])
/// Get the underlying bytes of the hash.
pub fn as_bytes(&self) -> &[u8] {
&self.value[..]
}

/// Convert the hash to a hexadecimal string.
pub fn as_hex(&self) -> String {
hex::encode(self.as_bytes())
}

/// Get the hash algorithm used for the `GitOid`.
pub fn hash_algorithm(&self) -> &'static str {
pub const fn hash_algorithm(&self) -> &'static str {
H::NAME
}

/// Get the object type of the `GitOid`.
pub fn object_type(&self) -> &'static str {
pub const fn object_type(&self) -> &'static str {
O::NAME
}

Expand All @@ -134,6 +147,113 @@ where
}
}

impl<H, O> Clone for GitOid<H, O>
where
H: HashAlgorithm,
O: ObjectType,
<H as OutputSizeUser>::OutputSize: ArrayLength<u8>,
GenericArray<u8, H::OutputSize>: Copy,
{
fn clone(&self) -> Self {
*self
}
}

impl<H, O> Copy for GitOid<H, O>
where
H: HashAlgorithm,
O: ObjectType,
<H as OutputSizeUser>::OutputSize: ArrayLength<u8>,
GenericArray<u8, H::OutputSize>: Copy,
{
}

impl<H, O> PartialEq<GitOid<H, O>> for GitOid<H, O>
where
H: HashAlgorithm,
O: ObjectType,
<H as OutputSizeUser>::OutputSize: ArrayLength<u8>,
GenericArray<u8, H::OutputSize>: Copy,
{
fn eq(&self, other: &GitOid<H, O>) -> bool {
self.value == other.value
}
}

impl<H, O> Eq for GitOid<H, O>
where
H: HashAlgorithm,
O: ObjectType,
<H as OutputSizeUser>::OutputSize: ArrayLength<u8>,
GenericArray<u8, H::OutputSize>: Copy,
{
}

impl<H, O> PartialOrd<GitOid<H, O>> for GitOid<H, O>
where
H: HashAlgorithm,
O: ObjectType,
<H as OutputSizeUser>::OutputSize: ArrayLength<u8>,
GenericArray<u8, H::OutputSize>: Copy,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}

impl<H, O> Ord for GitOid<H, O>
where
H: HashAlgorithm,
O: ObjectType,
<H as OutputSizeUser>::OutputSize: ArrayLength<u8>,
GenericArray<u8, H::OutputSize>: Copy,
{
fn cmp(&self, other: &Self) -> Ordering {
self.value.cmp(&other.value)
}
}

impl<H, O> Hash for GitOid<H, O>
where
H: HashAlgorithm,
O: ObjectType,
<H as OutputSizeUser>::OutputSize: ArrayLength<u8>,
GenericArray<u8, H::OutputSize>: Copy,
{
fn hash<H2>(&self, state: &mut H2)
where
H2: Hasher,
{
self.value.hash(state);
}
}

impl<H, O> Debug for GitOid<H, O>
where
H: HashAlgorithm,
O: ObjectType,
<H as OutputSizeUser>::OutputSize: ArrayLength<u8>,
GenericArray<u8, H::OutputSize>: Copy,
{
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
f.debug_struct("GitOid")
.field("value", &self.value)
.finish()
}
}

impl<H, O> Display for GitOid<H, O>
where
H: HashAlgorithm,
O: ObjectType,
<H as OutputSizeUser>::OutputSize: ArrayLength<u8>,
GenericArray<u8, H::OutputSize>: Copy,
{
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "{}:{}", H::NAME, self.as_hex())
}
}

struct GitOidUrlParser<'u, H, O>
where
H: HashAlgorithm,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Trait specifying valid [`GitOid`] hash algorithms.
use crate::named_digest::private::Sealed;
use crate::sealed::Sealed;
#[cfg(doc)]
use crate::GitOid;
use digest::Digest;
Expand Down
Loading

0 comments on commit cc66d61

Please sign in to comment.