oasis_core_runtime/common/
key_format.rs

1use std::{convert::TryInto, mem::size_of};
2
3use impl_trait_for_tuples::impl_for_tuples;
4
5/// Size of the KeyFormat prefix.
6const KEY_FORMAT_PREFIX_SIZE: usize = size_of::<u8>();
7
8/// A key formatting helper trait to be used together with key-value
9/// backends for constructing keys.
10pub trait KeyFormat {
11    /// The prefix that identifies the key format.
12    fn prefix() -> u8;
13
14    /// The minimum size of the encoded key.
15    fn size() -> usize;
16
17    /// Encode the given key format into a set of atoms.
18    fn encode_atoms(self, atoms: &mut Vec<Vec<u8>>);
19
20    /// Decode the given key format from data (without prefix).
21    ///
22    /// The caller must ensure that the size of the passed data is at
23    /// least the minimum size returned by `size`.
24    fn decode_atoms(data: &[u8]) -> Self
25    where
26        Self: Sized;
27
28    /// Encode the first few atoms in the key format.
29    ///
30    /// This method can be used to construct key prefixes for iteration.
31    /// Specifying a zero count will only generate the prefix.
32    fn encode_partial(self, count: usize) -> Vec<u8>
33    where
34        Self: Sized,
35    {
36        let mut v = Vec::with_capacity(KEY_FORMAT_PREFIX_SIZE + Self::size());
37        v.push(Self::prefix());
38
39        if count == 0 {
40            return v;
41        }
42
43        let mut atoms = Vec::new();
44        self.encode_atoms(&mut atoms);
45        for (included, mut atom) in atoms.into_iter().enumerate() {
46            if included >= count {
47                break;
48            }
49            v.append(&mut atom);
50        }
51
52        v
53    }
54
55    /// Encode the given key format.
56    fn encode(self) -> Vec<u8>
57    where
58        Self: Sized,
59    {
60        self.encode_partial(usize::MAX)
61    }
62
63    /// Decode the given key format from data.
64    ///
65    /// The method may return `None` in case the key is of a different
66    /// type as indicated by the prefix byte.
67    fn decode(data: &[u8]) -> Option<Self>
68    where
69        Self: Sized,
70    {
71        assert!(!data.is_empty(), "key format: malformed input (empty data)");
72        if data[0] != Self::prefix() {
73            return None;
74        }
75        assert!(
76            data.len() >= Self::size() + KEY_FORMAT_PREFIX_SIZE,
77            "key format: malformed input"
78        );
79
80        Some(Self::decode_atoms(&data[1..]))
81    }
82}
83
84/// Part of the KeyFormat to be used with key-value backends for constructing keys.
85pub trait KeyFormatAtom {
86    fn size() -> usize;
87
88    fn encode_atom(self) -> Vec<u8>;
89
90    fn decode_atom(data: &[u8]) -> Self
91    where
92        Self: Sized;
93}
94
95impl KeyFormatAtom for u64 {
96    fn size() -> usize {
97        8
98    }
99
100    fn encode_atom(self) -> Vec<u8> {
101        self.to_be_bytes().to_vec()
102    }
103
104    fn decode_atom(data: &[u8]) -> Self
105    where
106        Self: Sized,
107    {
108        u64::from_be_bytes(data.try_into().expect("key_format: malformed u64 input"))
109    }
110}
111
112impl KeyFormatAtom for u8 {
113    fn size() -> usize {
114        1
115    }
116
117    fn encode_atom(self) -> Vec<u8> {
118        vec![self]
119    }
120
121    fn decode_atom(data: &[u8]) -> Self
122    where
123        Self: Sized,
124    {
125        assert!(!data.is_empty(), "key_format: malformed: u8 input");
126        data[0]
127    }
128}
129
130impl KeyFormatAtom for () {
131    fn size() -> usize {
132        0
133    }
134
135    fn encode_atom(self) -> Vec<u8> {
136        Vec::new()
137    }
138
139    fn decode_atom(_: &[u8]) {}
140}
141
142#[impl_for_tuples(2, 10)]
143impl KeyFormatAtom for Tuple {
144    fn size() -> usize {
145        for_tuples!( #( Tuple::size() )+* );
146    }
147
148    fn encode_atom(self) -> Vec<u8> {
149        let mut atoms: Vec<Vec<u8>> = [for_tuples!( #( self.Tuple.encode_atom() ),* )].to_vec();
150
151        atoms.into_iter().flatten().collect()
152    }
153
154    fn decode_atom(data: &[u8]) -> for_tuples!( ( #( Tuple ),* ) ) {
155        assert!(
156            data.len() >= Self::size(),
157            "key format atom: malformed input"
158        );
159
160        let mut sizes: Vec<usize> = [for_tuples!( #( Tuple::size() ),* )].to_vec();
161        sizes.reverse();
162        let mut data = data.to_vec();
163
164        /*
165            (
166                {
167                    let x = T1::decode_atom(data.drain(0..T1::size()));
168                    x
169                },
170                {
171                    let x = T2::decode_atom(data.drain(0..T2::size()));
172                    x
173                }
174                ...
175            )
176        */
177        for_tuples!(
178            (
179                #(
180                    {
181                        let x = Tuple::decode_atom(data.drain(0..sizes.pop().unwrap()).as_slice());
182                        x
183                    }
184                ),*
185            )
186        )
187    }
188}
189
190/// Define a KeyFormat from KeyFormatAtom and a prefix.
191///
192/// # Examples
193///
194/// ```rust,ignore
195/// key_format!(NewKeyFormatName, 0x01, InnerType);
196/// ```
197#[macro_export]
198macro_rules! key_format {
199    ($name:ident, $prefix:expr, $inner:ty) => {
200        #[derive(Debug, Default, PartialEq, Eq, Clone)]
201        struct $name($inner);
202
203        impl KeyFormat for $name {
204            fn prefix() -> u8 {
205                $prefix
206            }
207
208            fn size() -> usize {
209                <$inner>::size()
210            }
211
212            fn encode_atoms(self, atoms: &mut Vec<Vec<u8>>) {
213                atoms.push(self.0.encode_atom());
214            }
215
216            fn decode_atoms(data: &[u8]) -> Self {
217                Self(<$inner>::decode_atom(data))
218            }
219        }
220    };
221}
222
223#[cfg(test)]
224mod test {
225    use rustc_hex::ToHex;
226
227    use crate::common::crypto::hash::Hash;
228
229    use super::*;
230
231    #[derive(Debug, PartialEq)]
232    struct Test1KeyFormat {
233        h: Hash,
234    }
235
236    impl KeyFormat for Test1KeyFormat {
237        fn prefix() -> u8 {
238            b'T'
239        }
240
241        fn size() -> usize {
242            32
243        }
244
245        fn encode_atoms(self, atoms: &mut Vec<Vec<u8>>) {
246            atoms.push(self.h.as_ref().to_vec());
247        }
248
249        fn decode_atoms(data: &[u8]) -> Self {
250            Self { h: data.into() }
251        }
252    }
253
254    #[test]
255    fn test_key_format() {
256        let mut enc = Test1KeyFormat {
257            h: Hash::empty_hash(),
258        }
259        .encode();
260        assert_eq!(
261            enc.to_hex::<String>(),
262            "54c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a"
263        );
264
265        let dec = Test1KeyFormat::decode(&enc);
266        assert_eq!(
267            dec,
268            Some(Test1KeyFormat {
269                h: Hash::empty_hash()
270            })
271        );
272
273        // Clear type.
274        enc[0] = 0x00;
275        let dec = Test1KeyFormat::decode(&enc);
276        assert_eq!(dec, None);
277
278        // Partial encoding.
279        let enc = Test1KeyFormat {
280            h: Hash::empty_hash(),
281        }
282        .encode_partial(0);
283        assert_eq!(enc.to_hex::<String>(), "54");
284    }
285
286    #[test]
287    fn test_key_format_atom() {
288        key_format!(TestKeyFormat, 0x01, (u8, u64, u8, u64, u64));
289
290        let key = TestKeyFormat((1, 2, 3, 4, 5));
291        let enc = key.clone().encode();
292        let dec = TestKeyFormat::decode(&enc);
293
294        assert_eq!(dec, Some(key),)
295    }
296}