Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

rust - Deserialize a Vec<Foobar<T>> as Vec<T> directly when Foobar has exactly one field

I'm given a data-format that includes a sequence of objects with exactly one named field value each. Can I remove this layer of indirection while deserializing?

When deserializing, the natural representation would be

/// 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>>,
}

While Foobar adds no extra cost beyond T, I'd like to remove this layer of indirection at the type-level:

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

Can Foobar be removed from FoobarContainer, while still using it using deserialization?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

In the general case, there's no trivial way to make this transformation. For that, review these existing answers:

The first is my normal go-to solution and looks like this in this example.


However, in your specific case, you say:

objects with exactly one named field value

And you've identified a key requirement:

While Foobar adds no extra cost beyond T

This means that you can make Foobar have a transparent representation and use unsafe Rust to transmute between the types (although not actually with 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 })
    }
}

See also:


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...