dtolnay / typetag

Serde serializable and deserializable trait objects
Apache License 2.0
1.19k stars 38 forks source link

non-unique tag error during deserialization when multiple structs with same name in different files, compile time error rather than runtime? #87

Open zakstucke opened 2 months ago

zakstucke commented 2 months ago

Amazing library!

When defining the 2 structs with the same name and implementing the typetag trait for both, deserialization now fails at runtime with following error:

Error("non-unique tag of dyn Tester: \"MyStruct\"", line: 1, column: 18)

This totally makes sense why this happens, but is brittle and easy to break in larger projects without realising, given it's a runtime error. For me, this was a confusing bug(albeit not typetag's bug!) to track down.

typetag does currently provide #[typetag::serde(name = "foo")] that would get around this. Would it be feasibly possible to make this a compile time error rather than runtime, by keeping track of generated type names in the typetag macro?

MRE:

#[typetag::serde(tag = "type")]
trait Tester {}

fn def_1() -> impl Tester {
    #[derive(serde::Serialize, serde::Deserialize)]
    struct MyStruct;

    #[typetag::serde]
    impl Tester for MyStruct {}

    MyStruct
}

fn def_2() -> impl Tester {
    #[derive(serde::Serialize, serde::Deserialize)]
    struct MyStruct;

    #[typetag::serde]
    impl Tester for MyStruct {}

    MyStruct
}

#[derive(Serialize, Deserialize)]
struct Wrapped(Box<dyn Tester>);

let wrapped = Wrapped(Box::new(def_1()));
let stringified = serde_json::to_string(&wrapped).unwrap();
serde_json::from_str::<Wrapped>(&stringified).unwrap();

Note: whilst the author closed it himself, I think is technically the same issue as #69