1use std::{
2 num::NonZeroUsize,
3 sync::{Arc, Mutex},
4};
5
6use iroh_base::PublicKey;
7
8type SignatureError = <PublicKey as TryFrom<&'static [u8]>>::Error;
9type PublicKeyBytes = [u8; PublicKey::LENGTH];
10
11#[derive(Debug, Clone)]
19pub struct KeyCache(Inner);
20
21#[derive(Debug, Clone)]
22enum Inner {
23 Disabled,
25 Shared(Arc<Mutex<lru::LruCache<PublicKey, ()>>>),
28}
29
30impl KeyCache {
31 #[cfg(all(test, feature = "server"))]
33 pub fn test() -> Self {
34 Self(Inner::Disabled)
35 }
36
37 pub fn new(capacity: usize) -> Self {
41 match NonZeroUsize::new(capacity) {
42 None => Self(Inner::Disabled),
43 Some(capacity) => {
44 let cache = lru::LruCache::new(capacity);
45 Self(Inner::Shared(Arc::new(Mutex::new(cache))))
46 }
47 }
48 }
49
50 pub fn key_from_slice(&self, slice: &[u8]) -> Result<PublicKey, SignatureError> {
52 let Inner::Shared(cache) = &self.0 else {
53 return PublicKey::try_from(slice);
54 };
55 let Ok(bytes) = PublicKeyBytes::try_from(slice) else {
56 return Err(PublicKey::try_from(slice).expect_err("invalid length"));
59 };
60 let mut cache = cache.lock().expect("not poisoned");
61 if let Some((key, _)) = cache.get_key_value(&bytes) {
62 return Ok(*key);
63 }
64 let key = PublicKey::from_bytes(&bytes)?;
65 cache.put(key, ());
66 Ok(key)
67 }
68}