Skip to main content

cu29_units/
lib.rs

1//! Copper-native SI quantity wrappers.
2//!
3//! Feature flags:
4//! - `default` = `["std"]`
5//! - `std`: enables `uom/std`
6//! - `reflect`: enables `bevy_reflect` support on wrapper types
7//! - `textlogs`: compatibility no-op for downstream feature forwarding
8//!
9#![cfg_attr(not(feature = "std"), no_std)]
10
11pub use uom;
12
13macro_rules! define_storage_wrappers {
14    ($storage_mod:ident, $storage_ty:ty, [$(($unit_mod:ident, $quantity:ident),)+]) => {
15        pub mod $storage_mod {
16            use core::marker::PhantomData;
17            use serde::{Deserialize, Deserializer, Serialize, Serializer};
18
19            #[cfg(feature = "reflect")]
20            use bevy_reflect::Reflect;
21
22            macro_rules! define_quantity {
23                ($unit_mod_name:ident, $quantity_name:ident) => {
24                    #[repr(transparent)]
25                    #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
26                    #[cfg_attr(feature = "reflect", derive(Reflect))]
27                    #[cfg_attr(feature = "reflect", reflect(opaque, from_reflect = false))]
28                    pub struct $quantity_name(pub(crate) uom::si::$storage_mod::$quantity_name);
29
30                    impl $quantity_name {
31                        #[inline]
32                        pub fn new<U>(value: $storage_ty) -> Self
33                        where
34                            U: uom::si::$unit_mod_name::Conversion<$storage_ty>,
35                        {
36                            Self(uom::si::$storage_mod::$quantity_name::new::<U>(value))
37                        }
38
39                        #[inline]
40                        pub fn get<U>(&self) -> $storage_ty
41                        where
42                            U: uom::si::$unit_mod_name::Conversion<$storage_ty>,
43                        {
44                            self.0.get::<U>()
45                        }
46
47                        #[inline]
48                        pub fn raw(&self) -> $storage_ty {
49                            self.0.value
50                        }
51
52                        #[inline]
53                        pub fn into_uom(self) -> uom::si::$storage_mod::$quantity_name {
54                            self.0
55                        }
56
57                        #[inline]
58                        pub fn as_uom(&self) -> &uom::si::$storage_mod::$quantity_name {
59                            &self.0
60                        }
61
62                        #[inline]
63                        pub fn from_uom(inner: uom::si::$storage_mod::$quantity_name) -> Self {
64                            Self(inner)
65                        }
66
67                        #[inline]
68                        fn from_base_value(
69                            value: $storage_ty,
70                        ) -> uom::si::$storage_mod::$quantity_name {
71                            uom::si::$storage_mod::$quantity_name {
72                                dimension: PhantomData,
73                                units: PhantomData,
74                                value,
75                            }
76                        }
77                    }
78
79                    impl Default for $quantity_name {
80                        fn default() -> Self {
81                            Self(Self::from_base_value(0.0 as $storage_ty))
82                        }
83                    }
84
85                    impl From<uom::si::$storage_mod::$quantity_name> for $quantity_name {
86                        fn from(value: uom::si::$storage_mod::$quantity_name) -> Self {
87                            Self(value)
88                        }
89                    }
90
91                    impl From<$quantity_name> for uom::si::$storage_mod::$quantity_name {
92                        fn from(value: $quantity_name) -> Self {
93                            value.0
94                        }
95                    }
96
97                    impl core::ops::Deref for $quantity_name {
98                        type Target = uom::si::$storage_mod::$quantity_name;
99
100                        fn deref(&self) -> &Self::Target {
101                            &self.0
102                        }
103                    }
104
105                    impl core::ops::Add for $quantity_name {
106                        type Output = Self;
107
108                        fn add(self, rhs: Self) -> Self::Output {
109                            Self(Self::from_base_value(self.raw() + rhs.raw()))
110                        }
111                    }
112
113                    impl core::ops::AddAssign for $quantity_name {
114                        fn add_assign(&mut self, rhs: Self) {
115                            *self = *self + rhs;
116                        }
117                    }
118
119                    impl core::ops::Sub for $quantity_name {
120                        type Output = Self;
121
122                        fn sub(self, rhs: Self) -> Self::Output {
123                            Self(Self::from_base_value(self.raw() - rhs.raw()))
124                        }
125                    }
126
127                    impl core::ops::SubAssign for $quantity_name {
128                        fn sub_assign(&mut self, rhs: Self) {
129                            *self = *self - rhs;
130                        }
131                    }
132
133                    impl core::ops::Mul<$storage_ty> for $quantity_name {
134                        type Output = Self;
135
136                        fn mul(self, rhs: $storage_ty) -> Self::Output {
137                            Self(Self::from_base_value(self.raw() * rhs))
138                        }
139                    }
140
141                    impl core::ops::MulAssign<$storage_ty> for $quantity_name {
142                        fn mul_assign(&mut self, rhs: $storage_ty) {
143                            *self = *self * rhs;
144                        }
145                    }
146
147                    impl core::ops::Div<$storage_ty> for $quantity_name {
148                        type Output = Self;
149
150                        fn div(self, rhs: $storage_ty) -> Self::Output {
151                            Self(Self::from_base_value(self.raw() / rhs))
152                        }
153                    }
154
155                    impl core::ops::DivAssign<$storage_ty> for $quantity_name {
156                        fn div_assign(&mut self, rhs: $storage_ty) {
157                            *self = *self / rhs;
158                        }
159                    }
160
161                    impl core::ops::Neg for $quantity_name {
162                        type Output = Self;
163
164                        fn neg(self) -> Self::Output {
165                            Self(Self::from_base_value(-self.raw()))
166                        }
167                    }
168
169                    impl Serialize for $quantity_name {
170                        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
171                        where
172                            S: Serializer,
173                        {
174                            self.raw().serialize(serializer)
175                        }
176                    }
177
178                    impl<'de> Deserialize<'de> for $quantity_name {
179                        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
180                        where
181                            D: Deserializer<'de>,
182                        {
183                            let value = <$storage_ty>::deserialize(deserializer)?;
184                            Ok(Self(Self::from_base_value(value)))
185                        }
186                    }
187
188                    impl bincode::Encode for $quantity_name {
189                        fn encode<E: bincode::enc::Encoder>(
190                            &self,
191                            encoder: &mut E,
192                        ) -> Result<(), bincode::error::EncodeError> {
193                            bincode::Encode::encode(&self.raw(), encoder)
194                        }
195                    }
196
197                    impl<Context> bincode::Decode<Context> for $quantity_name {
198                        fn decode<D: bincode::de::Decoder<Context = Context>>(
199                            decoder: &mut D,
200                        ) -> Result<Self, bincode::error::DecodeError> {
201                            let value: $storage_ty = bincode::Decode::decode(decoder)?;
202                            Ok(Self(Self::from_base_value(value)))
203                        }
204                    }
205
206                    impl<'de, Context> bincode::BorrowDecode<'de, Context> for $quantity_name {
207                        fn borrow_decode<D: bincode::de::BorrowDecoder<'de, Context = Context>>(
208                            decoder: &mut D,
209                        ) -> Result<Self, bincode::error::DecodeError> {
210                            <Self as bincode::Decode<Context>>::decode(decoder)
211                        }
212                    }
213
214                    #[cfg(feature = "reflect")]
215                    impl bevy_reflect::FromReflect for $quantity_name {
216                        fn from_reflect(
217                            reflect: &dyn bevy_reflect::PartialReflect,
218                        ) -> Option<Self> {
219                            if let Some(existing) = reflect.try_downcast_ref::<Self>() {
220                                return Some(*existing);
221                            }
222
223                            reflect
224                                .try_downcast_ref::<$storage_ty>()
225                                .map(|value| Self(Self::from_base_value(*value)))
226                        }
227                    }
228                };
229            }
230
231            $(define_quantity!($unit_mod, $quantity);)+
232        }
233    };
234}
235
236pub mod si {
237    pub use uom::si::{
238        ISQ, SI, absement, acceleration, action, amount_of_substance, angle, angular_absement,
239        angular_acceleration, angular_jerk, angular_momentum, angular_velocity, area,
240        areal_density_of_states, areal_heat_capacity, areal_mass_density, areal_number_density,
241        areal_number_rate, available_energy, capacitance, catalytic_activity,
242        catalytic_activity_concentration, curvature, diffusion_coefficient, dynamic_viscosity,
243        electric_charge, electric_charge_areal_density, electric_charge_linear_density,
244        electric_charge_volumetric_density, electric_current, electric_current_density,
245        electric_dipole_moment, electric_displacement_field, electric_field, electric_flux,
246        electric_permittivity, electric_potential, electric_quadrupole_moment,
247        electrical_conductance, electrical_conductivity, electrical_mobility,
248        electrical_resistance, electrical_resistivity, energy, force, frequency, frequency_drift,
249        heat_capacity, heat_flux_density, heat_transfer, inductance, information, information_rate,
250        inverse_velocity, jerk, kinematic_viscosity, length, linear_density_of_states,
251        linear_mass_density, linear_number_density, linear_number_rate, linear_power_density,
252        luminance, luminous_intensity, magnetic_field_strength, magnetic_flux,
253        magnetic_flux_density, magnetic_moment, magnetic_permeability, mass, mass_concentration,
254        mass_density, mass_flux, mass_per_energy, mass_rate, molality, molar_concentration,
255        molar_energy, molar_flux, molar_heat_capacity, molar_mass, molar_radioactivity,
256        molar_volume, moment_of_inertia, momentum, power, power_rate, pressure, radiant_exposure,
257        radioactivity, ratio, reciprocal_length, solid_angle, specific_area,
258        specific_heat_capacity, specific_power, specific_radioactivity, specific_volume,
259        surface_electric_current_density, surface_tension, temperature_coefficient,
260        temperature_gradient, temperature_interval, thermal_conductance, thermal_conductivity,
261        thermal_resistance, thermodynamic_temperature, time, torque, velocity, volume, volume_rate,
262        volumetric_density_of_states, volumetric_heat_capacity, volumetric_number_density,
263        volumetric_number_rate, volumetric_power_density,
264    };
265
266    define_storage_wrappers! {
267        f32,
268        f32,
269        [
270            (absement, Absement),
271            (acceleration, Acceleration),
272            (action, Action),
273            (amount_of_substance, AmountOfSubstance),
274            (angle, Angle),
275            (angular_absement, AngularAbsement),
276            (angular_acceleration, AngularAcceleration),
277            (angular_jerk, AngularJerk),
278            (angular_momentum, AngularMomentum),
279            (angular_velocity, AngularVelocity),
280            (area, Area),
281            (areal_density_of_states, ArealDensityOfStates),
282            (areal_heat_capacity, ArealHeatCapacity),
283            (areal_mass_density, ArealMassDensity),
284            (areal_number_density, ArealNumberDensity),
285            (areal_number_rate, ArealNumberRate),
286            (available_energy, AvailableEnergy),
287            (capacitance, Capacitance),
288            (catalytic_activity, CatalyticActivity),
289            (catalytic_activity_concentration, CatalyticActivityConcentration),
290            (curvature, Curvature),
291            (diffusion_coefficient, DiffusionCoefficient),
292            (dynamic_viscosity, DynamicViscosity),
293            (electric_charge, ElectricCharge),
294            (electric_charge_areal_density, ElectricChargeArealDensity),
295            (electric_charge_linear_density, ElectricChargeLinearDensity),
296            (electric_charge_volumetric_density, ElectricChargeVolumetricDensity),
297            (electric_current, ElectricCurrent),
298            (electric_current_density, ElectricCurrentDensity),
299            (electric_dipole_moment, ElectricDipoleMoment),
300            (electric_displacement_field, ElectricDisplacementField),
301            (electric_field, ElectricField),
302            (electric_flux, ElectricFlux),
303            (electric_permittivity, ElectricPermittivity),
304            (electric_potential, ElectricPotential),
305            (electric_quadrupole_moment, ElectricQuadrupoleMoment),
306            (electrical_conductance, ElectricalConductance),
307            (electrical_conductivity, ElectricalConductivity),
308            (electrical_mobility, ElectricalMobility),
309            (electrical_resistance, ElectricalResistance),
310            (electrical_resistivity, ElectricalResistivity),
311            (energy, Energy),
312            (force, Force),
313            (frequency, Frequency),
314            (frequency_drift, FrequencyDrift),
315            (heat_capacity, HeatCapacity),
316            (heat_flux_density, HeatFluxDensity),
317            (heat_transfer, HeatTransfer),
318            (inductance, Inductance),
319            (information, Information),
320            (information_rate, InformationRate),
321            (inverse_velocity, InverseVelocity),
322            (jerk, Jerk),
323            (kinematic_viscosity, KinematicViscosity),
324            (length, Length),
325            (linear_density_of_states, LinearDensityOfStates),
326            (linear_mass_density, LinearMassDensity),
327            (linear_number_density, LinearNumberDensity),
328            (linear_number_rate, LinearNumberRate),
329            (linear_power_density, LinearPowerDensity),
330            (luminance, Luminance),
331            (luminous_intensity, LuminousIntensity),
332            (magnetic_field_strength, MagneticFieldStrength),
333            (magnetic_flux, MagneticFlux),
334            (magnetic_flux_density, MagneticFluxDensity),
335            (magnetic_moment, MagneticMoment),
336            (magnetic_permeability, MagneticPermeability),
337            (mass, Mass),
338            (mass_concentration, MassConcentration),
339            (mass_density, MassDensity),
340            (mass_flux, MassFlux),
341            (mass_per_energy, MassPerEnergy),
342            (mass_rate, MassRate),
343            (molality, Molality),
344            (molar_concentration, MolarConcentration),
345            (molar_energy, MolarEnergy),
346            (molar_flux, MolarFlux),
347            (molar_heat_capacity, MolarHeatCapacity),
348            (molar_mass, MolarMass),
349            (molar_radioactivity, MolarRadioactivity),
350            (molar_volume, MolarVolume),
351            (moment_of_inertia, MomentOfInertia),
352            (momentum, Momentum),
353            (power, Power),
354            (power_rate, PowerRate),
355            (pressure, Pressure),
356            (radiant_exposure, RadiantExposure),
357            (radioactivity, Radioactivity),
358            (ratio, Ratio),
359            (reciprocal_length, ReciprocalLength),
360            (solid_angle, SolidAngle),
361            (specific_area, SpecificArea),
362            (specific_heat_capacity, SpecificHeatCapacity),
363            (specific_power, SpecificPower),
364            (specific_radioactivity, SpecificRadioactivity),
365            (specific_volume, SpecificVolume),
366            (surface_electric_current_density, SurfaceElectricCurrentDensity),
367            (surface_tension, SurfaceTension),
368            (temperature_coefficient, TemperatureCoefficient),
369            (temperature_gradient, TemperatureGradient),
370            (temperature_interval, TemperatureInterval),
371            (thermal_conductance, ThermalConductance),
372            (thermal_conductivity, ThermalConductivity),
373            (thermal_resistance, ThermalResistance),
374            (thermodynamic_temperature, ThermodynamicTemperature),
375            (time, Time),
376            (torque, Torque),
377            (velocity, Velocity),
378            (volume, Volume),
379            (volume_rate, VolumeRate),
380            (volumetric_density_of_states, VolumetricDensityOfStates),
381            (volumetric_heat_capacity, VolumetricHeatCapacity),
382            (volumetric_number_density, VolumetricNumberDensity),
383            (volumetric_number_rate, VolumetricNumberRate),
384            (volumetric_power_density, VolumetricPowerDensity),
385        ]
386    }
387
388    define_storage_wrappers! {
389        f64,
390        f64,
391        [
392            (absement, Absement),
393            (acceleration, Acceleration),
394            (action, Action),
395            (amount_of_substance, AmountOfSubstance),
396            (angle, Angle),
397            (angular_absement, AngularAbsement),
398            (angular_acceleration, AngularAcceleration),
399            (angular_jerk, AngularJerk),
400            (angular_momentum, AngularMomentum),
401            (angular_velocity, AngularVelocity),
402            (area, Area),
403            (areal_density_of_states, ArealDensityOfStates),
404            (areal_heat_capacity, ArealHeatCapacity),
405            (areal_mass_density, ArealMassDensity),
406            (areal_number_density, ArealNumberDensity),
407            (areal_number_rate, ArealNumberRate),
408            (available_energy, AvailableEnergy),
409            (capacitance, Capacitance),
410            (catalytic_activity, CatalyticActivity),
411            (catalytic_activity_concentration, CatalyticActivityConcentration),
412            (curvature, Curvature),
413            (diffusion_coefficient, DiffusionCoefficient),
414            (dynamic_viscosity, DynamicViscosity),
415            (electric_charge, ElectricCharge),
416            (electric_charge_areal_density, ElectricChargeArealDensity),
417            (electric_charge_linear_density, ElectricChargeLinearDensity),
418            (electric_charge_volumetric_density, ElectricChargeVolumetricDensity),
419            (electric_current, ElectricCurrent),
420            (electric_current_density, ElectricCurrentDensity),
421            (electric_dipole_moment, ElectricDipoleMoment),
422            (electric_displacement_field, ElectricDisplacementField),
423            (electric_field, ElectricField),
424            (electric_flux, ElectricFlux),
425            (electric_permittivity, ElectricPermittivity),
426            (electric_potential, ElectricPotential),
427            (electric_quadrupole_moment, ElectricQuadrupoleMoment),
428            (electrical_conductance, ElectricalConductance),
429            (electrical_conductivity, ElectricalConductivity),
430            (electrical_mobility, ElectricalMobility),
431            (electrical_resistance, ElectricalResistance),
432            (electrical_resistivity, ElectricalResistivity),
433            (energy, Energy),
434            (force, Force),
435            (frequency, Frequency),
436            (frequency_drift, FrequencyDrift),
437            (heat_capacity, HeatCapacity),
438            (heat_flux_density, HeatFluxDensity),
439            (heat_transfer, HeatTransfer),
440            (inductance, Inductance),
441            (information, Information),
442            (information_rate, InformationRate),
443            (inverse_velocity, InverseVelocity),
444            (jerk, Jerk),
445            (kinematic_viscosity, KinematicViscosity),
446            (length, Length),
447            (linear_density_of_states, LinearDensityOfStates),
448            (linear_mass_density, LinearMassDensity),
449            (linear_number_density, LinearNumberDensity),
450            (linear_number_rate, LinearNumberRate),
451            (linear_power_density, LinearPowerDensity),
452            (luminance, Luminance),
453            (luminous_intensity, LuminousIntensity),
454            (magnetic_field_strength, MagneticFieldStrength),
455            (magnetic_flux, MagneticFlux),
456            (magnetic_flux_density, MagneticFluxDensity),
457            (magnetic_moment, MagneticMoment),
458            (magnetic_permeability, MagneticPermeability),
459            (mass, Mass),
460            (mass_concentration, MassConcentration),
461            (mass_density, MassDensity),
462            (mass_flux, MassFlux),
463            (mass_per_energy, MassPerEnergy),
464            (mass_rate, MassRate),
465            (molality, Molality),
466            (molar_concentration, MolarConcentration),
467            (molar_energy, MolarEnergy),
468            (molar_flux, MolarFlux),
469            (molar_heat_capacity, MolarHeatCapacity),
470            (molar_mass, MolarMass),
471            (molar_radioactivity, MolarRadioactivity),
472            (molar_volume, MolarVolume),
473            (moment_of_inertia, MomentOfInertia),
474            (momentum, Momentum),
475            (power, Power),
476            (power_rate, PowerRate),
477            (pressure, Pressure),
478            (radiant_exposure, RadiantExposure),
479            (radioactivity, Radioactivity),
480            (ratio, Ratio),
481            (reciprocal_length, ReciprocalLength),
482            (solid_angle, SolidAngle),
483            (specific_area, SpecificArea),
484            (specific_heat_capacity, SpecificHeatCapacity),
485            (specific_power, SpecificPower),
486            (specific_radioactivity, SpecificRadioactivity),
487            (specific_volume, SpecificVolume),
488            (surface_electric_current_density, SurfaceElectricCurrentDensity),
489            (surface_tension, SurfaceTension),
490            (temperature_coefficient, TemperatureCoefficient),
491            (temperature_gradient, TemperatureGradient),
492            (temperature_interval, TemperatureInterval),
493            (thermal_conductance, ThermalConductance),
494            (thermal_conductivity, ThermalConductivity),
495            (thermal_resistance, ThermalResistance),
496            (thermodynamic_temperature, ThermodynamicTemperature),
497            (time, Time),
498            (torque, Torque),
499            (velocity, Velocity),
500            (volume, Volume),
501            (volume_rate, VolumeRate),
502            (volumetric_density_of_states, VolumetricDensityOfStates),
503            (volumetric_heat_capacity, VolumetricHeatCapacity),
504            (volumetric_number_density, VolumetricNumberDensity),
505            (volumetric_number_rate, VolumetricNumberRate),
506            (volumetric_power_density, VolumetricPowerDensity),
507        ]
508    }
509}
510
511#[cfg(all(test, feature = "reflect"))]
512mod tests {
513    use super::si::f32::Velocity;
514    use super::si::velocity::{kilometer_per_hour, meter_per_second};
515    use bevy_reflect::{PartialReflect, Reflect, ReflectRef};
516
517    #[derive(Reflect)]
518    #[reflect(from_reflect = false)]
519    struct Msg {
520        speed: Velocity,
521    }
522
523    #[test]
524    fn reflect_velocity_as_opaque_base_value() {
525        let msg = Msg {
526            speed: Velocity::new::<kilometer_per_hour>(36.0),
527        };
528
529        assert!(matches!(
530            msg.speed.as_partial_reflect().reflect_ref(),
531            ReflectRef::Opaque(_)
532        ));
533        assert_eq!(msg.speed.get::<meter_per_second>(), 10.0);
534
535        let speed_reflected = match msg.as_partial_reflect().reflect_ref() {
536            ReflectRef::Struct(s) => s.field("speed").expect("speed field should exist"),
537            _ => panic!("expected struct reflection"),
538        };
539
540        let speed = speed_reflected
541            .try_downcast_ref::<Velocity>()
542            .expect("speed should downcast to cu29_units::si::f32::Velocity");
543        assert_eq!(speed.raw(), 10.0);
544        assert_eq!(speed.get::<meter_per_second>(), 10.0);
545    }
546}