chore(versionable)!: Impl std::error::Error for UnversionizeError

BREAKING CHANGE: The `Upgrade` trait now requires to specify the Error type as
an associated type (similar to `TryFrom`)
This commit is contained in:
Nicolas Sarlin
2024-07-11 10:00:12 +02:00
committed by Nicolas Sarlin
parent 4d934f512a
commit c8ddc0f008
17 changed files with 164 additions and 55 deletions

View File

@@ -336,7 +336,7 @@ impl DispatchType {
value
.upgrade()
.map_err(|e|
#error_ty::upgrade(#src_variant, #dest_variant, &e)
#error_ty::upgrade(#src_variant, #dest_variant, e)
)
})
}

View File

@@ -207,7 +207,7 @@ impl VersionizeAttribute {
} else if let Some(target) = &self.try_from {
let target_name = format!("{}", target.to_token_stream());
quote! { #target::unversionize(#arg_name).and_then(|value| TryInto::<Self>::try_into(value)
.map_err(|e| #error::conversion(#target_name, &format!("{}", e))))
.map_err(|e| #error::conversion(#target_name, e)))
}
} else {
quote! { #arg_name.try_into() }

View File

@@ -37,6 +37,9 @@ mod v1 {
pub struct MyStruct(pub u32);
mod backward_compat {
use std::error::Error;
use std::fmt::Display;
use tfhe_versionable::{Upgrade, Version, VersionsDispatch};
use super::MyStruct;
@@ -44,11 +47,23 @@ mod v1 {
#[derive(Version)]
pub struct MyStructV0(pub Option<u32>);
#[derive(Debug, Clone)]
pub struct EmptyValueError;
impl Display for EmptyValueError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Value is empty")
}
}
impl Error for EmptyValueError {}
impl Upgrade<MyStruct> for MyStructV0 {
fn upgrade(self) -> Result<MyStruct, String> {
type Error = EmptyValueError;
fn upgrade(self) -> Result<MyStruct, Self::Error> {
match self.0 {
Some(val) => Ok(MyStruct(val)),
None => Err("Cannot convert from empty \"MyStructV0\"".to_string()),
None => Err(EmptyValueError),
}
}
}

View File

@@ -1,5 +1,7 @@
//! The simple example, with manual implementation of the versionize trait
use std::convert::Infallible;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use tfhe_versionable::{Unversionize, UnversionizeError, Upgrade, Versionize, VersionizeOwned};
@@ -15,7 +17,9 @@ struct MyStructV0 {
}
impl<T: Default> Upgrade<MyStruct<T>> for MyStructV0 {
fn upgrade(self) -> Result<MyStruct<T>, String> {
type Error = Infallible;
fn upgrade(self) -> Result<MyStruct<T>, Self::Error> {
Ok(MyStruct {
attr: T::default(),
builtin: self.builtin,
@@ -68,7 +72,7 @@ impl<T: Default + VersionizeOwned + Unversionize + Serialize + DeserializeOwned>
match versioned {
MyStructVersionsDispatchOwned::V0(v0) => v0
.upgrade()
.map_err(|e| UnversionizeError::upgrade("V0", "V1", &e)),
.map_err(|e| UnversionizeError::upgrade("V0", "V1", e)),
MyStructVersionsDispatchOwned::V1(v1) => Ok(Self {
attr: T::unversionize(v1.attr)?,
builtin: v1.builtin,

View File

@@ -1,5 +1,7 @@
//! An example of recursive versioning
use std::convert::Infallible;
use tfhe_versionable::{Upgrade, Version, Versionize, VersionsDispatch};
#[derive(Versionize)]
@@ -15,7 +17,9 @@ struct MyStructInnerV0 {
}
impl<T: Default> Upgrade<MyStructInner<T>> for MyStructInnerV0 {
fn upgrade(self) -> Result<MyStructInner<T>, String> {
type Error = Infallible;
fn upgrade(self) -> Result<MyStructInner<T>, Self::Error> {
Ok(MyStructInner {
attr: T::default(),
builtin: 0,

View File

@@ -1,5 +1,7 @@
//! Shows a basic usage of this crate
use std::convert::Infallible;
use tfhe_versionable::{Unversionize, Upgrade, Version, Versionize, VersionsDispatch};
// The structure that should be versioned, as defined in your code
@@ -21,7 +23,9 @@ struct MyStructV0 {
// The Upgrade trait tells how to go from the first version to the last. During unversioning, the
// upgrade method will be called on the deserialized value enough times to go to the last variant.
impl<T: Default> Upgrade<MyStruct<T>> for MyStructV0 {
fn upgrade(self) -> Result<MyStruct<T>, String> {
type Error = Infallible;
fn upgrade(self) -> Result<MyStruct<T>, Self::Error> {
Ok(MyStruct {
attr: T::default(),
builtin: self.builtin,

View File

@@ -37,6 +37,8 @@ mod v1 {
pub struct MyStruct<T: Default>(pub u32, pub T);
mod backward_compat {
use std::convert::Infallible;
use tfhe_versionable::{Upgrade, Version, VersionsDispatch};
use super::MyStruct;
@@ -45,7 +47,9 @@ mod v1 {
pub struct MyStructV0(pub u32);
impl<T: Default> Upgrade<MyStruct<T>> for MyStructV0 {
fn upgrade(self) -> Result<MyStruct<T>, String> {
type Error = Infallible;
fn upgrade(self) -> Result<MyStruct<T>, Self::Error> {
Ok(MyStruct(self.0, T::default()))
}
}
@@ -81,6 +85,8 @@ mod v2 {
}
mod backward_compat {
use std::convert::Infallible;
use tfhe_versionable::{Upgrade, Version, VersionsDispatch};
use super::{MyEnum, MyStruct};
@@ -89,7 +95,9 @@ mod v2 {
pub struct MyStructV0(pub u32);
impl<T: Default> Upgrade<MyStructV1<T>> for MyStructV0 {
fn upgrade(self) -> Result<MyStructV1<T>, String> {
type Error = Infallible;
fn upgrade(self) -> Result<MyStructV1<T>, Self::Error> {
Ok(MyStructV1(self.0, T::default()))
}
}
@@ -98,7 +106,9 @@ mod v2 {
pub struct MyStructV1<T>(pub u32, pub T);
impl<T: Default> Upgrade<MyStruct<T>> for MyStructV1<T> {
fn upgrade(self) -> Result<MyStruct<T>, String> {
type Error = Infallible;
fn upgrade(self) -> Result<MyStruct<T>, Self::Error> {
Ok(MyStruct {
count: self.0,
attr: T::default(),

View File

@@ -12,6 +12,7 @@ pub mod upgrade;
use aligned_vec::{ABox, AVec};
use num_complex::Complex;
use std::convert::Infallible;
use std::error::Error;
use std::fmt::Display;
use std::marker::PhantomData;
use std::sync::Arc;
@@ -70,12 +71,15 @@ pub enum UnversionizeError {
Upgrade {
from_vers: String,
into_vers: String,
message: String,
source: Box<dyn Error>,
},
/// An error has been returned in the conversion method provided by the `try_from` parameter
/// attribute
Conversion { from_type: String, message: String },
Conversion {
from_type: String,
source: Box<dyn Error>,
},
}
impl Display for UnversionizeError {
@@ -84,31 +88,40 @@ impl Display for UnversionizeError {
Self::Upgrade {
from_vers,
into_vers,
message,
source,
} => write!(
f,
"Failed to upgrade from {from_vers} into {into_vers}: {message}"
"Failed to upgrade from {from_vers} into {into_vers}: {source}"
),
Self::Conversion { from_type, message } => {
write!(f, "Failed to convert from {from_type}: {message}")
Self::Conversion { from_type, source } => {
write!(f, "Failed to convert from {from_type}: {source}")
}
}
}
}
impl Error for UnversionizeError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
UnversionizeError::Upgrade { source, .. } => Some(source.as_ref()),
UnversionizeError::Conversion { source, .. } => Some(source.as_ref()),
}
}
}
impl UnversionizeError {
pub fn upgrade(from_vers: &str, into_vers: &str, message: &str) -> Self {
pub fn upgrade<E: Error + 'static>(from_vers: &str, into_vers: &str, source: E) -> Self {
Self::Upgrade {
from_vers: from_vers.to_string(),
into_vers: into_vers.to_string(),
message: message.to_string(),
source: Box::new(source),
}
}
pub fn conversion(from_type: &str, message: &str) -> Self {
pub fn conversion<E: Error + 'static>(from_type: &str, source: E) -> Self {
Self::Conversion {
from_type: from_type.to_string(),
message: message.to_string(),
source: Box::new(source),
}
}
}

View File

@@ -3,5 +3,6 @@
/// This trait should be implemented for each version of the original type that is not the current
/// one. The upgrade method is called in chains until we get to the last version of the type.
pub trait Upgrade<T> {
fn upgrade(self) -> Result<T, String>;
type Error: std::error::Error;
fn upgrade(self) -> Result<T, Self::Error>;
}

View File

@@ -49,6 +49,8 @@ mod v1 {
pub struct MyStruct<T: Default>(pub u32, pub T);
mod backward_compat {
use std::convert::Infallible;
use tfhe_versionable::{Upgrade, Version, VersionsDispatch};
use super::MyStruct;
@@ -57,7 +59,9 @@ mod v1 {
pub struct MyStructV0(pub u32);
impl<T: Default> Upgrade<MyStruct<T>> for MyStructV0 {
fn upgrade(self) -> Result<MyStruct<T>, String> {
type Error = Infallible;
fn upgrade(self) -> Result<MyStruct<T>, Self::Error> {
Ok(MyStruct(self.0, T::default()))
}
}
@@ -85,6 +89,8 @@ mod v2 {
}
mod backward_compat {
use std::convert::Infallible;
use tfhe_versionable::{Upgrade, Version, VersionsDispatch};
use super::MyStruct;
@@ -93,7 +99,9 @@ mod v2 {
pub struct MyStructV0(pub u32);
impl<T: Default> Upgrade<MyStructV1<T>> for MyStructV0 {
fn upgrade(self) -> Result<MyStructV1<T>, String> {
type Error = Infallible;
fn upgrade(self) -> Result<MyStructV1<T>, Self::Error> {
Ok(MyStructV1(self.0, T::default()))
}
}
@@ -102,7 +110,9 @@ mod v2 {
pub struct MyStructV1<T>(pub u32, pub T);
impl<T: Default> Upgrade<MyStruct<T>> for MyStructV1<T> {
fn upgrade(self) -> Result<MyStruct<T>, String> {
type Error = Infallible;
fn upgrade(self) -> Result<MyStruct<T>, Self::Error> {
Ok(MyStruct {
count: self.0,
attr: T::default(),