Skip to content

Commit

Permalink
Replace uses of content_hash! with #[derive(ContentHash)]
Browse files Browse the repository at this point in the history
This is a pure refactor with no behavior changes.

#3054
  • Loading branch information
emesterhazy committed Feb 20, 2024
1 parent 65d45e0 commit e8f324f
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 260 deletions.
146 changes: 43 additions & 103 deletions lib/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use std::vec::Vec;
use async_trait::async_trait;
use thiserror::Error;

use crate::content_hash::{ContentHash, DigestUpdate};
use crate::content_hash::ContentHash;
use crate::index::Index;
use crate::merge::Merge;
use crate::object_id::{id_type, ObjectId};
Expand All @@ -39,18 +39,14 @@ id_type!(pub FileId);
id_type!(pub SymlinkId);
id_type!(pub ConflictId);

content_hash! {
#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord)]
pub struct MillisSinceEpoch(pub i64);
}
#[derive(ContentHash, Debug, PartialEq, Eq, Clone, PartialOrd, Ord)]
pub struct MillisSinceEpoch(pub i64);

content_hash! {
#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord)]
pub struct Timestamp {
pub timestamp: MillisSinceEpoch,
// time zone offset in minutes
pub tz_offset: i32,
}
#[derive(ContentHash, Debug, PartialEq, Eq, Clone, PartialOrd, Ord)]
pub struct Timestamp {
pub timestamp: MillisSinceEpoch,
// time zone offset in minutes
pub tz_offset: i32,
}

impl Timestamp {
Expand All @@ -68,21 +64,17 @@ impl Timestamp {
}
}

content_hash! {
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Signature {
pub name: String,
pub email: String,
pub timestamp: Timestamp,
}
#[derive(ContentHash, Debug, PartialEq, Eq, Clone)]
pub struct Signature {
pub name: String,
pub email: String,
pub timestamp: Timestamp,
}

content_hash! {
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct SecureSig {
pub data: Vec<u8>,
pub sig: Vec<u8>,
}
#[derive(ContentHash, Debug, PartialEq, Eq, Clone)]
pub struct SecureSig {
pub data: Vec<u8>,
pub sig: Vec<u8>,
}

pub type SigningFn<'a> = dyn FnMut(&[u8]) -> SignResult<Vec<u8>> + 'a;
Expand All @@ -92,7 +84,7 @@ pub type SigningFn<'a> = dyn FnMut(&[u8]) -> SignResult<Vec<u8>> + 'a;
// TODO(#1624): Delete this type at some point in the future, when we decide to drop
// support for conflicts in older repos, or maybe after we have provided an upgrade
// mechanism.
#[derive(Debug, Clone)]
#[derive(ContentHash, Debug, Clone)]
pub enum MergedTreeId {
/// The tree id of a legacy tree
Legacy(TreeId),
Expand All @@ -110,21 +102,6 @@ impl PartialEq for MergedTreeId {

impl Eq for MergedTreeId {}

impl ContentHash for MergedTreeId {
fn hash(&self, state: &mut impl DigestUpdate) {
match self {
MergedTreeId::Legacy(tree_id) => {
state.update(&0u32.to_le_bytes());
ContentHash::hash(tree_id, state);
}
MergedTreeId::Merge(tree_ids) => {
state.update(&1u32.to_le_bytes());
ContentHash::hash(tree_ids, state);
}
}
}
}

impl MergedTreeId {
/// Create a resolved `MergedTreeId` from a single regular tree.
pub fn resolved(tree_id: TreeId) -> Self {
Expand All @@ -140,37 +117,31 @@ impl MergedTreeId {
}
}

content_hash! {
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Commit {
pub parents: Vec<CommitId>,
pub predecessors: Vec<CommitId>,
pub root_tree: MergedTreeId,
pub change_id: ChangeId,
pub description: String,
pub author: Signature,
pub committer: Signature,
pub secure_sig: Option<SecureSig>,
}
#[derive(ContentHash, Debug, PartialEq, Eq, Clone)]
pub struct Commit {
pub parents: Vec<CommitId>,
pub predecessors: Vec<CommitId>,
pub root_tree: MergedTreeId,
pub change_id: ChangeId,
pub description: String,
pub author: Signature,
pub committer: Signature,
pub secure_sig: Option<SecureSig>,
}

content_hash! {
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ConflictTerm {
pub value: TreeValue,
}
#[derive(ContentHash, Debug, PartialEq, Eq, Clone)]
pub struct ConflictTerm {
pub value: TreeValue,
}

content_hash! {
#[derive(Default, Debug, PartialEq, Eq, Clone)]
pub struct Conflict {
// A conflict is represented by a list of positive and negative states that need to be applied.
// In a simple 3-way merge of B and C with merge base A, the conflict will be { add: [B, C],
// remove: [A] }. Also note that a conflict of the form { add: [A], remove: [] } is the
// same as non-conflict A.
pub removes: Vec<ConflictTerm>,
pub adds: Vec<ConflictTerm>,
}
#[derive(ContentHash, Default, Debug, PartialEq, Eq, Clone)]
pub struct Conflict {
// A conflict is represented by a list of positive and negative states that need to be applied.
// In a simple 3-way merge of B and C with merge base A, the conflict will be { add: [B, C],
// remove: [A] }. Also note that a conflict of the form { add: [A], remove: [] } is the
// same as non-conflict A.
pub removes: Vec<ConflictTerm>,
pub adds: Vec<ConflictTerm>,
}

/// Error that may occur during backend initialization.
Expand Down Expand Up @@ -225,7 +196,7 @@ pub enum BackendError {

pub type BackendResult<T> = Result<T, BackendError>;

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
#[derive(ContentHash, Debug, PartialEq, Eq, Clone, Hash)]
pub enum TreeValue {
File { id: FileId, executable: bool },
Symlink(SymlinkId),
Expand All @@ -246,35 +217,6 @@ impl TreeValue {
}
}

impl ContentHash for TreeValue {
fn hash(&self, state: &mut impl DigestUpdate) {
use TreeValue::*;
match self {
File { id, executable } => {
state.update(&0u32.to_le_bytes());
id.hash(state);
executable.hash(state);
}
Symlink(id) => {
state.update(&1u32.to_le_bytes());
id.hash(state);
}
Tree(id) => {
state.update(&2u32.to_le_bytes());
id.hash(state);
}
GitSubmodule(id) => {
state.update(&3u32.to_le_bytes());
id.hash(state);
}
Conflict(id) => {
state.update(&4u32.to_le_bytes());
id.hash(state);
}
}
}
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct TreeEntry<'a> {
name: &'a RepoPathComponent,
Expand Down Expand Up @@ -309,11 +251,9 @@ impl<'a> Iterator for TreeEntriesNonRecursiveIterator<'a> {
}
}

content_hash! {
#[derive(Default, PartialEq, Eq, Debug, Clone)]
pub struct Tree {
entries: BTreeMap<RepoPathComponentBuf, TreeValue>,
}
#[derive(ContentHash, Default, PartialEq, Eq, Debug, Clone)]
pub struct Tree {
entries: BTreeMap<RepoPathComponentBuf, TreeValue>,
}

impl Tree {
Expand Down
62 changes: 7 additions & 55 deletions lib/src/content_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,33 +145,6 @@ where
}
}

macro_rules! content_hash {
($(#[$meta:meta])* $vis:vis struct $name:ident {
$($(#[$field_meta:meta])* $field_vis:vis $field:ident : $ty:ty),* $(,)?
}) => {
$(#[$meta])*
$vis struct $name {
$($(#[$field_meta])* $field_vis $field : $ty),*
}

impl crate::content_hash::ContentHash for $name {
fn hash(&self, state: &mut impl digest::Update) {
$(<$ty as crate::content_hash::ContentHash>::hash(&self.$field, state);)*
}
}
};
($(#[$meta:meta])* $vis:vis struct $name:ident($field_vis:vis $ty:ty);) => {
$(#[$meta])*
$vis struct $name($field_vis $ty);

impl crate::content_hash::ContentHash for $name {
fn hash(&self, state: &mut impl digest::Update) {
<$ty as crate::content_hash::ContentHash>::hash(&self.0, state);
}
}
};
}

#[cfg(test)]
mod tests {
use std::collections::{BTreeMap, HashMap};
Expand Down Expand Up @@ -215,8 +188,9 @@ mod tests {

#[test]
fn test_struct_sanity() {
content_hash! {
struct Foo { x: i32 }
#[derive(ContentHash)]
struct Foo {
x: i32,
}
assert_ne!(hash(&Foo { x: 42 }), hash(&Foo { x: 12 }));
}
Expand All @@ -237,8 +211,10 @@ mod tests {

#[test]
fn test_consistent_hashing() {
content_hash! {
struct Foo { x: Vec<Option<i32>>, y: i64 }
#[derive(ContentHash)]
struct Foo {
x: Vec<Option<i32>>,
y: i64,
}
let foo_hash = hex::encode(hash(&Foo {
x: vec![None, Some(42)],
Expand Down Expand Up @@ -276,30 +252,6 @@ mod tests {
assert_eq!(hash(&Option::<i32>::None), hash(&MyOption::<i32>::None));
assert_eq!(hash(&Some(1)), hash(&MyOption::Some(1)));
}
// This will be removed once all uses of content_hash! are replaced by the
// derive version.
#[test]
fn derive_is_equivalent_to_macro() {
content_hash! {
struct FooMacro { x: Vec<Option<i32>>, y: i64}
}

#[derive(ContentHash)]
struct FooDerive {
x: Vec<Option<i32>>,
y: i64,
}

let foo_macro = FooMacro {
x: vec![None, Some(42)],
y: 17,
};
let foo_derive = FooDerive {
x: vec![None, Some(42)],
y: 17,
};
assert_eq!(hash(&foo_macro), hash(&foo_derive));
}

fn hash(x: &(impl ContentHash + ?Sized)) -> digest::Output<Blake2b512> {
blake2b_hash(x)
Expand Down
6 changes: 2 additions & 4 deletions lib/src/object_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,8 @@ pub trait ObjectId {

macro_rules! id_type {
($vis:vis $name:ident) => {
content_hash! {
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
$vis struct $name(Vec<u8>);
}
#[derive(ContentHash, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
$vis struct $name(Vec<u8>);
$crate::object_id::impl_id_type!($name);
};
}
Expand Down
Loading

0 comments on commit e8f324f

Please sign in to comment.