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

Dynamically choose unit for new/get/floor/ceil/... methods #91

Open
iliekturtles opened this issue Jun 25, 2018 · 6 comments
Open

Dynamically choose unit for new/get/floor/ceil/... methods #91

iliekturtles opened this issue Jun 25, 2018 · 6 comments
Milestone

Comments

@iliekturtles
Copy link
Owner

Add a way to dynamically choose the unit when calling methods with a generic parameter where N: Unit. What is the best way to do this? Add methods that accept dyn Unit? Add an enum for each quantity containing a member for each unit? Allow users to create enums on a per-quantity basis to only include the units they are interested in (this is useful at the UI level to provide a subset of units to a user)?

@iliekturtles
Copy link
Owner Author

Review in more detail prior to v1.0.0. Can/should this be implemented now or pushed to v2.0.0?

@DerekV
Copy link

DerekV commented Jul 3, 2022

Out of curiosity what is happening here? It certainly seems to be picking units dynamically in the from_str test. I'm a rust newbie at the moment, I was able to see that Quantity! macro is generating a match statement for the from_str implementations, and adding my own parse statements in that test using eg k::Length works, but I found it impossible to use from_str / parse in my own code, from si::Length, the compiler needs the unit and value size type parameters for Length. I don't fully follow what is happening with the k:: namespace and the Q! macro, but was scratching my head for quite a bit yesterday on why I couldn't use the .parse workaround like I saw in the test.

@iliekturtles
Copy link
Owner Author

You're right that the FromStr impl is using a large match statement to convert the abbreviation, singular, or plural description for each of the quantity's units into an explicit call with a fixed generic parameter.

Rather than use the pre-built SI system, tests use a custom system that just includes length, mass, and thermodynamic temperature. The f and k submodules define separate sets of quantities that use different base units (meter, kilogram, kelvin) and (kilometer, kilogram, kelvin). This is done to test conversions between different base units (e.g. length stored as meters + length stored as kilometers).

Using FromStr in your own code should look something like this following code block. You'll probably want to use uom::si::f32::*; and handle the result instead of unwrapping. If you still can't get your code to compile can you share the code or a minimal example?

let l = "1 m".parse::<uom::si::f32::Length>().unwrap();

@DerekV
Copy link

DerekV commented Jul 4, 2022

That works! The trick to getting the FromStr workaround was using <uom::si::f32::Length> rather than <uom::si::Length> as you said. Your explanation also helped me understand what I was seeing a bit better as well.
Thanks

@YgorSouza
Copy link

For what it's worth, I am practicing Rust by making a simple GUI for converting between units, and I ran into some of these limitations.
I originally wanted to take every quantity and every unit from uom and make them available in the GUI to convert in both directions, but I realized I would have to manually list them all, so I made some compromises.

image

Based on this experience, here are a few things that I think would simplify the implementation for this use case:

  • Move more methods from the quantities and units to traits, so we can use trait bounds in the generics and avoid rewriting them in macros. Things like description(), abbreviation(), format_args() and the methods mentioned in the items below.
  • Associate the Units enum and the units() iterator method with each quantity type, rather than leaving it in the module.
  • Add non-generic alternatives to new(), get(), and format_args(), which take the Units enum and find the right generic method to call using a match statement, similar to the parse() method.
  • Derive PartialEq for the Units enum.

I played with the uom source a little, and it seems that a lot of these changes would be relatively easy to implement by changing the quantity! macro. If they are considered useful, I would be willing to implement them and submit a PR.

But I don't know how useful all this is for "real" use cases, as you would usually need to add some units that are not in the enum, so you would not be able to use all this functionality implemented for the enum. So I guess this dynamic unit selection would have to accept user-defined units to be truly helpful.

@iliekturtles
Copy link
Owner Author

Really cool to see what you have done!

The addition of the Units enum was really a stop-gap fix for being able to dynamically choose units and isn't very ergonomic to work with. I would definitely accept PRs to approve things. I just ask for a bit of patience as I have a big backlog of new quantity/unit PRs to work through.

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

3 participants