В проекте, в котором задействованы специальные методы сериализации и десериализации Serde (1.0), я полагался на эту процедуру тестирования, чтобы проверить, приведет ли сериализация объекта и обратно к созданию эквивалентного объекта.
// let o: T = ...;
let buf: Vec<u8> = to_vec(&o).unwrap();
let o2: T = from_slice(&buf).unwrap();
assert_eq!(o, o2);
Выполнение этого встроенного решения работает очень хорошо. Следующим шагом на пути к повторному использованию было создание для этой цели функции check_serde
.
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);
}
Это хорошо работает для типов-владельцев, но не для типов с ограничениями времени жизни (Playground ):
check_serde(5);
check_serde(vec![1, 2, 5]);
check_serde("five".to_string());
check_serde("wait"); // [E0279]
Ошибка:
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`
Поскольку я хочу, чтобы функция работала с этими случаями (включая структуры со строковыми фрагментами), я попытался создать новую версию с явным временем жизни десериализации объекта:
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]
Эта реализация приводит к другой проблеме, и она не компилируется (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 | | }
| |_^
Я уже ожидал этого: эта версия подразумевает, что сериализованный контент (и, следовательно, десериализованный объект) живет до тех пор, пока входной объект, что неверно. Буфер предназначен только для жизни до тех пор, пока область действия функции.
Моя третья попытка направлена на создание собственных версий исходного ввода, таким образом избегая проблемы наличия десериализованного объекта с разными границами времени жизни. Характеристика ToOwned
, похоже, подходит для этого варианта использования.
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);
}
Благодаря этому функция теперь работает для простых строковых срезов, но не для составных объектов, содержащих их (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]
Опять же, мы натыкаемся на ту же ошибку, что и в первой версии:
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`
Конечно, я в растерянности. Как мы можем создать универсальную функцию, которая с помощью Serde сериализует объект и десериализует его обратно в новый объект? В частности, можно ли сделать эту функцию в Rust (стабильной или ночной), и если да, то какие корректировки в моей реализации отсутствуют?