p2panda_rs/operation/
operation_version.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3use serde::{Deserialize, Deserializer, Serialize, Serializer};
4
5/// Operation format versions to introduce API changes in the future.
6///
7/// Operations contain the actual data of applications in the p2panda network and will be stored
8/// for an indefinite time on different machines. To allow an upgrade path in the future and
9/// support backwards compatibility for old data we can use this version number.
10#[derive(Copy, Clone, Debug, PartialEq, Eq)]
11pub enum OperationVersion {
12    /// The latest version number.
13    V1,
14}
15
16impl OperationVersion {
17    /// Returns the operation version encoded as u64.
18    pub fn as_u64(&self) -> u64 {
19        match self {
20            OperationVersion::V1 => 1,
21        }
22    }
23}
24
25impl Serialize for OperationVersion {
26    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
27    where
28        S: Serializer,
29    {
30        serializer.serialize_u64(self.as_u64())
31    }
32}
33
34impl<'de> Deserialize<'de> for OperationVersion {
35    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
36    where
37        D: Deserializer<'de>,
38    {
39        let version = u64::deserialize(deserializer)?;
40
41        match version {
42            1 => Ok(OperationVersion::V1),
43            _ => Err(serde::de::Error::custom(format!(
44                "unsupported operation version {}",
45                version
46            ))),
47        }
48    }
49}
50
51#[cfg(test)]
52mod tests {
53    use ciborium::cbor;
54
55    use crate::serde::{deserialize_into, serialize_from, serialize_value};
56
57    use super::OperationVersion;
58
59    #[test]
60    fn u64_representation() {
61        assert_eq!(OperationVersion::V1.as_u64(), 1);
62    }
63
64    #[test]
65    fn serialize() {
66        let bytes = serialize_from(OperationVersion::V1);
67        assert_eq!(bytes, vec![1]);
68    }
69
70    #[test]
71    fn deserialize() {
72        let version: OperationVersion = deserialize_into(&serialize_value(cbor!(1))).unwrap();
73        assert_eq!(version, OperationVersion::V1);
74
75        // Unsupported version number
76        let invalid_version = deserialize_into::<OperationVersion>(&serialize_value(cbor!(0)));
77        assert!(invalid_version.is_err());
78
79        // Can not be a string
80        let invalid_type = deserialize_into::<OperationVersion>(&serialize_value(cbor!("0")));
81        assert!(invalid_type.is_err());
82    }
83}