1pub mod store;
24
25use std::{
26 borrow::Borrow,
27 hash::{Hash, Hasher},
28};
29
30use bytes::Bytes;
31use libp2p_core::{multihash::Multihash, Multiaddr};
32use libp2p_identity::PeerId;
33#[cfg(feature = "serde")]
34use serde::{Deserialize, Serialize};
35use web_time::Instant;
36
37#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
39#[derive(Clone, Debug, PartialEq, Eq, Hash)]
40pub struct Key(Bytes);
41
42impl Key {
43 pub fn new<K: AsRef<[u8]>>(key: &K) -> Self {
45 Key(Bytes::copy_from_slice(key.as_ref()))
46 }
47
48 pub fn to_vec(&self) -> Vec<u8> {
50 Vec::from(&self.0[..])
51 }
52}
53
54impl Borrow<[u8]> for Key {
55 fn borrow(&self) -> &[u8] {
56 &self.0[..]
57 }
58}
59
60impl AsRef<[u8]> for Key {
61 fn as_ref(&self) -> &[u8] {
62 &self.0[..]
63 }
64}
65
66impl From<Vec<u8>> for Key {
67 fn from(v: Vec<u8>) -> Key {
68 Key(Bytes::from(v))
69 }
70}
71
72impl<const S: usize> From<Multihash<S>> for Key {
73 fn from(m: Multihash<S>) -> Key {
74 Key::from(m.to_bytes())
75 }
76}
77
78#[derive(Clone, Debug, Eq, PartialEq)]
80pub struct Record {
81 pub key: Key,
83 pub value: Vec<u8>,
85 pub publisher: Option<PeerId>,
87 pub expires: Option<Instant>,
89}
90
91impl Record {
92 pub fn new<K>(key: K, value: Vec<u8>) -> Self
94 where
95 K: Into<Key>,
96 {
97 Record {
98 key: key.into(),
99 value,
100 publisher: None,
101 expires: None,
102 }
103 }
104
105 pub fn is_expired(&self, now: Instant) -> bool {
107 self.expires.is_some_and(|t| now >= t)
108 }
109}
110
111#[derive(Clone, Debug)]
118pub struct ProviderRecord {
119 pub key: Key,
121 pub provider: PeerId,
123 pub expires: Option<Instant>,
125 pub addresses: Vec<Multiaddr>,
127}
128
129impl Hash for ProviderRecord {
130 fn hash<H: Hasher>(&self, state: &mut H) {
131 self.key.hash(state);
132 self.provider.hash(state);
133 }
134}
135
136impl PartialEq for ProviderRecord {
137 fn eq(&self, other: &Self) -> bool {
138 self.key == other.key && self.provider == other.provider
139 }
140}
141
142impl Eq for ProviderRecord {}
143
144impl ProviderRecord {
145 pub fn new<K>(key: K, provider: PeerId, addresses: Vec<Multiaddr>) -> Self
147 where
148 K: Into<Key>,
149 {
150 ProviderRecord {
151 key: key.into(),
152 provider,
153 expires: None,
154 addresses,
155 }
156 }
157
158 pub fn is_expired(&self, now: Instant) -> bool {
160 self.expires.is_some_and(|t| now >= t)
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use std::time::Duration;
167
168 use quickcheck::*;
169
170 use super::*;
171 use crate::SHA_256_MH;
172
173 impl Arbitrary for Key {
174 fn arbitrary(g: &mut Gen) -> Key {
175 let hash: [u8; 32] = core::array::from_fn(|_| u8::arbitrary(g));
176 Key::from(Multihash::<64>::wrap(SHA_256_MH, &hash).unwrap())
177 }
178 }
179
180 impl Arbitrary for Record {
181 fn arbitrary(g: &mut Gen) -> Record {
182 Record {
183 key: Key::arbitrary(g),
184 value: Vec::arbitrary(g),
185 publisher: if bool::arbitrary(g) {
186 Some(PeerId::random())
187 } else {
188 None
189 },
190 expires: if bool::arbitrary(g) {
191 Some(Instant::now() + Duration::from_secs(g.gen_range(0..60)))
192 } else {
193 None
194 },
195 }
196 }
197 }
198
199 impl Arbitrary for ProviderRecord {
200 fn arbitrary(g: &mut Gen) -> ProviderRecord {
201 ProviderRecord {
202 key: Key::arbitrary(g),
203 provider: PeerId::random(),
204 expires: if bool::arbitrary(g) {
205 Some(Instant::now() + Duration::from_secs(g.gen_range(0..60)))
206 } else {
207 None
208 },
209 addresses: vec![],
210 }
211 }
212 }
213}