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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
use super::*;
use crate::error::HoloHashError;
use std::convert::TryInto;

#[cfg(feature = "serialization")]
use holochain_serialized_bytes::prelude::*;

/// The AnyDht (composite) HashType
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(
    feature = "serialization",
    derive(serde::Deserialize, serde::Serialize, SerializedBytes),
    serde(from = "AnyDhtSerial", into = "AnyDhtSerial")
)]
pub enum AnyDht {
    /// The hash of an Entry
    Entry,
    /// The hash of a Header
    Header,
}

impl HashType for AnyDht {
    fn get_prefix(self) -> &'static [u8] {
        match self {
            AnyDht::Entry => Entry::new().get_prefix(),
            AnyDht::Header => Header::new().get_prefix(),
        }
    }

    fn try_from_prefix(prefix: &[u8]) -> HoloHashResult<Self> {
        match prefix {
            primitive::ENTRY_PREFIX => Ok(AnyDht::Entry),
            primitive::HEADER_PREFIX => Ok(AnyDht::Header),
            _ => Err(HoloHashError::BadPrefix(
                "AnyDht".to_string(),
                prefix.try_into().expect("3 byte prefix"),
            )),
        }
    }

    fn hash_name(self) -> &'static str {
        "AnyDhtHash"
    }
}

impl HashTypeAsync for AnyDht {}

#[cfg_attr(
    feature = "serialization",
    derive(serde::Deserialize, serde::Serialize)
)]
enum AnyDhtSerial {
    /// The hash of an Entry of EntryType::Agent
    Header(Header),
    /// The hash of any other EntryType
    Entry(Entry),
}

impl From<AnyDht> for AnyDhtSerial {
    fn from(t: AnyDht) -> Self {
        match t {
            AnyDht::Header => AnyDhtSerial::Header(Header),
            AnyDht::Entry => AnyDhtSerial::Entry(Entry),
        }
    }
}

impl From<AnyDhtSerial> for AnyDht {
    fn from(t: AnyDhtSerial) -> Self {
        match t {
            AnyDhtSerial::Header(_) => AnyDht::Header,
            AnyDhtSerial::Entry(_) => AnyDht::Entry,
        }
    }
}

/// The AnyLinkable (composite) HashType
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(
    feature = "serialization",
    derive(serde::Deserialize, serde::Serialize, SerializedBytes),
    serde(from = "AnyLinkableSerial", into = "AnyLinkableSerial")
)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum AnyLinkable {
    /// The hash of an Entry
    Entry,
    /// The hash of a Header
    Header,
    /// The hash of an External thing.
    External,
}

#[cfg(feature = "arbitrary")]
impl<'a> arbitrary::Arbitrary<'a> for crate::HoloHash<AnyLinkable> {
    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
        let any_linkable = AnyLinkable::arbitrary(u)?;
        let some_hash = crate::HoloHash::<Entry>::arbitrary(u)?;
        Ok(some_hash.retype(any_linkable))
    }
}

impl HashType for AnyLinkable {
    fn get_prefix(self) -> &'static [u8] {
        match self {
            Self::Entry => Entry::new().get_prefix(),
            Self::Header => Header::new().get_prefix(),
            Self::External => External::new().get_prefix(),
        }
    }

    fn try_from_prefix(prefix: &[u8]) -> HoloHashResult<Self> {
        match prefix {
            primitive::ENTRY_PREFIX => Ok(AnyLinkable::Entry),
            primitive::HEADER_PREFIX => Ok(AnyLinkable::Header),
            primitive::EXTERNAL_PREFIX => Ok(AnyLinkable::External),
            _ => Err(HoloHashError::BadPrefix(
                "AnyLinkable".to_string(),
                prefix.try_into().expect("3 byte prefix"),
            )),
        }
    }

    fn hash_name(self) -> &'static str {
        "AnyLinkableHash"
    }
}

impl HashTypeSync for AnyLinkable {}

#[cfg_attr(
    feature = "serialization",
    derive(serde::Deserialize, serde::Serialize)
)]
enum AnyLinkableSerial {
    /// The hash of an Entry of EntryType::Agent
    Header(Header),
    /// The hash of any other EntryType
    Entry(Entry),
    /// The hash of any external thing.
    External(External),
}

impl From<AnyLinkable> for AnyLinkableSerial {
    fn from(t: AnyLinkable) -> Self {
        match t {
            AnyLinkable::Header => Self::Header(Header),
            AnyLinkable::Entry => Self::Entry(Entry),
            AnyLinkable::External => Self::External(External),
        }
    }
}

impl From<AnyLinkableSerial> for AnyLinkable {
    fn from(t: AnyLinkableSerial) -> Self {
        match t {
            AnyLinkableSerial::Header(_) => Self::Header,
            AnyLinkableSerial::Entry(_) => Self::Entry,
            AnyLinkableSerial::External(_) => Self::External,
        }
    }
}