Confusions about serialize_tuple and serialize_newtype_struct in serde

I'm trying do implement Serialize and Deserialize on my own data structure and several of them have differences with JSON data. There are "keyword" and "named map" that contain extra informations.

So I have to use tuple in my Visitor, but the strange thing is I found the function
serialize_tuple, but didn't find a function called visit_tuple, looks like it's removed for long and just turned into visit_seq. Similar things happen on struct as well, but I found a visit_newtype_struct function and...

Is there any articles or docs to read? that could guide me on this case?


edit: more details about my original problem,

say I have a data structure highly similar to Clojure EDN, now I parse a string of it and assign it to a structure:

struct Person {
  name: String,
  data: Vec<f64>,
}

let a: Person = parse_edn(str_content);

since it's not JSON, I cannot use serde_json directly. what should I do now? Without such trick, I have to call x.get()?.get()...all the way down to transfer the data by myself.

What is your question? What are you trying to do? What's wrong with using visit_seq()?

take Clojure Edn for example, what's you suggestion when I want to represent keyword and record in serde?

in the docs of serde, I found examples for visit_map and visit_seq. But for data structures like EDN, there are vector, list, hashset, hashmap, record, what's the best way of encoding them?(maybe tuple is not the choice I should take... which API should I use?)

I can't find "record" anywhere in the EDN documentation. If you mean a type with named fields and corresponding values (that's the common colloquial meaning of "record" in computer science), then that's similar to a struct in Rust, and most formats represent it as a maps from field names as strings to the value of each field.

Keywords can simply be represented by strings.

I mean "tagged elements". my bad.

one approach I was thinking about was using a prefixed character like

"str
:kwd
'sym

that could work. but I still want to know more about how serde is abstracting concepts like "tagged unions", or how to use "struct" correctly since I didn't dig much out of the docs.

to ask this question in another way... can I just use TryInto but got such a data recursive structure(like Clojure EDN) working? I tried, but failed to apply the types recursively. (may not be really useful for my structs to receive data from that dynamic structure.)

Serde doesn't have the concept identical to EDN's "tagged elements" which are apparently active objects with special semantics prescribed by a specific parser implementation. The term "tagged union" is usually taken to mean something completely different: it is used for describing algebraic sum/variant types, which are called enums in Rust.

That's pretty broad – roughly, you would serialize a struct by calling serialize_struct() and then serialize each field with the help of the returned serializer, and you would deserialize one by calling deserialize_struct on Deserializer and then implementing a Visitor that accepts MapAccess.

It is definitely possible to implement TryInto recursively. Without further specifics, I don't know what problem you ran into. Usually, the way data types are represented in memory is an enum Value, some variants of which contain further Values behind indirection. See e.g. serde_json::Value.

1 Like

I'm not sure, but it's not very easily rust - How is there a conflicting implementation of `From` when using a generic type? - Stack Overflow .

I realized there is still a lot to read in the docs before I know how to write all the code. Thanks anyway for the help.

read some more about serde docs... I think serde may not be the library I want since I have such customized data type in my own EDN. But I want to have the ability to write let p: Person = serde_maybe::from_value(data) and let compiler to infer types for me.

As long as you have a statically-typed data structure, and its members (transitively) know how to deserialize themselves from a primitive type provided by the Serde data model, that should just work. It is not the case that you must provide a 1-to-1 mapping between all possible custom types in your own format and the Serde type system. Multiple static types may be constructed from the same kind of primitive.

This is why I suggested that strings, symbols, and keywords alike can be represented simply by a string literal, e.g. this works just fine:

#[derive(Clone, Debug, Serialize, Deserialize)]
struct Kw(String);

#[derive(Clone, Debug, Serialize, Deserialize)]
struct Sym(String);

#[derive(Clone, Debug, Serialize, Deserialize)]
struct Str(String);

fn main() -> Result<()> {
    let x: (Kw, Sym, Str) = serde_json::from_value(json!(["keyword", "symbol", "string"]))?;
    println!("{:#?}", x);
    Ok(())
}
1 Like

it cool but as I looked into the code how serde_json is implementing from_value and to_value, I found Deserializer/Serializer side a lot trickier than Deserialize/Serialize. And what my code is lack of is the Deserializer/Serializer part.

looks highly likely what I need:

https://cprimozic.net/blog/writing-a-hashmap-to-struct-procedural-macro-in-rust/