Десериализовать Vecкак Vec <T>напрямую, когда Foobar имеет ровно одно поле - PullRequest
0 голосов
/ 21 октября 2019

Мне дан формат данных, который включает последовательность объектов с ровно одним именованным полем value каждый. Могу ли я удалить этот слой косвенности при десериализации?

При десериализации естественное представление будет

/// Each record has it's own `{ value: ... }` object
#[derive(serde::Deserialize)]
struct Foobar<T> {
    value: T,
}

/// The naive representation, via `Foobar`...
#[derive(serde::Deserialize)]
struct FoobarContainer {
    values: Vec<Foobar<T>>,
}

Хотя Foobar не добавляет дополнительных затрат сверх T, я бы хотелудалить этот слой косвенности на уровне типа:

#[derive(serde::Deserialize)]
struct FoobarContainer {
    values: Vec<T>,
}

Можно ли удалить Foobar из FoobarContainer, все еще используя его с помощью десериализации?

1 Ответ

2 голосов
/ 21 октября 2019

В общем случае нет тривиального способа сделать это преобразование. Для этого просмотрите следующие существующие ответы:

Первое - это мое обычное решение перехода, и выглядит такэто в этом примере.


Однако, в вашем конкретном случае вы говорите:

объектов с точно одним значением именованного поля

И вы определили ключевое требование:

В то время как Foobar не добавляет дополнительных затрат сверх T

Это означает, чтовы можете сделать Foobar иметь прозрачное представление и использовать unsafe Rust для трансмутации между типами (хотя на самом деле не с mem::transmute):

struct FoobarContainer<T> {
    values: Vec<T>,
}

#[derive(serde::Deserialize)]
#[repr(transparent)]
struct Foobar<T> {
    value: T,
}

impl<'de, T> serde::Deserialize<'de> for FoobarContainer<T>
where
    T: serde::Deserialize<'de>,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let mut v: Vec<Foobar<T>> = serde::Deserialize::deserialize(deserializer)?;

        // I copied this from Stack Overflow without reading the surrounding
        // text that describes why this is actually safe.
        let values = unsafe {
            let data = v.as_mut_ptr() as *mut T;
            let len = v.len();
            let cap = v.capacity();

            std::mem::forget(v);

            Vec::from_raw_parts(data, len, cap)
        };

        Ok(FoobarContainer { values })
    }
}

См. Также:

...