owengage / fastnbt

Fast serde serializer and deserializer for Minecraft's NBT and Anvil formats
MIT License
186 stars 34 forks source link

Array types in untagged enums: data did not match any variant of untagged enum #55

Closed valmyzk closed 2 years ago

valmyzk commented 2 years ago

fastnbt fails to deserialize untagged enums with structs containing array types like fastnbt::ByteArray or fastnbt::LongArray.

use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
struct A {
    val: fastnbt::LongArray,
}

#[derive(Serialize, Deserialize)]
struct B;

#[derive(Serialize, Deserialize)]
#[serde(untagged)]
enum C {
    A(A),
    B(B)
}

fn main() {
    let C = C::A(A { val: fastnbt::LongArray::new(Vec::new()) });
    let ser = fastnbt::to_bytes(&C).unwrap();

    let _: C = fastnbt::from_bytes(&ser).unwrap();
}

The program works as expected when deserializing directly to struct A.

owengage commented 2 years ago

This is documented, but does say to open an issue if it's important to you.

This is something I will eventually look into. v1 of fastnbt supports this if all you need is deserialization. If you also need serialization then you might need to work around it somehow. The hacky way that fastanvil currently does it is by trying one then the other...

valmyzk commented 2 years ago

Thanks for the solution! However, my case requires the enum to be inside a struct, ie

#[derive(Serialize, Deserialize)]
struct A {
    val: fastnbt::LongArray,
}

#[derive(Serialize, Deserialize)]
struct B;

#[derive(Serialize, Deserialize)]
#[serde(untagged)]
enum C {
    A(A),
    B(B)
}

#[derive(Serialize, Deserialize)]
struct D {
 inner: C,
 #[serde(flatten)]
 extra: HashMap<String, fastnbt::Value>
}

Is there any hack to work around this issue?

owengage commented 2 years ago

Untagged is now supported in fastnbt 2.3.0. Sorry it took so long to get back to you!