libp2p_gossipsub/
topic.rs1use std::fmt;
22
23use base64::prelude::*;
24use prometheus_client::encoding::EncodeLabelSet;
25use quick_protobuf::Writer;
26use sha2::{Digest, Sha256};
27
28use crate::rpc_proto::proto;
29
30pub trait Hasher {
32 fn hash(topic_string: String) -> TopicHash;
34}
35
36#[derive(Debug, Clone)]
38pub struct IdentityHash {}
39impl Hasher for IdentityHash {
40 fn hash(topic_string: String) -> TopicHash {
42 TopicHash { hash: topic_string }
43 }
44}
45
46#[derive(Debug, Clone)]
47pub struct Sha256Hash {}
48impl Hasher for Sha256Hash {
49 fn hash(topic_string: String) -> TopicHash {
52 use quick_protobuf::MessageWrite;
53
54 let topic_descripter = proto::TopicDescriptor {
55 name: Some(topic_string),
56 auth: None,
57 enc: None,
58 };
59 let mut bytes = Vec::with_capacity(topic_descripter.get_size());
60 let mut writer = Writer::new(&mut bytes);
61 topic_descripter
62 .write_message(&mut writer)
63 .expect("Encoding to succeed");
64 let hash = BASE64_STANDARD.encode(Sha256::digest(&bytes));
65 TopicHash { hash }
66 }
67}
68
69#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, EncodeLabelSet)]
70pub struct TopicHash {
71 hash: String,
73}
74
75impl TopicHash {
76 pub fn from_raw(hash: impl Into<String>) -> TopicHash {
77 TopicHash { hash: hash.into() }
78 }
79
80 pub fn into_string(self) -> String {
81 self.hash
82 }
83
84 pub fn as_str(&self) -> &str {
85 &self.hash
86 }
87}
88
89#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
91pub struct Topic<H: Hasher> {
92 topic: String,
93 phantom_data: std::marker::PhantomData<H>,
94}
95
96impl<H: Hasher> From<Topic<H>> for TopicHash {
97 fn from(topic: Topic<H>) -> TopicHash {
98 topic.hash()
99 }
100}
101
102impl<H: Hasher> Topic<H> {
103 pub fn new(topic: impl Into<String>) -> Self {
104 Topic {
105 topic: topic.into(),
106 phantom_data: std::marker::PhantomData,
107 }
108 }
109
110 pub fn hash(&self) -> TopicHash {
111 H::hash(self.topic.clone())
112 }
113}
114
115impl<H: Hasher> fmt::Display for Topic<H> {
116 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
117 write!(f, "{}", self.topic)
118 }
119}
120
121impl fmt::Display for TopicHash {
122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123 write!(f, "{}", self.hash)
124 }
125}