|
| 1 | +extern crate unsigned_varint; |
| 2 | +#[macro_use] extern crate failure; |
| 3 | +extern crate serde; |
| 4 | + |
| 5 | + |
| 6 | +use unsigned_varint::{decode::u16 as decode_varint, |
| 7 | + encode::u16 as encode_varint, |
| 8 | + decode::Error as VarintError}; |
| 9 | + |
| 10 | +use serde::{Serialize, Serializer, ser::SerializeSeq}; |
| 11 | + |
| 12 | +#[derive(Debug, Fail)] |
| 13 | +pub enum Error { |
| 14 | + #[fail(display = "Codec {} unknown", _0)] |
| 15 | + InvalidCodec(u16), |
| 16 | + #[fail(display = "Can't parse varint: {}", _0)] |
| 17 | + VarintFailed(VarintError) |
| 18 | + |
| 19 | +} |
| 20 | + |
| 21 | +macro_rules! build_codec_enum { |
| 22 | + {$( $val:expr => $var:ident, )*} => { |
| 23 | + #[allow(non_camel_case_types)] |
| 24 | + #[derive(PartialEq, Eq, Clone, Copy, Debug)] |
| 25 | + pub enum Codec { |
| 26 | + $( $var, )* |
| 27 | + } |
| 28 | + |
| 29 | + use Codec::*; |
| 30 | + |
| 31 | + impl Codec { |
| 32 | + /// Get the base code. |
| 33 | + pub fn code(&self) -> u16 { |
| 34 | + match *self { |
| 35 | + $( $var => $val, )* |
| 36 | + } |
| 37 | + } |
| 38 | + |
| 39 | + /// Convert a code to a base. |
| 40 | + pub fn from_code(code: u16) -> Result<Codec, Error> { |
| 41 | + match code { |
| 42 | + $( $val => Ok($var), )* |
| 43 | + _ => Err(Error::InvalidCodec(code)), |
| 44 | + } |
| 45 | + } |
| 46 | + } |
| 47 | + } |
| 48 | +} |
| 49 | + |
| 50 | +// SOURCE: https://github.com/multiformats/multicodec/blob/master/table.csv |
| 51 | +build_codec_enum! { |
| 52 | + 0x55 => Bin, |
| 53 | + // bases encodings |
| 54 | + 0x01 => Base1, |
| 55 | + 0x07 => Base8, |
| 56 | + 0x09 => Base10, |
| 57 | + |
| 58 | + // serialization formats |
| 59 | + 0x51 => Cbor, |
| 60 | + 0x50 => Protobuf, |
| 61 | + 0x60 => Rlp, |
| 62 | + 0x63 => Bencode, |
| 63 | + |
| 64 | + // multiformats |
| 65 | + 0x30 => Multicodec, |
| 66 | + 0x31 => Multihash, |
| 67 | + 0x32 => Multiaddr, |
| 68 | + 0x33 => Multibase, |
| 69 | + |
| 70 | + // multihashes |
| 71 | + 0x11 => Sha1, |
| 72 | + 0x12 => Sha2_256, |
| 73 | + 0x13 => Sha2_512, |
| 74 | + 0x56 => Dbl_Sha2_256, |
| 75 | + 0x17 => Sha3_224, |
| 76 | + 0x16 => Sha3_256, |
| 77 | + 0x15 => Sha3_384, |
| 78 | + 0x14 => Sha3_512, |
| 79 | + 0x18 => Shake_128, |
| 80 | + 0x19 => Shake_256, |
| 81 | + 0x1A => Keccak_224, |
| 82 | + 0x1B => Keccak_256, |
| 83 | + 0x1C => Keccak_384, |
| 84 | + 0x1D => Keccak_512, |
| 85 | + 0x22 => Murmur3, |
| 86 | + 0xb201 => Blake2b_8, |
| 87 | + 0xb202 => Blake2b_16, |
| 88 | + 0xb203 => Blake2b_24, |
| 89 | + 0xb204 => Blake2b_32, |
| 90 | + 0xb205 => Blake2b_40, |
| 91 | + 0xb206 => Blake2b_48, |
| 92 | + 0xb207 => Blake2b_56, |
| 93 | + 0xb208 => Blake2b_64, |
| 94 | + 0xb209 => Blake2b_72, |
| 95 | + 0xb20a => Blake2b_80, |
| 96 | + 0xb20b => Blake2b_88, |
| 97 | + 0xb20c => Blake2b_96, |
| 98 | + 0xb20d => Blake2b_104, |
| 99 | + 0xb20e => Blake2b_112, |
| 100 | + 0xb20f => Blake2b_120, |
| 101 | + 0xb210 => Blake2b_128, |
| 102 | + 0xb211 => Blake2b_136, |
| 103 | + 0xb212 => Blake2b_144, |
| 104 | + 0xb213 => Blake2b_152, |
| 105 | + 0xb214 => Blake2b_160, |
| 106 | + 0xb215 => Blake2b_168, |
| 107 | + 0xb216 => Blake2b_176, |
| 108 | + 0xb217 => Blake2b_184, |
| 109 | + 0xb218 => Blake2b_192, |
| 110 | + 0xb219 => Blake2b_200, |
| 111 | + 0xb21a => Blake2b_208, |
| 112 | + 0xb21b => Blake2b_216, |
| 113 | + 0xb21c => Blake2b_224, |
| 114 | + 0xb21d => Blake2b_232, |
| 115 | + 0xb21e => Blake2b_240, |
| 116 | + 0xb21f => Blake2b_248, |
| 117 | + 0xb220 => Blake2b_256, |
| 118 | + 0xb221 => Blake2b_264, |
| 119 | + 0xb222 => Blake2b_272, |
| 120 | + 0xb223 => Blake2b_280, |
| 121 | + 0xb224 => Blake2b_288, |
| 122 | + 0xb225 => Blake2b_296, |
| 123 | + 0xb226 => Blake2b_304, |
| 124 | + 0xb227 => Blake2b_312, |
| 125 | + 0xb228 => Blake2b_320, |
| 126 | + 0xb229 => Blake2b_328, |
| 127 | + 0xb22a => Blake2b_336, |
| 128 | + 0xb22b => Blake2b_344, |
| 129 | + 0xb22c => Blake2b_352, |
| 130 | + 0xb22d => Blake2b_360, |
| 131 | + 0xb22e => Blake2b_368, |
| 132 | + 0xb22f => Blake2b_376, |
| 133 | + 0xb230 => Blake2b_384, |
| 134 | + 0xb231 => Blake2b_392, |
| 135 | + 0xb232 => Blake2b_400, |
| 136 | + 0xb233 => Blake2b_408, |
| 137 | + 0xb234 => Blake2b_416, |
| 138 | + 0xb235 => Blake2b_424, |
| 139 | + 0xb236 => Blake2b_432, |
| 140 | + 0xb237 => Blake2b_440, |
| 141 | + 0xb238 => Blake2b_448, |
| 142 | + 0xb239 => Blake2b_456, |
| 143 | + 0xb23a => Blake2b_464, |
| 144 | + 0xb23b => Blake2b_472, |
| 145 | + 0xb23c => Blake2b_480, |
| 146 | + 0xb23d => Blake2b_488, |
| 147 | + 0xb23e => Blake2b_496, |
| 148 | + 0xb23f => Blake2b_504, |
| 149 | + 0xb240 => Blake2b_512, |
| 150 | + 0xb241 => Blake2s_8, |
| 151 | + 0xb242 => Blake2s_16, |
| 152 | + 0xb243 => Blake2s_24, |
| 153 | + 0xb244 => Blake2s_32, |
| 154 | + 0xb245 => Blake2s_40, |
| 155 | + 0xb246 => Blake2s_48, |
| 156 | + 0xb247 => Blake2s_56, |
| 157 | + 0xb248 => Blake2s_64, |
| 158 | + 0xb249 => Blake2s_72, |
| 159 | + 0xb24a => Blake2s_80, |
| 160 | + 0xb24b => Blake2s_88, |
| 161 | + 0xb24c => Blake2s_96, |
| 162 | + 0xb24d => Blake2s_104, |
| 163 | + 0xb24e => Blake2s_112, |
| 164 | + 0xb24f => Blake2s_120, |
| 165 | + 0xb250 => Blake2s_128, |
| 166 | + 0xb251 => Blake2s_136, |
| 167 | + 0xb252 => Blake2s_144, |
| 168 | + 0xb253 => Blake2s_152, |
| 169 | + 0xb254 => Blake2s_160, |
| 170 | + 0xb255 => Blake2s_168, |
| 171 | + 0xb256 => Blake2s_176, |
| 172 | + 0xb257 => Blake2s_184, |
| 173 | + 0xb258 => Blake2s_192, |
| 174 | + 0xb259 => Blake2s_200, |
| 175 | + 0xb25a => Blake2s_208, |
| 176 | + 0xb25b => Blake2s_216, |
| 177 | + 0xb25c => Blake2s_224, |
| 178 | + 0xb25d => Blake2s_232, |
| 179 | + 0xb25e => Blake2s_240, |
| 180 | + 0xb25f => Blake2s_248, |
| 181 | + 0xb260 => Blake2s_256, |
| 182 | + |
| 183 | + // multiaddrs |
| 184 | + 0x04 => Ip4, |
| 185 | + 0x29 => Ip6, |
| 186 | + 0x06 => Tcp, |
| 187 | + 0x0111 => Udp, |
| 188 | + 0x21 => Dccp, |
| 189 | + 0x84 => Sctp, |
| 190 | + 0x012D => Udt, |
| 191 | + 0x012E => Utp, |
| 192 | + 0x01A5 => Ipfs, |
| 193 | + 0x01E0 => Http, |
| 194 | + 0x01BB => Https, |
| 195 | + 0x01CC => Quic, |
| 196 | + 0x01DD => Ws, |
| 197 | + 0x01BC => Onion, |
| 198 | + 0x0122 => P2p_Circuit, |
| 199 | + |
| 200 | + // IPLD formats |
| 201 | + 0x70 => Dag_Pb, |
| 202 | + 0x71 => Dag_Cbor, |
| 203 | + |
| 204 | + 0x78 => Git_Raw, |
| 205 | + |
| 206 | + 0x90 => Eth_Block, |
| 207 | + 0x91 => Eth_Block_List, |
| 208 | + 0x92 => Eth_Tx_Trie, |
| 209 | + 0x93 => Eth_Tx, |
| 210 | + 0x94 => Eth_Tx_Receipt_Trie, |
| 211 | + 0x95 => Eth_Tx_Receipt, |
| 212 | + 0x96 => Eth_State_Trie, |
| 213 | + 0x97 => Eth_Account_Snapshot, |
| 214 | + 0x98 => Eth_Storage_Trie, |
| 215 | + |
| 216 | + 0xb0 => Bitcoin_Block, |
| 217 | + 0xb1 => Bitcoin_Tx, |
| 218 | + |
| 219 | + 0xc0 => Zcash_Block, |
| 220 | + 0xc1 => Zcash_Tx, |
| 221 | + |
| 222 | + 0xd0 => Stellar_Block, |
| 223 | + 0xd1 => Stellar_Tx, |
| 224 | + |
| 225 | + 0x7b => Torrent_Info, |
| 226 | + 0x7c => Torrent_File, |
| 227 | + 0xed => Ed25519_Pub, |
| 228 | +} |
| 229 | + |
| 230 | + |
| 231 | +#[derive(PartialEq, Eq, Clone, Copy, Debug)] |
| 232 | +pub struct MultiCodec<'a> { |
| 233 | + codec: Codec, |
| 234 | + data: &'a [u8] |
| 235 | +} |
| 236 | + |
| 237 | +impl<'a> MultiCodec<'a> { |
| 238 | + /// create a new MultiCodec |
| 239 | + pub fn new(codec: Codec, data: &'a [u8]) -> MultiCodec { |
| 240 | + MultiCodec { codec, data } |
| 241 | + } |
| 242 | + /// try to parse a MultiCodec from a packed bytestring |
| 243 | + pub fn from(packed: &'a [u8]) -> Result<MultiCodec, Error> { |
| 244 | + let (code, data) = decode_varint(packed).map_err(|e| Error::VarintFailed(e))?; |
| 245 | + let codec = Codec::from_code(code)?; |
| 246 | + Ok(MultiCodec { codec, data }) |
| 247 | + } |
| 248 | + |
| 249 | + pub fn pack(&self) -> Vec<u8> { |
| 250 | + let mut buf = [0u8; 3]; |
| 251 | + encode_varint(self.codec.code(), &mut buf); |
| 252 | + let mut v : Vec<u8> = Vec::new(); |
| 253 | + for b in &buf { |
| 254 | + v.push(*b); |
| 255 | + // varint uses first bit to indicate another byte follows, stop if not the case |
| 256 | + if *b <= 127 { break } |
| 257 | + } |
| 258 | + v.extend(self.data); |
| 259 | + v |
| 260 | + } |
| 261 | +} |
| 262 | + |
| 263 | +impl<'a> Serialize for MultiCodec<'a> { |
| 264 | + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
| 265 | + where |
| 266 | + S: Serializer, |
| 267 | + { |
| 268 | + serializer.serialize_bytes(&self.pack()) |
| 269 | + } |
| 270 | +} |
| 271 | + |
| 272 | + |
| 273 | + |
| 274 | +#[cfg(test)] |
| 275 | +mod tests { |
| 276 | + use super::*; |
| 277 | + #[test] |
| 278 | + fn it_works() { |
| 279 | + let codec = MultiCodec::new(Codec::Sha2_256, b"EiC5TSe5k00"); |
| 280 | + let packed = codec.pack(); |
| 281 | + let redo = MultiCodec::from(&packed).unwrap(); |
| 282 | + assert_eq!(packed, "\x12EiC5TSe5k00".as_bytes()); |
| 283 | + assert_eq!(redo, codec); |
| 284 | + } |
| 285 | +} |
0 commit comments