basecoin_store/utils/
codec.rs

1use core::marker::PhantomData;
2
3use serde::de::DeserializeOwned;
4use serde::Serialize;
5
6/// A trait that defines how types are decoded/encoded.
7pub trait Codec {
8    type Value;
9
10    type Encoded: AsRef<[u8]>;
11
12    fn encode(d: &Self::Value) -> Option<Self::Encoded>;
13
14    fn decode(bytes: &[u8]) -> Option<Self::Value>;
15}
16
17/// A JSON codec that uses `serde_json` to encode/decode as a JSON string
18#[derive(Clone, Debug)]
19pub struct JsonCodec<T>(PhantomData<T>);
20
21impl<T> Codec for JsonCodec<T>
22where
23    T: Serialize + DeserializeOwned,
24{
25    type Value = T;
26    type Encoded = String;
27
28    fn encode(d: &Self::Value) -> Option<Self::Encoded> {
29        serde_json::to_string(d).ok()
30    }
31
32    fn decode(bytes: &[u8]) -> Option<Self::Value> {
33        let json_string = String::from_utf8(bytes.to_vec()).ok()?;
34        serde_json::from_str(&json_string).ok()
35    }
36}
37
38/// A Null codec that can be used for paths that are only meant to be set/reset and do not hold any
39/// typed value.
40#[derive(Clone, Debug)]
41pub struct NullCodec;
42
43impl Codec for NullCodec {
44    type Value = ();
45    type Encoded = Vec<u8>;
46
47    fn encode(_d: &Self::Value) -> Option<Self::Encoded> {
48        // using [0x00] to represent null
49        Some(vec![0x00])
50    }
51
52    fn decode(bytes: &[u8]) -> Option<Self::Value> {
53        match bytes {
54            // the encoded bytes must be [0x00]
55            [0x00] => Some(()),
56            _ => None,
57        }
58    }
59}
60
61/// A Protobuf codec that uses `prost` to encode/decode
62#[derive(Clone, Debug)]
63pub struct ProtobufCodec<T, R> {
64    domain_type: PhantomData<T>,
65    raw_type: PhantomData<R>,
66}
67
68impl<T, R> Codec for ProtobufCodec<T, R>
69where
70    T: Into<R> + Clone,
71    R: TryInto<T> + Default + prost::Message,
72{
73    type Value = T;
74    type Encoded = Vec<u8>;
75
76    fn encode(d: &Self::Value) -> Option<Self::Encoded> {
77        let r = d.clone().into();
78        Some(r.encode_to_vec())
79    }
80
81    fn decode(bytes: &[u8]) -> Option<Self::Value> {
82        let r = R::decode(bytes).ok()?;
83        r.try_into().ok()
84    }
85}
86
87/// A binary codec that uses `AsRef<[u8]>` and `From<Vec<u8>>` to encode and decode respectively.
88#[derive(Clone, Debug)]
89pub struct BinCodec<T>(PhantomData<T>);
90
91impl<T> Codec for BinCodec<T>
92where
93    T: AsRef<[u8]> + From<Vec<u8>>,
94{
95    type Value = T;
96    type Encoded = Vec<u8>;
97
98    fn encode(d: &Self::Value) -> Option<Self::Encoded> {
99        Some(d.as_ref().to_vec())
100    }
101
102    fn decode(bytes: &[u8]) -> Option<Self::Value> {
103        Some(bytes.to_vec().into())
104    }
105}