Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

deserialize values to user-specified unit type #427

Open
robfitzgerald opened this issue Jul 20, 2023 · 1 comment
Open

deserialize values to user-specified unit type #427

robfitzgerald opened this issue Jul 20, 2023 · 1 comment

Comments

@robfitzgerald
Copy link

hi there! thanks for your work.

i want to use uom in code that reads CSVs of velocity data from a user and builds lookup functions from it. i would like to allow the user to specify their velocity unit, but via system configuration instead of inline with every CSV cell, i.e.:

pub fb build_lookup(filename: String, velocity_type: ?) -> {
  ...
  for row in file {
    let vel: Velocity<?> = Velocity::try_from(velocity_type, row.velocity)?;
    ...
  } 
} 

i didn't find any documentation on use of serde with this package to show me how the Type might be parameterized at deserialization, and i did find issues that imply that Units aren't actually reified into enums or structs here to allow matching. i didn't find a function to do this automagically. i tried to build my own enums, which means i have to duplicate the list of supported velocity types, but then i ran into the problem that the return type of my as_quantity method below would need to return a specific type argument:

#[derive(Debug, Serialize, Deserialize)]
pub enum VelocityType {
    MetersPerSecond,
    KilometersPerHour,
    MilesPerHour,
}

impl VelocityType {
    pub fn as_quantity(&self, value: f64) -> Velocity<?> {
      match self {
        MetersPerSecond -> Velocity::new<meters_per_second>(value),
        ...
      }
    }
}

wondering if i missed a way to get this kind of behavior, or if using uom i need to 1) require all users specify velocity in one type such as Velocity<kilometers_per_hour>, 2) require users to append the unit type to every velocity entry in the CSV ("40.2 kph", "41.52 kph" for 55 million rows).

thank you for reading!

@iliekturtles
Copy link
Owner

You're right that uom doesn't include units during (de)serialization and because of the generic requirements on fn new constructing a quantity with a run-time provided unit is not ideal right now. Long term I want to address this issue. Short-term I see a few options, none which are very ideal.

  • Include the unit in your file as you mentioned. That's a lot of wasted bytes, but likely the easiest solution.
  • Concatenate the configuration-supplied unit with the value before parsing. That's lots of string concatenation, but you save file size.
  • Write a custom parsing function similar to the from_str impl where the unit is provided as a parameter. You would need to manually write out the match expression but would get the best performance/smallest file.

uom/src/quantity.rs

Lines 434 to 445 in 787272d

fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut parts = s.splitn(2, ' ');
let value = parts.next().unwrap();
let unit = parts.next().ok_or(NoSeparator)?;
let value = value.parse::<V>().map_err(|_| ValueParseError)?;
#[allow(unreachable_patterns)]
match unit.trim() {
$($abbreviation | $singular | $plural => Ok(Self::new::<super::super::$unit>(value)),)+
_ => Err(UnknownUnit),
}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants