hyveos_core/dht.rs
1#[cfg(feature = "serde")]
2use serde::{Deserialize, Serialize};
3
4use crate::{
5 error::{Error, Result},
6 grpc,
7};
8
9#[derive(Debug, Clone, Hash, PartialEq, Eq)]
10#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
11pub struct Key {
12 pub topic: String,
13 pub key: Vec<u8>,
14}
15
16impl Key {
17 /// Create a vector of bytes from the key.
18 ///
19 /// The key is a concatenation of the topic and the key, separated by a slash.
20 ///
21 /// # Errors
22 ///
23 /// Returns an error if the topic contains a slash.
24 ///
25 /// # Example
26 ///
27 /// ```
28 /// use hyveos_core::dht::Key;
29 ///
30 /// let key = Key {
31 /// topic: "topic".to_string(),
32 /// key: "key".into(),
33 /// };
34 ///
35 /// let bytes = key.into_bytes().unwrap();
36 ///
37 /// assert_eq!(bytes, b"topic/key");
38 /// ```
39 pub fn into_bytes(self) -> Result<Vec<u8>> {
40 let topic_bytes = self.topic.into_bytes();
41
42 if topic_bytes.contains(&b'/') {
43 return Err(Error::InvalidTopic);
44 }
45
46 Ok(topic_bytes
47 .into_iter()
48 .chain(Some(b'/'))
49 .chain(self.key)
50 .collect())
51 }
52
53 /// Create a key from a vector of bytes.
54 ///
55 /// The bytes should be a concatenation of the topic and the key, separated by a slash.
56 ///
57 /// # Errors
58 ///
59 /// Returns an error if the bytes do not contain a slash or if the topic is not valid UTF-8.
60 ///
61 /// # Example
62 ///
63 /// ```
64 /// use hyveos_core::dht::Key;
65 ///
66 /// let bytes = b"topic/key".to_vec();
67 /// let key = Key::from_bytes(bytes).unwrap();
68 ///
69 /// assert_eq!(key.topic, "topic");
70 /// assert_eq!(&key.key, b"key");
71 /// ```
72 pub fn from_bytes(mut bytes: Vec<u8>) -> Result<Self> {
73 let index = bytes
74 .iter()
75 .position(|b| *b == b'/')
76 .ok_or(Error::InvalidKey("Should contain '/'".to_string()))?;
77
78 let key = bytes.split_off(index + 1);
79 bytes.pop();
80
81 let topic = String::from_utf8(bytes).map_err(|e| Error::InvalidKey(e.to_string()))?;
82
83 Ok(Self { topic, key })
84 }
85}
86
87impl From<Key> for grpc::DhtKey {
88 fn from(key: Key) -> Self {
89 Self {
90 topic: grpc::Topic { topic: key.topic },
91 key: key.key,
92 }
93 }
94}
95
96impl From<grpc::DhtKey> for Key {
97 fn from(key: grpc::DhtKey) -> Self {
98 Self {
99 topic: key.topic.topic,
100 key: key.key,
101 }
102 }
103}