sc_network_types/
multihash.rs1use litep2p::types::multihash::{Code as LiteP2pCode, MultihashDigest as _};
23use multihash::Multihash as LiteP2pMultihash;
24use std::fmt::{self, Debug};
25
26const MULTIHASH_IDENTITY_CODE: u64 = 0x00;
33
34#[derive(Clone, Copy, Debug, PartialEq, Eq)]
36pub enum Code {
37 Identity,
39 Sha2_256,
41}
42
43impl Code {
44 pub fn digest(&self, input: &[u8]) -> Multihash {
46 match self {
47 Code::Identity => LiteP2pMultihash::<64>::wrap(MULTIHASH_IDENTITY_CODE, input)
48 .expect("identity digest fits in Multihash<64>; qed")
49 .into(),
50 Code::Sha2_256 => LiteP2pCode::Sha2_256.digest(input).into(),
51 }
52 }
53}
54
55#[derive(Debug, thiserror::Error)]
57pub enum Error {
58 #[error("invalid multihash size '{0}'")]
60 InvalidSize(u64),
61 #[error("unsupported multihash code '{0:x}'")]
63 UnsupportedCode(u64),
64 #[error("other error: {0}")]
67 Other(Box<dyn std::error::Error + Send + Sync>),
68}
69
70impl From<multihash::Error> for Error {
71 fn from(error: multihash::Error) -> Self {
72 Self::Other(Box::new(error))
75 }
76}
77
78impl TryFrom<u64> for Code {
79 type Error = Error;
80
81 fn try_from(code: u64) -> Result<Self, Self::Error> {
82 if code == MULTIHASH_IDENTITY_CODE {
83 Ok(Code::Identity)
84 } else if code == u64::from(LiteP2pCode::Sha2_256) {
85 Ok(Code::Sha2_256)
86 } else {
87 Err(Error::UnsupportedCode(code))
88 }
89 }
90}
91
92impl From<Code> for u64 {
93 fn from(code: Code) -> Self {
94 match code {
95 Code::Identity => MULTIHASH_IDENTITY_CODE,
96 Code::Sha2_256 => u64::from(LiteP2pCode::Sha2_256),
97 }
98 }
99}
100
101#[derive(Clone, Copy, Hash, PartialEq, Eq, Ord, PartialOrd)]
102pub struct Multihash {
103 multihash: LiteP2pMultihash<64>,
104}
105
106impl Multihash {
107 pub fn code(&self) -> u64 {
109 self.multihash.code()
110 }
111
112 pub fn digest(&self) -> &[u8] {
114 self.multihash.digest()
115 }
116
117 pub fn wrap(code: u64, input_digest: &[u8]) -> Result<Self, Error> {
119 LiteP2pMultihash::<64>::wrap(code, input_digest)
120 .map(Into::into)
121 .map_err(Into::into)
122 }
123
124 pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
128 LiteP2pMultihash::<64>::from_bytes(bytes).map(Into::into).map_err(Into::into)
129 }
130
131 pub fn to_bytes(&self) -> Vec<u8> {
133 self.multihash.to_bytes()
134 }
135}
136
137impl Debug for Multihash {
139 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140 Debug::fmt(&self.multihash, f)
141 }
142}
143
144impl From<LiteP2pMultihash<64>> for Multihash {
145 fn from(multihash: LiteP2pMultihash<64>) -> Self {
146 Multihash { multihash }
147 }
148}
149
150impl From<Multihash> for LiteP2pMultihash<64> {
151 fn from(multihash: Multihash) -> Self {
152 multihash.multihash
153 }
154}
155
156#[cfg(test)]
157mod tests {
158 use super::*;
159
160 #[test]
161 fn code_from_u64() {
162 assert_eq!(Code::try_from(0x00).unwrap(), Code::Identity);
163 assert_eq!(Code::try_from(0x12).unwrap(), Code::Sha2_256);
164 assert!(matches!(Code::try_from(0x01).unwrap_err(), Error::UnsupportedCode(0x01)));
165 }
166
167 #[test]
168 fn code_into_u64() {
169 assert_eq!(u64::from(Code::Identity), 0x00);
170 assert_eq!(u64::from(Code::Sha2_256), 0x12);
171 }
172}