В проекте, в котором задействованы стандартные методы сериализации и десериализации 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);
}
Это хорошо работает для владения типами, но не для типов с ограничениями продолжительности жизни (Игровая площадка):
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]
Эта реализация приводит к другой проблеме, и она не будет компилироваться (Игровая площадка).
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 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 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 (стабильная или ночная), и если да, то какие корректировки моей реализации отсутствуют?