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

Unclear about how to create arbitrary quantities with arbitrary units #464

Open
joe-saronic opened this issue Mar 4, 2024 · 6 comments
Open

Comments

@joe-saronic
Copy link

I'm new to rust and very new to UOM, so admittedly, this is likely user error caused by a lack of understanding. This is a followup from my StackOverflow post, which got no traction unfortunately.

I am trying to make a simple type that will be backed by an array in the default units of a given dimension. The idea is pretty simple: I provide a constructor that converts quantities to base units and getters that convert them back to desired units for some given dimension:

use anyhow::Result;
use core::marker::PhantomData;
use uom::{
    Conversion, si::{Dimension, Quantity, SI, Unit, length::{Dimension as Length, meter}},
};

#[derive(Debug)]
struct Coordinate<D: Dimension + ?Sized> {
    buf: [f64; 2],
    dim: PhantomData<D>,
}

impl<D: Dimension + ?Sized> Coordinate<D>
{
    pub fn new<U: Unit + Conversion<f64>>(x: f64, y: f64) -> Self {
        Self {
            buf: [
                Quantity::<D, SI<f64>, f64>::new::<U>(x).value,
                Quantity::<D, SI<f64>, f64>::new::<U>(y).value,
            ],
            dim: PhantomData,
        }
    }

    pub fn x(&self) -> Quantity<D, SI<f64>, f64> {
        Quantity::<D, SI<f64>, f64> { dimension: PhantomData, units: PhantomData, value: self.buf[0], }
    }

    pub fn y(&self) -> Quantity<D, SI<f64>, f64> {
        Quantity::<D, SI<f64>, f64> { dimension: PhantomData, units: PhantomData, value: self.buf[1], }
    }
}

fn main() -> Result<()> {
    let n = Coordinate::<Length>::new::<meter>(1.0, 1.0);
    println!("{n:?}");
    Ok(())
}

I end up with a couple of different errors that I can't quite make sense of:

   Compiling scratchpad v0.1.0 (/home/joe/saronic/scratch/scratchpad)
error[E0599]: no function or associated item named `new` found for struct `Quantity<D, ..., ...>` in the current scope
  --> src/main.rs:18:46
   |
18 |                 Quantity::<D, SI<f64>, f64>::new::<U>(x).value,
   |                                              ^^^ function or associated item not found in `Quantity<D, ..., ...>`
   |
   = note: the full type name has been written to '/home/joe/saronic/scratch/scratchpad/target/debug/deps/scratchpad-dd83b867192bd049.long-type-8409603177462832417.txt'
   = note: the function or associated item was found for
           - `Quantity<(dyn Dimension<I = Z0, J = Z0, Kind = (dyn Kind + 'static), L = PInt<UInt<UTerm, B1>>, M = Z0, N = Z0, T = PInt<UInt<UTerm, B1>>, Th = Z0> + 'static), U, V>`
           - `Quantity<(dyn Dimension<I = Z0, J = Z0, Kind = (dyn Kind + 'static), L = PInt<UInt<UTerm, B1>>, M = Z0, N = Z0, T = NInt<UInt<UInt<UTerm, B1>, B0>>, Th = Z0> + 'static), U, V>`
           - `Quantity<(dyn Dimension<I = Z0, J = Z0, Kind = (dyn Kind + 'static), L = PInt<UInt<UInt<UTerm, B1>, B0>>, M = PInt<UInt<UTerm, B1>>, N = Z0, T = NInt<UInt<UTerm, B1>>, Th = Z0> + 'static), U, V>`
           - `Quantity<(dyn Dimension<I = Z0, J = Z0, Kind = (dyn Kind + 'static), L = Z0, M = Z0, N = PInt<UInt<UTerm, B1>>, T = Z0, Th = Z0> + 'static), U, V>`
           and 106 more types

error[E0599]: no function or associated item named `new` found for struct `Quantity<D, ..., ...>` in the current scope
  --> src/main.rs:19:46
   |
19 |                 Quantity::<D, SI<f64>, f64>::new::<U>(y).value,
   |                                              ^^^ function or associated item not found in `Quantity<D, ..., ...>`
   |
   = note: the full type name has been written to '/home/joe/saronic/scratch/scratchpad/target/debug/deps/scratchpad-dd83b867192bd049.long-type-8409603177462832417.txt'
   = note: the function or associated item was found for
           - `Quantity<(dyn Dimension<I = Z0, J = Z0, Kind = (dyn Kind + 'static), L = PInt<UInt<UTerm, B1>>, M = Z0, N = Z0, T = PInt<UInt<UTerm, B1>>, Th = Z0> + 'static), U, V>`
           - `Quantity<(dyn Dimension<I = Z0, J = Z0, Kind = (dyn Kind + 'static), L = PInt<UInt<UTerm, B1>>, M = Z0, N = Z0, T = NInt<UInt<UInt<UTerm, B1>, B0>>, Th = Z0> + 'static), U, V>`
           - `Quantity<(dyn Dimension<I = Z0, J = Z0, Kind = (dyn Kind + 'static), L = PInt<UInt<UInt<UTerm, B1>, B0>>, M = PInt<UInt<UTerm, B1>>, N = Z0, T = NInt<UInt<UTerm, B1>>, Th = Z0> + 'static), U, V>`
           - `Quantity<(dyn Dimension<I = Z0, J = Z0, Kind = (dyn Kind + 'static), L = Z0, M = Z0, N = PInt<UInt<UTerm, B1>>, T = Z0, Th = Z0> + 'static), U, V>`
           and 106 more types

error[E0277]: `dyn Dimension<I = Z0, J = Z0, Kind = (dyn Kind + 'static), L = PInt<UInt<UTerm, B1>>, M = Z0, N = Z0, T = Z0, Th = Z0>` doesn't implement `Debug`
  --> src/main.rs:36:15
   |
36 |     println!("{n:?}");
   |               ^^^^^ `dyn Dimension<I = Z0, J = Z0, Kind = (dyn Kind + 'static), L = PInt<UInt<UTerm, B1>>, M = Z0, N = Z0, T = Z0, Th = Z0>` cannot be formatted using `{:?}` because it doesn't implement `Debug`
   |
   = help: the trait `Debug` is not implemented for `dyn Dimension<I = Z0, J = Z0, Kind = (dyn Kind + 'static), L = PInt<UInt<UTerm, B1>>, M = Z0, N = Z0, T = Z0, Th = Z0>`
   = help: the following other types implement trait `Debug`:
             (dyn Any + 'static)
             (dyn Any + Send + 'static)
             (dyn Any + Send + Sync + 'static)
   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)

Some errors have detailed explanations: E0277, E0599.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `scratchpad` (bin "scratchpad") due to 3 previous errors

I am having trouble understanding what is going on here because I was under the impression that there is a blanket implementation of new for Quantity, but apparently that's not the case.

If I comment out the lines with Quantity::<D, SI<f64>, f64>::new::<U>(...).value,, e.g. like 0.0, //Quantity::<D, SI<f64>, f64>::new::<U>(x).value,, the debug error still persists:

   Compiling scratchpad v0.1.0 (/home/joe/saronic/scratch/scratchpad)
error[E0277]: `dyn Dimension<I = Z0, J = Z0, Kind = (dyn Kind + 'static), L = PInt<UInt<UTerm, B1>>, M = Z0, N = Z0, T = Z0, Th = Z0>` doesn't implement `Debug`
  --> src/main.rs:36:15
   |
36 |     println!("{n:?}");
   |               ^^^^^ `dyn Dimension<I = Z0, J = Z0, Kind = (dyn Kind + 'static), L = PInt<UInt<UTerm, B1>>, M = Z0, N = Z0, T = Z0, Th = Z0>` cannot be formatted using `{:?}` because it doesn't implement `Debug`
   |
   = help: the trait `Debug` is not implemented for `dyn Dimension<I = Z0, J = Z0, Kind = (dyn Kind + 'static), L = PInt<UInt<UTerm, B1>>, M = Z0, N = Z0, T = Z0, Th = Z0>`
   = help: the following other types implement trait `Debug`:
             (dyn Any + 'static)
             (dyn Any + Send + 'static)
             (dyn Any + Send + Sync + 'static)
   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0277`.
error: could not compile `scratchpad` (bin "scratchpad") due to previous error

I have had a hard time finding a good tutorial for UOM. My issue is that while the crate is well documented and thorough, it appears to assume a certain level of prior knowledge that I simply don't have.

@iliekturtles
Copy link
Owner

I didn't have a chance to fully go through your code and try to compile locally to resolve the errors. My guess right now is that type constraints are missing and compiler isn't explicitly calling them out.

Is there any reason you want to store the data as buf: [f64; 2], and not buf: [Quantity<D, SI<f64>, f64>; 2],? Doing this would skip the need to construct and deconstruct the types and reduce the need for constraints.

@joe-saronic
Copy link
Author

@iliekturtles Thanks for looking into this. The arrays in this code are a standin for nalgebra::Vector2, which is what I'm really using. I didn't think the particular type was related to the issue, but I'll definitely try to make a vector of quantities.

@joe-saronic
Copy link
Author

@iliekturtles That being said, is there a way to convert an f64 and a Units to a quantity of the appropriate dimension somehow? It seems like this should be possible, but I haven't had any luck figuring it out.

@joe-saronic
Copy link
Author

I have had a hard time understanding how to get Dimension from a Units, and how the Conversion trait really works for arbitrary cases. I suspect that it's tied to the answer somehow.

@iliekturtles
Copy link
Owner

If you know the quantity (Length in the example below), you can explicitly provide the dimension, underlying storage type, and unit to create a quantity. There isn't a way to get the dimension when you just have a unit.

use uom::si::length as l;
use uom::si::*;

fn main() {
    let x = Quantity::<l::Dimension, SI<f32>, f32>::new::<l::meter>(5.0);

    println!("{:?}", x); // 5.0 m^1
}

@joe-saronic
Copy link
Author

The issue is that I don't have the quantity available initially. Is there a way to get the mapping between meter and length::Dimension somehow?

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