Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deserializing runtime types #2609

Open
racradi opened this issue Sep 5, 2023 · 7 comments
Open

Deserializing runtime types #2609

racradi opened this issue Sep 5, 2023 · 7 comments

Comments

@racradi
Copy link

racradi commented Sep 5, 2023

Sorry if this is not the right place to ask, but I've been stuck with this problem for a while and I'm not sure if it's possible to achieve this using Serde.

I have what is effectively a dynamic (runtime) representation of a struct. I want to use this representation to deserialize some data. To my understanding, the typical solution would be to treat it as a map and use deserialize_map alongside a custom Visitor, however I cannot do that as the serialization format I'm using has length-prefixed maps. The data I'm interested in deserializing does not treat these types as maps, and so there's no length prefix. Although serialize_struct is pretty much what I want, I can't use that either as the names of the members are not &'static str.

More concretely, here's a condensed example:

enum Kind {
    Struct,
    Number,
}

// Using this representation of the struct, I know the types and
// names of each member.
struct MyStructRepr {
    name: String,
    members: Vec<(String, Kind)>,
}

// The actual data into which I want to deserialize the input.
enum Data {
    Struct {
        members: Vec<Data>,
    },
    Number(usize),
    String(String),
}

Is this doable with Serde?

@Rulexec
Copy link

Rulexec commented Sep 9, 2023

You can try to do it in two steps. If I understood the problem correctly, you can try to Implement Deserialize for MyStructRepr, which closely matches original data. Then implement Deserialize for Data, which calls MyStructRepr::deserialize(deserializer)?, then map intermediate representation to wanted one. Or even maybe without two Deserialize impls, your custom Visitor can return type which is just extracts data which you can map later to expected result.

@racradi
Copy link
Author

racradi commented Sep 9, 2023

@Rulexec Unfortunately that doesn't address my issue.

MyStructRepr is just a way to represent the definition of a type. For example, consider the following type:

struct Foo {
    my_member: i32,
}

The same type could instead be represented as:

let foo = MyStructRepr {
   name: "Foo".to_string(),
   members: vec![("my_member".to_string(), Kind::Number)]
};

The point here is that the definition of the type is not available at compile time, as these are dynamic types created at runtime. MyStructRepr should only be used as a way to drive the deserializer, i.e. tell the deserializer what comes next. This leads me back to my initial problem: driving a deserializer based on runtime information.

I cannot use deserialize_struct, as it requires that the names of all member fields are &'static str (something they are not in my case), and I cannot use deserialize_map as the serialization format I am using encodes maps differently from structs. I can make deserialize_struct work by leaking the strings, but I'd rather not do that.

A similar thing was discussed in #2043, but unfortunately the solution there doesn't help my use case.

@Mingun
Copy link
Contributor

Mingun commented Sep 9, 2023

MyStructRepr should only be used as a way to drive the deserializer,

This looks like MyStructRepr is itself should be (part of) deserializer, but I under impression that you want to deserialize that type from another deserializer.

The deserialize_* methods called by the deserializable types, so if MyStructRepr is a deserializer, then what you want should be possible.

@racradi
Copy link
Author

racradi commented Sep 9, 2023

@Mingun

under impression that you want to deserialize that type from another deserializer.

Yes, that is what I'm trying to achieve. MyStructRepr is not a deserializer itself, it just contains information about the type that should be used to drive another deserializer. To make things more tricky, it has to work with different deserializers, including e.g. serde_json.

@max-heller
Copy link

I'm trying to implement a similar workflow for postcard and am also running into &'static str limitations: #2218 (comment)

@max-heller
Copy link

max-heller commented Dec 22, 2024

Unlike #2218, removing the &'statics from Deserializer methods seems more tractable since it doesn't need to affect any return types (those are determined by the Visitor, which does not receive &'statics). The naive replacement of &'static _ with &_ in Deserializer::deserialize_*() methods seems to "just work" with minor tweaks to Deserializer implementations. If serde 2.0 were to ever happen, this seems like it could be changed with relatively little upgrade burden.

@oli-obk
Copy link
Member

oli-obk commented Dec 23, 2024

If serde 2.0 were to ever happen, this seems like it could be changed with relatively little upgrade burden.

That's not something that can be done without a huge amount of churn. We have no plans to do so

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

5 participants