tfhe_versionable/
deprecation.rs

1//! Handle the deprecation of older versions of some types
2
3use std::error::Error;
4use std::fmt::Display;
5use std::marker::PhantomData;
6
7use serde::{Deserialize, Serialize};
8
9use crate::{UnversionizeError, Upgrade, Version};
10
11/// This trait should be implemented for types that have deprecated versions. You can then use them
12/// inside the dispatch enum by wrapping them into the [`Deprecated`] type.
13pub trait Deprecable {
14    const TYPE_NAME: &'static str;
15    const MIN_SUPPORTED_APP_VERSION: &'static str;
16
17    fn error() -> DeprecatedVersionError {
18        DeprecatedVersionError {
19            type_name: Self::TYPE_NAME.to_string(),
20            min_supported_app_version: Self::MIN_SUPPORTED_APP_VERSION.to_string(),
21        }
22    }
23}
24
25/// An error returned when trying to interact (unserialize or unversionize) with a deprecated type.
26#[derive(Debug)]
27pub struct DeprecatedVersionError {
28    type_name: String,
29    min_supported_app_version: String,
30}
31
32impl Display for DeprecatedVersionError {
33    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34        write!(
35            f,
36            "Deprecated {} found in serialized data, minimal supported version is {}",
37            self.type_name, self.min_supported_app_version
38        )
39    }
40}
41
42impl Error for DeprecatedVersionError {}
43
44/// Wrapper type that can be used inside the dispatch enum for a type to mark a version that has
45/// been deprecated.
46///
47/// For example:
48/// ```rust
49/// use tfhe_versionable::deprecation::{Deprecable, Deprecated};
50/// use tfhe_versionable::{Versionize, VersionsDispatch};
51/// #[derive(Versionize)]
52/// #[versionize(MyStructVersions)]
53/// struct MyStruct;
54///
55/// impl Deprecable for MyStruct {
56///     const TYPE_NAME: &'static str = "MyStruct";
57///     const MIN_SUPPORTED_APP_VERSION: &'static str = "my_app v2";
58/// }
59///
60/// #[derive(VersionsDispatch)]
61/// #[allow(unused)]
62/// pub enum MyStructVersions {
63///     V0(Deprecated<MyStruct>),
64///     V1(Deprecated<MyStruct>),
65///     V2(MyStruct),
66/// }
67/// ```
68pub struct Deprecated<T> {
69    _phantom: PhantomData<T>,
70}
71
72/// This type is used in the [`Version`] trait but should not be manually used.
73pub struct DeprecatedVersion<T> {
74    _phantom: PhantomData<T>,
75}
76
77// Manual impl of Serialize/Deserialize to be able to catch them and return a meaningful error to
78// the user.
79
80impl<T: Deprecable> Serialize for DeprecatedVersion<T> {
81    fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
82    where
83        S: serde::Serializer,
84    {
85        Err(serde::ser::Error::custom(
86            "a DeprecatedVersion should never be serialized",
87        ))
88    }
89}
90
91impl<'de, T: Deprecable> Deserialize<'de> for DeprecatedVersion<T> {
92    fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
93    where
94        D: serde::Deserializer<'de>,
95    {
96        Err(<D::Error as serde::de::Error>::custom(T::error()))
97    }
98}
99
100impl<T: Deprecable> Version for Deprecated<T> {
101    // Since the type is a ZST we directly use it without a reference
102    type Ref<'vers>
103        = DeprecatedVersion<T>
104    where
105        T: 'vers;
106
107    type Owned = DeprecatedVersion<T>;
108}
109
110impl<T: Deprecable> From<Deprecated<T>> for DeprecatedVersion<T> {
111    fn from(_value: Deprecated<T>) -> Self {
112        Self {
113            _phantom: PhantomData,
114        }
115    }
116}
117
118impl<T: Deprecable> From<&Deprecated<T>> for DeprecatedVersion<T> {
119    fn from(_value: &Deprecated<T>) -> Self {
120        Self {
121            _phantom: PhantomData,
122        }
123    }
124}
125
126impl<T: Deprecable> TryFrom<DeprecatedVersion<T>> for Deprecated<T> {
127    type Error = UnversionizeError;
128
129    fn try_from(_value: DeprecatedVersion<T>) -> Result<Self, Self::Error> {
130        Err(UnversionizeError::DeprecatedVersion(T::error()))
131    }
132}
133
134impl<T: Deprecable, U> Upgrade<U> for Deprecated<T> {
135    type Error = DeprecatedVersionError;
136
137    fn upgrade(self) -> Result<U, Self::Error> {
138        Err(T::error())
139    }
140}