Skip to content

Commit 8d36211

Browse files
committed
Conversion now has both a value and a factor type
Initially, `ConversionFactor` and thus `Conversion::T` requred `PartialEq`. This makes sense for the conversion factor itself (i.e. scaling across units), however it breaks once you introduce complex numbers. Those can *still* be scaled just like normal numbers - you essentially just increase or decrese a vector length, but the conversion function cannot compare them - "Z_1 < Z_2" is not trivially decidable. It is, however, also not needed - unit scales are just that - scalars that scale. And those can be easily compared. This commit seperates `Conversion::T` into `Conversion::VT` and `Conversion::T` and moves the `PartialEq` requirements from `ConversionFactor` into `Conversion::TT` directly. This requires a lot of trait bounds added down the line, so im not 100% that this does not break anything down the line. There might be a nicer way to go about this, but i haven't found any. closes #452
1 parent edee7cb commit 8d36211

7 files changed

Lines changed: 103 additions & 58 deletions

File tree

src/lib.rs

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -408,13 +408,15 @@ pub enum ConstantOp {
408408
/// Trait to identify [units][units] which have a [conversion factor][factor].
409409
///
410410
/// ## Generic Parameters
411-
/// * `V`: Underlying storage type trait is implemented for.
412-
///
411+
/// * `T`: The type of the conversion factor. Usually same as `VT`, but for example complex storage types have this as float as it needs `PartialEq`
412+
/// * `VT`: Underlying storage type trait is implemented for. Does not have to implement `PartialEq`, so its viable for complex data types.
413413
/// [units]: https://jcgm.bipm.org/vim/en/1.13.html
414414
/// [factor]: https://jcgm.bipm.org/vim/en/1.24.html
415415
pub trait Conversion<V> {
416416
/// Conversion factor type specific to the underlying storage type.
417-
type T: ConversionFactor<V>;
417+
type T: ConversionFactor<V> + PartialOrd;
418+
/// Value type of the underlying type.
419+
type VT: ConversionFactor<V> + From<Self::T>;
418420

419421
/// Coefficient portion of [conversion factor](https://jcgm.bipm.org/vim/en/1.24.html) for
420422
/// converting the given unit. To convert to the base unit for the quantity use `(value +
@@ -436,21 +438,17 @@ pub trait Conversion<V> {
436438
#[must_use = "method returns a new number and does not mutate the original value"]
437439
#[inline(always)]
438440
#[allow(unused_variables)]
439-
fn constant(op: ConstantOp) -> Self::T {
440-
<Self::T as num::Zero>::zero()
441+
fn constant(op: ConstantOp) -> Self::VT {
442+
<Self::VT as num::Zero>::zero()
441443
}
442444

443445
/// Instance [conversion factor](https://jcgm.bipm.org/vim/en/1.24.html).
444446
///
445447
/// Default implementation returns the coefficient: `Self::coefficient()`.
446448
#[must_use = "method returns a new number and does not mutate the original value"]
447-
#[inline(always)]
448-
fn conversion(&self) -> Self::T
449+
fn conversion(&self) -> Self::VT
449450
where
450-
Self: Sized,
451-
{
452-
Self::coefficient()
453-
}
451+
Self: Sized;
454452
}
455453

456454
/// Trait representing a [conversion factor][factor].
@@ -461,8 +459,7 @@ pub trait Conversion<V> {
461459
/// [factor]: https://jcgm.bipm.org/vim/en/1.24.html
462460
#[allow(unused_qualifications)] // lib:cmp::PartialOrder false positive.
463461
pub trait ConversionFactor<V>:
464-
lib::cmp::PartialOrd
465-
+ lib::ops::Add<Self, Output = Self>
462+
lib::ops::Add<Self, Output = Self>
466463
+ lib::ops::Sub<Self, Output = Self>
467464
+ lib::ops::Mul<Self, Output = Self>
468465
+ lib::ops::Div<Self, Output = Self>
@@ -515,19 +512,20 @@ pub trait Kind:
515512
storage_types! {
516513
types: Float;
517514

518-
impl crate::Conversion<Self> for V {
515+
impl crate::Conversion<V> for V {
519516
type T = Self;
517+
type VT = Self::T;
520518

521519
#[inline(always)]
522-
fn constant(op: crate::ConstantOp) -> Self::T {
520+
fn constant(op: crate::ConstantOp) -> Self::VT {
523521
match op {
524-
crate::ConstantOp::Add => -<Self::T as crate::num::Zero>::zero(),
525-
crate::ConstantOp::Sub => <Self::T as crate::num::Zero>::zero(),
522+
crate::ConstantOp::Add => -<Self::VT as crate::num::Zero>::zero(),
523+
crate::ConstantOp::Sub => <Self::VT as crate::num::Zero>::zero(),
526524
}
527525
}
528526

529527
#[inline(always)]
530-
fn conversion(&self) -> Self::T {
528+
fn conversion(&self) -> Self::VT {
531529
*self
532530
}
533531
}
@@ -554,9 +552,10 @@ storage_types! {
554552

555553
impl crate::Conversion<V> for V {
556554
type T = crate::num::rational::Ratio<V>;
555+
type VT = Self::T;
557556

558557
#[inline(always)]
559-
fn conversion(&self) -> Self::T {
558+
fn conversion(&self) -> Self::VT {
560559
(*self).into()
561560
}
562561
}
@@ -583,9 +582,10 @@ storage_types! {
583582

584583
impl crate::Conversion<V> for V {
585584
type T = crate::num::rational::Ratio<V>;
585+
type VT = Self::T;
586586

587587
#[inline(always)]
588-
fn conversion(&self) -> Self::T {
588+
fn conversion(&self) -> Self::VT {
589589
self.clone().into()
590590
}
591591
}
@@ -612,9 +612,10 @@ storage_types! {
612612

613613
impl crate::Conversion<V> for V {
614614
type T = V;
615+
type VT = Self::T;
615616

616617
#[inline(always)]
617-
fn conversion(&self) -> Self::T {
618+
fn conversion(&self) -> Self::VT {
618619
*self
619620
}
620621
}
@@ -637,9 +638,10 @@ storage_types! {
637638

638639
impl crate::Conversion<V> for V {
639640
type T = V;
641+
type VT = Self::T;
640642

641643
#[inline(always)]
642-
fn conversion(&self) -> Self::T {
644+
fn conversion(&self) -> Self::VT {
643645
self.clone()
644646
}
645647
}
@@ -665,20 +667,21 @@ storage_types! {
665667
types: Complex;
666668
impl crate::Conversion<V> for V {
667669
type T = VV;
670+
type VT = V;
668671

669672
#[inline(always)]
670-
fn constant(op: crate::ConstantOp) -> Self::T {
673+
fn constant(op: crate::ConstantOp) -> Self::VT {
671674
match op {
672-
crate::ConstantOp::Add => -<Self::T as crate::num::Zero>::zero(),
673-
crate::ConstantOp::Sub => <Self::T as crate::num::Zero>::zero(),
675+
crate::ConstantOp::Add => -<Self::VT as crate::num::Zero>::zero(),
676+
crate::ConstantOp::Sub => <Self::VT as crate::num::Zero>::zero(),
674677
}
675678
}
676679

677680
#[inline(always)]
678-
fn conversion(&self) -> Self::T {
681+
fn conversion(&self) -> Self::VT {
679682
// Conversion factor is the norm of the number. Scaling with length again yields the
680683
// same number.
681-
self.norm()
684+
*self
682685
}
683686
}
684687

@@ -695,6 +698,18 @@ storage_types! {
695698
V::new(self, 0.0)
696699
}
697700
}
701+
702+
impl crate::ConversionFactor<V> for V {
703+
#[inline(always)]
704+
fn powi(self, e: i32) -> Self {
705+
crate::num::complex::Complex::powi(&self,e)
706+
}
707+
708+
#[inline(always)]
709+
fn value(self) -> V {
710+
self
711+
}
712+
}
698713
}
699714

700715
/// Utilities for formatting and printing quantities.

src/quantity.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ macro_rules! quantity {
133133
/// [units]: https://jcgm.bipm.org/vim/en/1.13.html
134134
/// [factor]: https://jcgm.bipm.org/vim/en/1.24.html
135135
#[allow(dead_code)]
136-
pub trait Conversion<V>: Unit + $crate::Conversion<V, T = <V as $crate::Conversion<V>>::T>
136+
pub trait Conversion<V>: Unit + $crate::Conversion<V, T = <V as $crate::Conversion<V>>::T, VT = <V as $crate::Conversion<V>>::VT>
137137
where
138138
V: $crate::Conversion<V>,
139139
{
@@ -218,7 +218,7 @@ macro_rules! quantity {
218218
#[inline(always)]
219219
pub fn new<N>(v: V) -> Self
220220
where
221-
N: Unit + $crate::Conversion<V, T = V::T>,
221+
N: Unit + $crate::Conversion<V, T = V::T, VT = V::VT>,
222222
{
223223
$quantity {
224224
dimension: $crate::lib::marker::PhantomData,
@@ -235,7 +235,7 @@ macro_rules! quantity {
235235
#[inline(always)]
236236
pub fn get<N>(&self) -> V
237237
where
238-
N: Unit + $crate::Conversion<V, T = V::T>,
238+
N: Unit + $crate::Conversion<V, T = V::T, VT = V::VT>,
239239
{
240240
__system::from_base::<Dimension, U, V, N>(&self.value)
241241
}
@@ -250,7 +250,7 @@ macro_rules! quantity {
250250
pub fn floor<N>(self) -> Self
251251
where
252252
V: $crate::num::Float,
253-
N: Unit + $crate::Conversion<V, T = V::T>,
253+
N: Unit + $crate::Conversion<V, T = V::T, VT = V::VT>,
254254
{
255255
Self::new::<N>(self.get::<N>().floor())
256256
}
@@ -265,7 +265,7 @@ macro_rules! quantity {
265265
pub fn ceil<N>(self) -> Self
266266
where
267267
V: $crate::num::Float,
268-
N: Unit + $crate::Conversion<V, T = V::T>,
268+
N: Unit + $crate::Conversion<V, T = V::T, VT = V::VT>,
269269
{
270270
Self::new::<N>(self.get::<N>().ceil())
271271
}
@@ -280,7 +280,7 @@ macro_rules! quantity {
280280
pub fn round<N>(self) -> Self
281281
where
282282
V: $crate::num::Float,
283-
N: Unit + $crate::Conversion<V, T = V::T>,
283+
N: Unit + $crate::Conversion<V, T = V::T, VT = V::VT>,
284284
{
285285
Self::new::<N>(self.get::<N>().round())
286286
}
@@ -294,7 +294,7 @@ macro_rules! quantity {
294294
pub fn trunc<N>(self) -> Self
295295
where
296296
V: $crate::num::Float,
297-
N: Unit + $crate::Conversion<V, T = V::T>,
297+
N: Unit + $crate::Conversion<V, T = V::T, VT = V::VT>,
298298
{
299299
Self::new::<N>(self.get::<N>().trunc())
300300
}
@@ -308,7 +308,7 @@ macro_rules! quantity {
308308
pub fn fract<N>(self) -> Self
309309
where
310310
V: $crate::num::Float,
311-
N: Unit + $crate::Conversion<V, T = V::T>,
311+
N: Unit + $crate::Conversion<V, T = V::T, VT = V::VT>,
312312
{
313313
Self::new::<N>(self.get::<N>().fract())
314314
}

src/si/angle.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ where
127127
D: crate::si::Dimension + ?Sized,
128128
U: crate::si::Units<V> + ?Sized,
129129
V: crate::num::Float + crate::Conversion<V>,
130-
radian: crate::Conversion<V, T = V::T>,
130+
radian: crate::Conversion<V, T = V::T, VT = V::VT>,
131131
{
132132
/// Computes the four quadrant arctangent of self (y) and other (x).
133133
#[must_use = "method returns a new number and does not mutate the original value"]

src/si/ratio.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ impl<U, V> Ratio<U, V>
3939
where
4040
U: crate::si::Units<V> + ?Sized,
4141
V: crate::num::Float + crate::Conversion<V>,
42-
radian: crate::Conversion<V, T = V::T>,
43-
ratio: crate::Conversion<V, T = V::T>,
42+
radian: crate::Conversion<V, T = V::T, VT = V::VT>,
43+
ratio: crate::Conversion<V, T = V::T, VT = V::VT>,
4444
{
4545
/// Computes the value of the inverse cosine of the ratio.
4646
#[must_use = "method returns a new number and does not mutate the original value"]

src/si/time.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ impl<U, V> crate::lib::convert::TryFrom<Time<U, V>> for Duration
8282
where
8383
U: crate::si::Units<V> + ?Sized,
8484
V: crate::num::Num + crate::Conversion<V> + PartialOrd + ToPrimitive,
85-
second: crate::Conversion<V, T = V::T>,
86-
nanosecond: crate::Conversion<V, T = V::T>,
85+
second: crate::Conversion<V, T = V::T, VT = V::VT>,
86+
nanosecond: crate::Conversion<V, T = V::T, VT = V::VT>,
8787
{
8888
type Error = TryFromError;
8989

@@ -117,8 +117,8 @@ impl<U, V> crate::lib::convert::TryFrom<Duration> for Time<U, V>
117117
where
118118
U: crate::si::Units<V> + ?Sized,
119119
V: crate::num::Num + crate::Conversion<V> + FromPrimitive,
120-
second: crate::Conversion<V, T = V::T>,
121-
nanosecond: crate::Conversion<V, T = V::T>,
120+
second: crate::Conversion<V, T = V::T, VT = V::VT>,
121+
nanosecond: crate::Conversion<V, T = V::T, VT = V::VT>,
122122
{
123123
type Error = TryFromError;
124124

src/system.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ macro_rules! system {
163163
///
164164
/// Base unit.
165165
#[allow(non_camel_case_types)]
166-
type $name: Unit + $crate::Conversion<V, T = V::T>;)+
166+
type $name: Unit + $crate::Conversion<V, T = V::T, VT = V::VT>;)+
167167
}
168168

169169
/// Trait to identify [measurement units][measurement] of individual
@@ -307,7 +307,7 @@ macro_rules! system {
307307
D: Dimension + ?Sized,
308308
U: Units<V> + ?Sized,
309309
V: $crate::Conversion<V>,
310-
N: $crate::Conversion<V, T = V::T>,
310+
N: $crate::Conversion<V, T = V::T, VT = V::VT>,
311311
{
312312
use $crate::typenum::Integer;
313313
use $crate::{Conversion, ConversionFactor};
@@ -318,10 +318,10 @@ macro_rules! system {
318318
let n_cons = N::constant($crate::ConstantOp::Sub);
319319

320320
if n_coef < f {
321-
(v * (f / n_coef) - n_cons).value()
321+
(v * (f / n_coef).into() - n_cons.into()).value()
322322
}
323323
else {
324-
(v / (n_coef / f) - n_cons).value()
324+
(v / (n_coef / f).into() - n_cons.into()).value()
325325
}
326326
}
327327

@@ -338,7 +338,7 @@ macro_rules! system {
338338
D: Dimension + ?Sized,
339339
U: Units<V> + ?Sized,
340340
V: $crate::Conversion<V>,
341-
N: $crate::Conversion<V, T = V::T>,
341+
N: $crate::Conversion<V, T = V::T, VT= V::VT>,
342342
{
343343
use $crate::typenum::Integer;
344344
use $crate::{Conversion, ConversionFactor};
@@ -349,10 +349,10 @@ macro_rules! system {
349349
let n_cons = N::constant($crate::ConstantOp::Add);
350350

351351
if n_coef >= f {
352-
((v + n_cons) * (n_coef / f)).value()
352+
((v + n_cons.into()) * (n_coef / f).into()).value()
353353
}
354354
else {
355-
(((v + n_cons) * n_coef) / f).value()
355+
(((v + n_cons.into()) * n_coef.into()) / f.into()).value()
356356
}
357357
}
358358

@@ -376,8 +376,8 @@ macro_rules! system {
376376
use $crate::typenum::Integer;
377377
use $crate::{Conversion, ConversionFactor};
378378

379-
(v.conversion() $(* Ur::$name::coefficient().powi(D::$symbol::to_i32())
380-
/ Ul::$name::coefficient().powi(D::$symbol::to_i32()))+)
379+
(v.conversion() $(* Ur::$name::coefficient().powi(D::$symbol::to_i32()).into()
380+
/ Ul::$name::coefficient().powi(D::$symbol::to_i32()).into())+)
381381
.value()
382382
}}
383383

@@ -1508,7 +1508,7 @@ macro_rules! system {
15081508
D: Dimension + ?Sized,
15091509
U: Units<V> + ?Sized,
15101510
V: Num + Conversion<V> + fmt::$style,
1511-
N: Unit + Conversion<V, T = V::T>,
1511+
N: Unit + Conversion<V, T = V::T, VT = V::VT>,
15121512
{
15131513
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
15141514
let value = from_base::<D, U, V, N>(&self.quantity.value);

0 commit comments

Comments
 (0)