Skip to content

Commit 4cd70f1

Browse files
committed
Introduce persistence traits
Add persistence abstractions with `Value` and `Persister` traits to define a common interface for storing and retrieving Payjoin related datastructures. The `Value` trait enables types to generate their own storage keys, while the Persister trait provides a generic interface for saving and loading values. The no-op implementation stores values in memory without actual persistence. Issue: payjoin#336
1 parent 8f68d8d commit 4cd70f1

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
lines changed

payjoin/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ pub mod receive;
2828
#[cfg(feature = "_core")]
2929
pub mod send;
3030

31+
#[cfg(feature = "v2")]
32+
pub mod persist;
33+
3134
#[cfg(feature = "v2")]
3235
pub(crate) mod hpke;
3336
#[cfg(feature = "v2")]

payjoin/src/persist/mod.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
use std::fmt::Display;
2+
3+
/// Types that can generate their own keys for persistent storage
4+
pub trait Value: serde::Serialize + serde::de::DeserializeOwned + Sized + Clone {
5+
type Key: AsRef<[u8]> + Clone + Display;
6+
7+
/// Unique identifier for this persisted value
8+
fn key(&self) -> Self::Key;
9+
}
10+
11+
/// Implemented types that should be persisted by the application.
12+
pub trait Persister<V: Value> {
13+
type Token: From<V>;
14+
type Error: std::error::Error + Send + Sync + 'static;
15+
16+
fn save(&mut self, value: V) -> Result<Self::Token, Self::Error>;
17+
fn load(&self, token: Self::Token) -> Result<V, Self::Error>;
18+
}
19+
20+
/// A key type that stores the value itself for no-op persistence
21+
#[derive(Debug, Clone, serde::Serialize)]
22+
pub struct NoopToken<V: Value>(V);
23+
24+
impl<V: Value> AsRef<[u8]> for NoopToken<V> {
25+
fn as_ref(&self) -> &[u8] {
26+
// Since this is a no-op implementation, we can return an empty slice
27+
// as we never actually need to use the bytes
28+
&[]
29+
}
30+
}
31+
32+
impl<'de, V: Value> serde::Deserialize<'de> for NoopToken<V> {
33+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
34+
where
35+
D: serde::Deserializer<'de>,
36+
{
37+
Ok(NoopToken(V::deserialize(deserializer)?))
38+
}
39+
}
40+
41+
impl<V: Value> Value for NoopToken<V> {
42+
type Key = V::Key;
43+
44+
fn key(&self) -> Self::Key { self.0.key() }
45+
}
46+
47+
/// A persister that does nothing but store values in memory
48+
#[derive(Debug, Clone)]
49+
pub struct NoopPersister;
50+
51+
impl<V: Value> From<V> for NoopToken<V> {
52+
fn from(value: V) -> Self { NoopToken(value) }
53+
}
54+
impl<V: Value> Persister<V> for NoopPersister {
55+
type Token = NoopToken<V>;
56+
type Error = std::convert::Infallible;
57+
58+
fn save(&mut self, value: V) -> Result<Self::Token, Self::Error> { Ok(NoopToken(value)) }
59+
60+
fn load(&self, token: Self::Token) -> Result<V, Self::Error> { Ok(token.0) }
61+
}

0 commit comments

Comments
 (0)