pub trait TryMigrate:
TryFrom<Self::TryFrom>
+ Any
+ DeserializeOwned
+ Debug {
type TryFrom: TryMigrate;
type Error: From<<Self as TryFrom<<Self as TryMigrate>::TryFrom>>::Error> + From<<<Self as TryMigrate>::TryFrom as TryMigrate>::Error> + Display + Debug;
// Required method
fn deserializer<'de>(input: &'de str) -> impl Deserializer<'de>;
// Provided method
fn try_from_str_migrations(
input: &str,
) -> Option<Result<Self, <Self as TryMigrate>::Error>> { ... }
}Expand description
Use the TryMigrate trait when structs CANNOT be infallibly migrated
from one version to the next and an error may be returned. For infallible
migration see Migrate.
Like Migrate each implementation of this trait creates a link in a migration
chain. To have a full chain, the first struct must implement this trait
(TryMigrate) on itself.
In addition to specifying the struct links and the deserializer (like Migrate)
you must also specify what error to return when the migration chain fails. This
error must be able to hold any error created in the migration chain.
In practice that means From must be implemented
on error types in the migration chain going into the error.
§Example
use magic_migrate::TryMigrate;
// First define a migration on the beginning of the chain
//
// In this scenario `PersonV1` only converts from itself.
//
// Implement the `deserializer` function to tell magic migrate
// the data format that the input string will be in. In this case
// we are using `toml`.
impl TryMigrate for PersonV1 {
type TryFrom = Self;
type Error = PersonMigrationError;
fn deserializer<'de>(input: &'de str) -> impl serde::de::Deserializer<'de> {
magic_migrate::de::toml(input)
}
}
// The first struct references itself, in the chain (it's how we know
// to stop iterating). A by-product is that the error in `TryMigrate`
// must be able to take `Infallible` even though that error cannot be raised
impl From<std::convert::Infallible> for PersonMigrationError {
fn from(_value: std::convert::Infallible) -> Self {
unreachable!();
}
}
// Now define the second link in the migration chain by
// specifying that `PersonV2` can be built from `PersonV1`.
//
// The deserializer function body can be reused from `PersonV1`
impl TryMigrate for PersonV2 {
type TryFrom = PersonV1;
type Error = PersonMigrationError;
fn deserializer<'de>(input: &'de str) -> impl serde::de::Deserializer<'de> {
<Self as TryMigrate>::TryFrom::deserializer(input)
}
}
// That's it! Now, you can use it.
// Given a serialized struct
let toml_string = toml::to_string(&PersonV1 {
name: "Schneems".to_string(),
title: Some("Señor Developer".to_string())
}).unwrap();
// Cannot deserialize PersonV1 toml into PersonV2
let result = toml::from_str::<PersonV2>(&toml_string);
assert!(result.is_err());
// Can deserialize to PersonV1 then migrate to PersonV2
let person: PersonV2 = PersonV2::try_from_str_migrations(&toml_string).unwrap().unwrap();
assert_eq!(person.name, "Schneems".to_string());
// Conversion can fail (missing title)
let result = PersonV2::try_from_str_migrations(&"name = 'Schneems'").unwrap();
assert!(result.is_err());Required Associated Types§
type TryFrom: TryMigrate
type Error: From<<Self as TryFrom<<Self as TryMigrate>::TryFrom>>::Error> + From<<<Self as TryMigrate>::TryFrom as TryMigrate>::Error> + Display + Debug
Required Methods§
Sourcefn deserializer<'de>(input: &'de str) -> impl Deserializer<'de>
fn deserializer<'de>(input: &'de str) -> impl Deserializer<'de>
Tell magic migrate how you want to deserialize your strings into structs
Provided Methods§
fn try_from_str_migrations( input: &str, ) -> Option<Result<Self, <Self as TryMigrate>::Error>>
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.
Implementors§
Source§impl<T> TryMigrate for Twhere
T: Migrate,
Implement TryMigrate for all structs that infailably
can Migrate.
impl<T> TryMigrate for Twhere
T: Migrate,
Implement TryMigrate for all structs that infailably
can Migrate.