Dans un projet où des méthodes personnalisées de sérialisation et de désérialisation de Serde (1.0) sont impliquées, je me suis appuyé sur cette routine de test pour vérifier si la sérialisation d'un objet et d'un retour produirait un objet équivalent.Comment pouvons-nous écrire une fonction générique pour vérifier la sérialisation Serde et la désérialisation?
// let o: T = ...;
let buf: Vec<u8> = to_vec(&o).unwrap();
let o2: T = from_slice(&buf).unwrap();
assert_eq!(o, o2);
Faire cela en ligne fonctionne plutôt bien. Ma prochaine étape vers la réutilisabilité était de faire une fonction check_serde
à cet effet.
pub fn check_serde<T>(o: T)
where
T: Debug + PartialEq<T> + Serialize + DeserializeOwned,
{
let buf: Vec<u8> = to_vec(&o).unwrap();
let o2: T = from_slice(&buf).unwrap();
assert_eq!(o, o2);
}
Cela fonctionne bien pour posséder types, mais pas pour les types avec des bornes à vie (Playground):
check_serde(5);
check_serde(vec![1, 2, 5]);
check_serde("five".to_string());
check_serde("wait"); // [E0279]
L'erreur:
error[E0279]: the requirement `for<'de> 'de : ` is not satisfied (`expected bound lifetime parameter 'de, found concrete lifetime`)
--> src/main.rs:24:5
|
24 | check_serde("wait"); // [E0277]
| ^^^^^^^^^^^
|
= note: required because of the requirements on the impl of `for<'de> serde::Deserialize<'de>` for `&str`
= note: required because of the requirements on the impl of `serde::de::DeserializeOwned` for `&str`
= note: required by `check_serde`
Comme je veux faire le travail de la fonction avec ces cas (y compris les structs avec des tranches de chaîne), j'ai tenté une nouvelle version avec une vie de désérialisation d'objet explicite:
pub fn check_serde<'a, T>(o: &'a T)
where
T: Debug + PartialEq<T> + Serialize + Deserialize<'a>,
{
let buf: Vec<u8> = to_vec(o).unwrap();
let o2: T = from_slice(&buf).unwrap();
assert_eq!(o, &o2);
}
check_serde(&5);
check_serde(&vec![1, 2, 5]);
check_serde(&"five".to_string());
check_serde(&"wait"); // [E0405]
Cette implémentation conduit à un autre problème et ne compilera pas (Playground).
error[E0597]: `buf` does not live long enough
--> src/main.rs:14:29
|
14 | let o2: T = from_slice(&buf).unwrap();
| ^^^ does not live long enough
15 | assert_eq!(o, &o2);
16 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 10:1...
--> src/main.rs:10:1
|
10 |/pub fn check_serde<'a, T>(o: &'a T)
11 | | where T: Debug + PartialEq<T> + Serialize + Deserialize<'a>
12 | | {
13 | | let buf: Vec<u8> = to_vec(o).unwrap();
14 | | let o2: T = from_slice(&buf).unwrap();
15 | | assert_eq!(o, &o2);
16 | | }
| |_^
J'ai déjà attendu celui-ci: cette version implique que le contenu sérialisé (et donc l'objet désérialisé) vit aussi longtemps que l'objet d'entrée, ce qui est faux. Le tampon est seulement destiné à vivre aussi longtemps que la portée de la fonction.
Ma troisième tentative vise à construire des versions appartenant à l'entrée d'origine, évitant ainsi le problème d'avoir un objet désérialisé avec des limites de vie différentes. Le trait ToOwned
semble convenir à ce cas d'utilisation.
pub fn check_serde<'a, T: ?Sized>(o: &'a T)
where
T: Debug + ToOwned + PartialEq<<T as ToOwned>::Owned> + Serialize,
<T as ToOwned>::Owned: Debug + DeserializeOwned,
{
let buf: Vec<u8> = to_vec(&o).unwrap();
let o2: T::Owned = from_slice(&buf).unwrap();
assert_eq!(o, &o2);
}
Cela rend le travail de fonction pour les tranches de chaîne simple maintenant, mais pas pour les objets composites les contenant (Playground):
check_serde(&5);
check_serde(&vec![1, 2, 5]);
check_serde(&"five".to_string());
check_serde("wait");
check_serde(&("There's more!", 36)); // [E0279]
Encore une fois, nous tombons sur le même genre d'erreur que la première version:
error[E0279]: the requirement `for<'de> 'de : ` is not satisfied (`expected bound lifetime parameter 'de, found concrete lifetime`)
--> src/main.rs:25:5
|
25 | check_serde(&("There's more!", 36)); // [E0279]
| ^^^^^^^^^^^
|
= note: required because of the requirements on the impl of `for<'de> serde::Deserialize<'de>` for `&str`
= note: required because of the requirements on the impl of `for<'de> serde::Deserialize<'de>` for `(&str, {integer})`
= note: required because of the requirements on the impl of `serde::de::DeserializeOwned` for `(&str, {integer})`
= note: required by `check_serde`
Accordée, je suis à perte. Comment pouvons-nous construire une fonction générique qui, en utilisant Serde, sérialise un objet et le désérialise dans un nouvel objet? En particulier, cette fonction peut-elle être effectuée dans Rust (stable ou nocturne), et si oui, quels ajustements à ma mise en œuvre manquent?