libp2p_pubsub_core/
topic.rs1use std::convert::Infallible;
2use std::fmt;
3use std::str::FromStr;
4
5use base64::prelude::*;
6use prost::Message as _;
7use sha2::{Digest, Sha256};
8
9use libp2p_pubsub_proto::topic_descriptor::TopicDescriptorProto;
10
11pub type IdentTopic = Topic<IdentityHash>;
12pub type Sha256Topic = Topic<Sha256Hash>;
13
14pub trait Hasher {
16 fn hash(topic: String) -> TopicHash;
18}
19
20#[derive(Debug, Clone)]
22pub struct IdentityHash;
23
24impl Hasher for IdentityHash {
25 fn hash(topic_string: String) -> TopicHash {
27 TopicHash { hash: topic_string }
28 }
29}
30
31#[derive(Debug, Clone)]
32pub struct Sha256Hash;
33
34impl Hasher for Sha256Hash {
35 fn hash(topic_string: String) -> TopicHash {
38 let topic_descriptor = TopicDescriptorProto {
39 name: Some(topic_string),
40 auth: None,
41 enc: None,
42 };
43 let mut bytes = Vec::with_capacity(topic_descriptor.encoded_len());
44 topic_descriptor
45 .encode(&mut bytes)
46 .expect("Encoding to succeed");
47 let hash = BASE64_STANDARD.encode(Sha256::digest(&bytes));
48 TopicHash { hash }
49 }
50}
51
52#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
53pub struct TopicHash {
54 hash: String,
56}
57
58impl TopicHash {
59 pub fn from_raw<T: Into<String>>(raw: T) -> Self {
60 Self { hash: raw.into() }
61 }
62
63 pub fn into_string(self) -> String {
64 self.hash
65 }
66
67 pub fn as_str(&self) -> &str {
68 &self.hash
69 }
70}
71
72impl<T: Into<String>> From<T> for TopicHash {
73 fn from(hash: T) -> Self {
74 Self::from_raw(hash)
75 }
76}
77
78impl FromStr for TopicHash {
79 type Err = Infallible;
80
81 fn from_str(s: &str) -> Result<Self, Self::Err> {
82 Ok(Self::from_raw(s))
83 }
84}
85
86impl AsRef<str> for TopicHash {
87 fn as_ref(&self) -> &str {
88 self.as_str()
89 }
90}
91
92#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
94pub struct Topic<H: Hasher> {
95 topic: String,
96 phantom_data: std::marker::PhantomData<H>,
97}
98
99impl<H: Hasher> From<Topic<H>> for TopicHash {
100 fn from(topic: Topic<H>) -> TopicHash {
101 topic.hash()
102 }
103}
104
105impl<H: Hasher> Topic<H> {
106 pub fn new<T: Into<String>>(topic: T) -> Self {
107 Topic {
108 topic: topic.into(),
109 phantom_data: std::marker::PhantomData,
110 }
111 }
112
113 pub fn hash(&self) -> TopicHash {
114 H::hash(self.topic.clone())
115 }
116}
117
118impl<H: Hasher> fmt::Display for Topic<H> {
119 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
120 write!(f, "{}", self.topic)
121 }
122}
123
124impl fmt::Display for TopicHash {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 write!(f, "{}", self.hash)
127 }
128}