1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//! Simple hash types.
//!
//! TODO: unify with hashes from `kitsune_p2p_types::bin_types`

/// 32 bytes
pub type Hash32 = [u8; 32];

/// Get the 32 byte slice of a larger slice representing hash data
///
/// # Panics
///
/// Panics if the slice length is not 32, 36, or 39.
pub fn hash_slice_32(v: &[u8]) -> &[u8] {
    let len = v.len();
    if len == 36 || len == 39 {
        &v[4..36]
    } else if len == 32 {
        v
    } else {
        panic!("hash_slice_32 function must only be used with a slice 32, 36, or 39 bytes long")
    }
}

/// Get a fake hash, for testing only.
#[cfg(feature = "test_utils")]
pub fn fake_hash() -> Hash32 {
    use rand::distributions::*;

    let mut rng = rand::thread_rng();
    let uni = Uniform::from(u8::MIN..=u8::MAX);
    let bytes: Vec<u8> = uni.sample_iter(&mut rng).take(32).collect();
    let bytes: [u8; 32] = bytes.try_into().unwrap();
    bytes
}

/// The hash of an Op
#[derive(
    Clone, Hash, PartialEq, Eq, PartialOrd, Ord, derive_more::Constructor, derive_more::From,
)]
pub struct OpHash(pub Hash32);

impl OpHash {
    /// Random fake hash for testing
    pub fn fake() -> Self {
        Self(fake_hash())
    }
}

/// The hash of an Agent
#[derive(
    Clone, Hash, PartialEq, Eq, PartialOrd, Ord, derive_more::Constructor, derive_more::From,
)]
pub struct AgentKey(pub Hash32);

impl AgentKey {
    /// Random fake hash for testing
    pub fn fake() -> Self {
        Self(fake_hash())
    }
}

/// The hash of a Region, which is the XOR of all OpHashes contained in this region.
#[derive(
    Clone,
    PartialEq,
    Eq,
    derive_more::Constructor,
    derive_more::Deref,
    derive_more::DerefMut,
    derive_more::From,
    serde::Serialize,
    serde::Deserialize,
)]
pub struct RegionHash(pub Hash32);

impl RegionHash {
    /// If the Vec is 32/36/39 long, construct a RegionHash from it
    pub fn from_vec(v: Vec<u8>) -> Option<Self> {
        if v.len() == 36 || v.len() == 39 {
            v[4..36].try_into().map(Self).ok()
        } else {
            v[..].try_into().map(Self).ok()
        }
    }
}

impl std::fmt::Debug for OpHash {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_fmt(format_args!("{}(0x", "OpHash"))?;
        for byte in &self.0 {
            f.write_fmt(format_args!("{:02x}", byte))?;
        }
        f.write_fmt(format_args!(")"))?;
        Ok(())
    }
}

impl std::fmt::Debug for AgentKey {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_fmt(format_args!("{}(0x", "AgentKey"))?;
        for byte in &self.0 {
            f.write_fmt(format_args!("{:02x}", byte))?;
        }
        f.write_fmt(format_args!(")"))?;
        Ok(())
    }
}

impl std::fmt::Debug for RegionHash {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_fmt(format_args!("{}(0x", "RegionHash"))?;
        for byte in &self.0 {
            f.write_fmt(format_args!("{:02x}", byte))?;
        }
        f.write_fmt(format_args!(")"))?;
        Ok(())
    }
}