oasis_core_runtime/common/
versioned.rs

1/// Version key used in serialized form.
2pub const VERSION_KEY: &str = "v";
3
4/// A generic versioned serializable data structure.
5#[derive(Clone, Debug, PartialEq, Eq, Hash)]
6pub struct Versioned<T> {
7    pub version: u16,
8    pub inner: T,
9}
10
11impl<T> Versioned<T> {
12    /// Create a new versioned structure.
13    pub fn new(version: u16, inner: T) -> Self {
14        Self { version, inner }
15    }
16}
17
18impl<T: cbor::EncodeAsMap> cbor::Encode for Versioned<T> {
19    fn into_cbor_value(self) -> cbor::Value {
20        let mut inner = cbor::EncodeAsMap::into_cbor_map(self.inner);
21        // Add version to the given map.
22        let key = cbor::values::IntoCborValue::into_cbor_value(VERSION_KEY);
23        inner.push((key, self.version.into_cbor_value()));
24        cbor::Value::Map(inner)
25    }
26}
27
28impl<T: cbor::Decode> cbor::Decode for Versioned<T> {
29    fn try_from_cbor_value(value: cbor::Value) -> Result<Self, cbor::DecodeError> {
30        match value {
31            cbor::Value::Map(mut items) => {
32                // Take the version field from the map and decode the rest.
33                let key = cbor::values::IntoCborValue::into_cbor_value(VERSION_KEY);
34                let (index, _) = items
35                    .iter()
36                    .enumerate()
37                    .find(|(_, v)| v.0 == key)
38                    .ok_or(cbor::DecodeError::MissingField)?;
39                let version = items.remove(index).1;
40
41                Ok(Self {
42                    version: cbor::Decode::try_from_cbor_value(version)?,
43                    inner: cbor::Decode::try_from_cbor_value(cbor::Value::Map(items))?,
44                })
45            }
46            _ => Err(cbor::DecodeError::UnexpectedType),
47        }
48    }
49}