Deserialize references to quantities
kylecarow opened this issue · 2 comments
Howdy! Thanks for the useful crate! Looking forward to using it. I'm still somewhat a Rust novice, so bear with me.
Summary
I'm trying to understand why deriving Deserialize
on a reference to a quantity doesn't work (or, perhaps, why quantities impl Deserialize
but references to quantities do not). Is this something that could be changed? I don't really want to impl Deserialize
myself, as I expect to add more fields and it would be a maintenance headache. Or, is there a better way to structure my code?
Context
I have a struct Cycle
that contains Vec
s of quantities, and another struct CycleElement
that ought to hold one index of elements from a Cycle
. CycleElement
can also serve as a way of constructing a Cycle
by push
ing them sequentially - see the test build_cycle
below.
I am unable to derive Deserialize
on CycleElement
, as it contains references to quantities, rather than owned quantities. I need to impl Deserialize
on CycleElement
in order for csv
serde to work, see the example here which requires the record struct to impl Deserialize
.
Error
error[E0277]: the trait bound `&'a Quantity<(dyn Dimension<I = Z0, J = Z0, Kind = (dyn Kind + 'static), L = PInt<UInt<UTerm, B1>>, M = Z0, N = Z0, T = Z0, Th = Z0> + 'static), (dyn uom::si::Units<f64, amount_of_substance = uom::si::amount_of_substance::mole, electric_current = uom::si::electric_current::ampere, length = uom::si::length::meter, luminous_intensity = uom::si::luminous_intensity::candela, mass = uom::si::mass::kilogram, thermodynamic_temperature = uom::si::thermodynamic_temperature::kelvin, time = uom::si::time::second> + 'static), f64>: Deserialize<'_>` is not satisfied
--> src/main.rs:23:8
|
23 | a: &'a Length, // error here
| ^^^^^^^^^^ the trait `Deserialize<'_>` is not implemented for `&'a Quantity<(dyn Dimension<I = Z0, J = Z0, Kind = (dyn Kind + 'static), L = PInt<UInt<UTerm, B1>>, M = Z0, N = Z0, T = Z0, Th = Z0> + 'static), (dyn uom::si::Units<f64, amount_of_substance = uom::si::amount_of_substance::mole, electric_current = uom::si::electric_current::ampere, length = uom::si::length::meter, luminous_intensity = uom::si::luminous_intensity::candela, mass = uom::si::mass::kilogram, thermodynamic_temperature = uom::si::thermodynamic_temperature::kelvin, time = uom::si::time::second> + 'static), f64>`
|
note: required by a bound in `next_element`
Code
Below is a minimal reproducible example that refuses to compile. Remove the Deserialize
derive on struct CycleElement
and it works fine, but would become incompatible with csv
serde. The tests are just there to make it easier to see how this code works, they don't really test anything.
main.rs
:
use serde::{Deserialize, Serialize};
use uom::si::f64::Force;
use uom::si::f64::Length;
pub fn main() {}
#[derive(Debug, Deserialize, Serialize)]
struct Cycle {
a: Vec<Length>,
b: Vec<Force>,
}
impl Cycle {
pub fn push(&mut self, cyc_elem: CycleElement) {
self.a.push(*cyc_elem.a);
self.b.push(*cyc_elem.b);
}
}
#[derive(Serialize, Deserialize)] // including Deserialize here breaks it
struct CycleElement<'a> {
a: &'a Length, // error here
b: &'a Force, // error here
}
#[cfg(test)]
mod tests {
use super::*;
use uom::si::force::newton;
use uom::si::length::meter;
#[test]
fn build_cycle() {
let mut cyc = Cycle {
a: vec![],
b: vec![],
};
cyc.push(CycleElement {
a: &Length::new::<meter>(7.0),
b: &Force::new::<newton>(8.0),
});
cyc.push(CycleElement {
a: &Length::new::<meter>(42.0),
b: &Force::new::<newton>(1.0),
});
cyc.push(CycleElement {
a: &Length::new::<meter>(0.0),
b: &Force::new::<newton>(0.0),
});
dbg!(cyc);
}
#[test]
fn test_serialize() {
let cycle = Cycle {
a: vec![Length::new::<meter>(1.0), Length::new::<meter>(2.0)],
b: vec![Force::new::<newton>(4.0), Force::new::<newton>(5.0)],
};
let output = serde_json::to_string(&cycle).unwrap();
dbg!(output);
}
#[test]
fn test_deserialize() {
let input = "{\"a\":[1.0,2.0,3.0,7.0],\"b\":[4.0,5.0,6.0,8.0]}";
let cyc: Cycle = serde_json::from_str(input).unwrap();
dbg!(cyc);
}
}
Cargo.toml
:
[package]
name = "test-cyc"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
serde = { version = "1.0.193", features = ["derive"] }
serde_json = "1.0.108"
uom = { version = "0.35.0", features = ["use_serde"] }
I'm wondering if I'll run into trouble anyway, considering the docs for csv::Reader::deserialize
that I linked above state that it requires the trait DeserializeOwned
... not sure.
Realized this is not possible given these SO posts and is not specific to this crate.