msgpack-rust icon indicating copy to clipboard operation
msgpack-rust copied to clipboard

`#[serde(other)]` not working as expected on enum tuple-like variants

Open b-zee opened this issue 10 months ago • 0 comments

I have a use case where I want to have the possibility to introduce a breaking change to a data structure. If my app currently only supports version 0, it will detect when a version 1 is used. I have written the following code, but I get an error instead of matching on the #[serde(other)] variant. (Inspiration taken from https://stackoverflow.com/a/70380491)

#[derive(serde::Serialize, serde::Deserialize)]
enum A {
    V0(String),
    #[serde(other)]
    Unsupported,
}

#[derive(serde::Serialize, serde::Deserialize)]
enum B {
    V0(String),
    V1(usize),
    #[serde(other)]
    Unsupported,
}

#[test]
fn test() {
    let b_v1 = rmp_serde::to_vec(&B::V1(1)).unwrap();

    // Yields `Err(rmp_serde::decode::Error::TypeMismatch(rmp::Marker::FixPos(1)))`
    let a_unsupported = rmp_serde::from_slice::<A>(b_v1.as_slice());
    // But instead, I would expect this to pass (`Ok(A::Unsupported)`):
    assert!(matches!(a_unsupported, Ok(A::Unsupported)));
}

The above code does work when I change the A and B enums to be unit-only:

 #[derive(serde::Serialize, serde::Deserialize)]
 enum A {
-    V0(String),
+    V0,
     #[serde(other)]
     Unsupported,
 }
 
 #[derive(serde::Serialize, serde::Deserialize)]
 enum B {
-    V0(String),
-    V1(usize),
+    V0,
+    V1,
     #[serde(other)]
     Unsupported,
 }
 
 #[test]
 fn test() {
-    let b_v1 = rmp_serde::to_vec(&B::V1(1)).unwrap();
+    let b_v1 = rmp_serde::to_vec(&B::V1).unwrap();
 
     // Yields `Err(rmp_serde::decode::Error::TypeMismatch(rmp::Marker::FixPos(1)))`
     let a_unsupported = rmp_serde::from_slice::<A>(b_v1.as_slice());

b-zee avatar Jan 28 '25 10:01 b-zee