2

Why can I auto derive serde::Deserializefor my WidgetValue enum, but not for a struct made up entirely of WidgetValue fields?

This seems counterintuitive to me.

EDIT: For various reasons, I'm using the WidgetValue enum because I'd like to send different values through a function with the same type signature. See Vector store mixed types of data in Rust, How do I create a heterogeneous collection of objects?, etc.

serde = { version = "1.0.126", features = ["derive"] }
//works fine
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub enum WidgetValue{
    Integer32(i32),
    Unsized32(u32),
    CString(&'static str),
}

//lifetime error
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub struct DraggableInfo{
    parent: WidgetValue,
    index: WidgetValue,
    draggable_id: WidgetValue,
}

Error:

cannot infer an appropriate lifetime for lifetime parameter `'de` due to conflicting requirements
ANimator120
  • 2,556
  • 1
  • 20
  • 52
  • 1
    I'm guessing based on not trying this myself but the likely cause of this error is that serde doesn't known how to deserialise into a static lifetime, since the data it is deserializing from isn't static. – PiRocks Jun 27 '21 at 04:23
  • Though I believe this is a follow up question from the last question you asked. Perhaps it would be best if you explained more about what your end goal is. – PiRocks Jun 27 '21 at 04:26
  • And as a side not I do not think you should derive copy on DraggableInfo. – PiRocks Jun 27 '21 at 04:34
  • @PiRocks why not derive ```Copy```? – ANimator120 Jun 27 '21 at 05:38
  • `DraggableInfo` is at least 27 bytes, likely more due to alignment. By deriving copy you make a cost implicit, and end up passing by value everywhere instead of passing a reference. – PiRocks Jun 27 '21 at 13:35
  • @PiRocks do you agree with @jonasbb's recomendation to use ```CString(Cow<'static, str>)``` instead of ```CString(&'static str)```? – ANimator120 Jun 28 '21 at 00:44
  • If it was me I would would add a lifetime parameter to the enum, and therefore the struct, but Cow may also work depending on the specifics. Based on your last question, you want to avoid String, but Cow smuggles in a String. – PiRocks Jun 28 '21 at 03:34

1 Answers1

0

You can fix the lifetime error, by manually providing a bound on the 'de lifetime during deserialization. Due to the &'static str the enum WidgetValue only implements Deserialize<'static> since no other lifetime works to borrow a &'static str. This leads to an error for DraggableInfo since by default the 'de lifetime is not constrained. With this manual bound you declare 'de to outlive 'static, making them equal.

#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
#[serde(bound(deserialize = "'de: 'static"))]
pub struct DraggableInfo{
    parent: WidgetValue,
    index: WidgetValue,
    draggable_id: WidgetValue,
}

#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub enum WidgetValue{
    Integer32(i32),
    Unsized32(u32),
    CString(&'static str),
}

You likely do not want to use it like this though, since you can only derive from 'static data. You can redefine CString like this CString(Cow<'static, str>) to allow both static string literals and deserializing from non-static data.

jonasbb
  • 2,131
  • 1
  • 6
  • 25
  • This did solve the lifetime error, but resulted in a new error that ```implementation of `Deserialize` is not general enough``` when I actually used ```DraggableInfo``` in a method. I created a new follow up question about this: [https://stackoverflow.com/questions/68156340/implementation-of-serdedeserialize-is-not-general-enough](https://stackoverflow.com/questions/68156340/implementation-of-serdedeserialize-is-not-general-enough) – ANimator120 Jun 28 '21 at 00:38