From a4e3936aeac6c8a6ecc54ea6a28d2b9943e53770 Mon Sep 17 00:00:00 2001 From: Loup Federico <16464925+Sh099078@users.noreply.github.com> Date: Mon, 17 Nov 2025 14:34:37 +0100 Subject: [PATCH 1/5] editoast: uom: define a custom system of units for Editoast - It has the same base units as the International System of Units (ISQ) but different default measurement units (ex: meter -> centimeter). This will allow us to use u64 as the storage type for the different quantities without any precision loss. For more information on the subject, check the [design paragraph in the uom official documentation](https://docs.rs/uom/latest/uom/#design) explaining the issue faced when using the ISQ (based on meters) to store smaller values (millimeters in our case) in integers. - It allows us to own the quantity types of the units system and implement any trait we want on them directly without bumping into the orphan rule. - The available measurements are drastically reduced for maintenability purposes: only the ones that are used in Editoast have been kept in the new system. Signed-off-by: Loup Federico <16464925+Sh099078@users.noreply.github.com> --- editoast/common/src/lib.rs | 4 ++ editoast/common/src/unit_system.rs | 52 +++++++++++++++++++++++ editoast/common/src/unit_system/length.rs | 15 +++++++ editoast/common/src/unit_system/mass.rs | 15 +++++++ editoast/common/src/unit_system/time.rs | 15 +++++++ editoast/src/views/timetable.rs | 2 +- 6 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 editoast/common/src/unit_system.rs create mode 100644 editoast/common/src/unit_system/length.rs create mode 100644 editoast/common/src/unit_system/mass.rs create mode 100644 editoast/common/src/unit_system/time.rs diff --git a/editoast/common/src/lib.rs b/editoast/common/src/lib.rs index 106ff7f0280..318e5377beb 100644 --- a/editoast/common/src/lib.rs +++ b/editoast/common/src/lib.rs @@ -1,7 +1,11 @@ +#[macro_use] +extern crate uom; + pub mod geometry; mod hash_rounded_float; pub mod rangemap_utils; pub mod tracing; +pub mod unit_system; pub mod units; use std::collections::HashSet; diff --git a/editoast/common/src/unit_system.rs b/editoast/common/src/unit_system.rs new file mode 100644 index 00000000000..06701613f25 --- /dev/null +++ b/editoast/common/src/unit_system.rs @@ -0,0 +1,52 @@ +//! Editoast System of Quantities (ESQ). Subset of the International System of Quantities (ISQ) +//! that, for now, uses the same base units (meter, kilogram, second) and only defines the +//! quantities used in Editoast. It will later allow us to change the base units in order to +//! represent any quantity that we might treat using integers instead of floats. + +// There are other base quantities defined in the ISQ, such as electric current, luminous +// intensity, thermodynamic temperature and amount of substance, but we don’t need them. +// Future quantities might need them and we will need to expand ESQ with them as required. +pub mod length; +pub mod mass; +pub mod time; + +system! { + /// [Editoast System of Quantities](https://jcgm.bipm.org/vim/en/1.6.html) (ESQ). + /// + /// It only defines a subset of the quantities of the International System of Quantities + /// (ISQ) provided by uom. + /// + /// ## Generic Parameters + /// * `L`: Length dimension. + /// * `M`: Mass dimension. + /// * `T`: Time dimension. + quantities: ESQ { + /// Length, one of the base quantities in the ESQ, denoted by the symbol L. The base unit + /// for length is meter. + length: meter, L; + /// Mass, one of the base quantities in the ESQ, denoted by the symbol M. The base unit + /// for mass is kilogram. + mass: kilogram, M; + /// Time, one of the base quantities in the ESQ, denoted by the symbol T. The base unit + /// for time is the second. + time: second, T; + } + units: U { + mod length::Length, + mod mass::Mass, + mod time::Time, + } +} + +pub mod quantities { + ESQ!(self::super, f64); +} + +pub fn quantity_eq(a: &Quantity, b: &Quantity) -> bool +where + D: Dimension + ?Sized, + U: Units + ?Sized, + V: uom::num_traits::Num + uom::num_traits::float::TotalOrder + uom::Conversion, +{ + crate::float_eq(&a.value, &b.value) +} diff --git a/editoast/common/src/unit_system/length.rs b/editoast/common/src/unit_system/length.rs new file mode 100644 index 00000000000..f79fb8a3126 --- /dev/null +++ b/editoast/common/src/unit_system/length.rs @@ -0,0 +1,15 @@ +//! Length (base unit meter, m). +quantity! { + /// Length (base unit meter, m). + quantity: Length; "length"; + /// Dimension of length, L (base unit meter, m). + dimension: ESQ< + P1, // length + Z0, // mass + Z0>; // time + + units { + @meter: 1.0; "m", "meter", "meters"; + @millimeter: 1.0E-3; "mm", "millimeter", "millimeters"; + } +} diff --git a/editoast/common/src/unit_system/mass.rs b/editoast/common/src/unit_system/mass.rs new file mode 100644 index 00000000000..12d83754e71 --- /dev/null +++ b/editoast/common/src/unit_system/mass.rs @@ -0,0 +1,15 @@ +//! Mass (base unit kilogram, kg). +quantity! { + /// Mass (base unit kilogram, kg). + quantity: Mass; "mass"; + /// Dimension of mass, M (base unit kilogram, kg). + dimension: ESQ< + Z0, // length + P1, // mass + Z0>; // time + + units { + @ton: 1.0E3; "t", "ton", "tons"; + @kilogram: 1.0; "kg", "kilogram", "kilograms"; + } +} diff --git a/editoast/common/src/unit_system/time.rs b/editoast/common/src/unit_system/time.rs new file mode 100644 index 00000000000..f8df906dde4 --- /dev/null +++ b/editoast/common/src/unit_system/time.rs @@ -0,0 +1,15 @@ +//! Time (base unit second, s). +quantity! { + /// Time (base unit second, s). + quantity: Time; "time"; + /// Dimension of time, T (base unit second, s). + dimension: ESQ< + Z0, // length + Z0, // mass + P1>; // time + + units { + @second: 1.0; "s", "second", "seconds"; + @millisecond: 1.0E-3; "ms", "millisecond", "milliseconds"; + } +} diff --git a/editoast/src/views/timetable.rs b/editoast/src/views/timetable.rs index 6445bf13483..571aecb7a7b 100644 --- a/editoast/src/views/timetable.rs +++ b/editoast/src/views/timetable.rs @@ -744,7 +744,7 @@ impl PhysicsConsistParameters { let traction_engine_inertia = self.traction_engine.mass * self.traction_engine.inertia_coefficient; let towed_inertia = towed_mass * towed_rolling_stock.inertia_coefficient; - ((traction_engine_inertia + towed_inertia) / total_mass).into() + ((traction_engine_inertia + towed_inertia) / total_mass).value } else { self.traction_engine.inertia_coefficient } From 8f45e0e0ae9aa199ea1d79ea57cdf8e5917e8c1f Mon Sep 17 00:00:00 2001 From: Loup Federico <16464925+Sh099078@users.noreply.github.com> Date: Mon, 17 Nov 2025 15:43:28 +0100 Subject: [PATCH 2/5] editoast: uom: extend the ESQ with the composed units used in Editoast Add to the Editoast System of Quantities (ESQ) the different composed units that are used in osrd. - These units are named in a similar fashion as they are in the International System of Quantities. - Keep the existing type aliases made to the SI units when they are known / used under a different name in the context of OSRD (example: the type alias `SolidFriction` for `Force`). - Only keep the measurements used in OSRD. Signed-off-by: Loup Federico <16464925+Sh099078@users.noreply.github.com> --- editoast/common/src/unit_system.rs | 25 +++++++++++++++++++ .../common/src/unit_system/acceleration.rs | 19 ++++++++++++++ editoast/common/src/unit_system/force.rs | 20 +++++++++++++++ editoast/common/src/unit_system/frequency.rs | 19 ++++++++++++++ .../src/unit_system/linear_mass_density.rs | 19 ++++++++++++++ .../src/unit_system/linear_number_density.rs | 18 +++++++++++++ editoast/common/src/unit_system/mass_rate.rs | 19 ++++++++++++++ editoast/common/src/unit_system/velocity.rs | 15 +++++++++++ editoast/common/src/units.rs | 17 +++++++++++++ 9 files changed, 171 insertions(+) create mode 100644 editoast/common/src/unit_system/acceleration.rs create mode 100644 editoast/common/src/unit_system/force.rs create mode 100644 editoast/common/src/unit_system/frequency.rs create mode 100644 editoast/common/src/unit_system/linear_mass_density.rs create mode 100644 editoast/common/src/unit_system/linear_number_density.rs create mode 100644 editoast/common/src/unit_system/mass_rate.rs create mode 100644 editoast/common/src/unit_system/velocity.rs diff --git a/editoast/common/src/unit_system.rs b/editoast/common/src/unit_system.rs index 06701613f25..87fcc5c6ea9 100644 --- a/editoast/common/src/unit_system.rs +++ b/editoast/common/src/unit_system.rs @@ -6,9 +6,16 @@ // There are other base quantities defined in the ISQ, such as electric current, luminous // intensity, thermodynamic temperature and amount of substance, but we don’t need them. // Future quantities might need them and we will need to expand ESQ with them as required. +pub mod acceleration; +pub mod force; +pub mod frequency; pub mod length; +pub mod linear_mass_density; +pub mod linear_number_density; pub mod mass; +pub mod mass_rate; pub mod time; +pub mod velocity; system! { /// [Editoast System of Quantities](https://jcgm.bipm.org/vim/en/1.6.html) (ESQ). @@ -32,14 +39,32 @@ system! { time: second, T; } units: U { + // Base units mod length::Length, mod mass::Mass, mod time::Time, + // Composed units + mod velocity::Velocity, + mod acceleration::Acceleration, + mod force::Force, + mod mass_rate::MassRate, + mod frequency::Frequency, + mod linear_mass_density::LinearMassDensity, + mod linear_number_density::LinearNumberDensity, } } pub mod quantities { ESQ!(self::super, f64); + // Editoast aliases for existing units + pub type Offset = Time; + pub type SolidFriction = Force; + pub type SolidFrictionPerWeight = Acceleration; + pub type Deceleration = Acceleration; + pub type ViscosityFriction = MassRate; + pub type ViscosityFrictionPerWeight = Frequency; + pub type AerodynamicDrag = LinearMassDensity; + pub type AerodynamicDragPerWeight = LinearNumberDensity; } pub fn quantity_eq(a: &Quantity, b: &Quantity) -> bool diff --git a/editoast/common/src/unit_system/acceleration.rs b/editoast/common/src/unit_system/acceleration.rs new file mode 100644 index 00000000000..40aef4495d1 --- /dev/null +++ b/editoast/common/src/unit_system/acceleration.rs @@ -0,0 +1,19 @@ +//! Acceleration (base unit meter per second squared, m · s⁻²). +//! +//! It has the same dimension as solid friction per weight. +//! A typical value is 0.05 m/s² for acceleration and 1 daN/t for solid friction per weight. +quantity! { + /// Acceleration (base unit meter per second squared, m · s⁻²). + quantity: Acceleration; "acceleration"; + /// Dimension of acceleration, LT⁻² (base unit meter per second squared, m · s⁻²). + dimension: ESQ< + P1, // length + Z0, // mass + N2>; // time + + units { + @meter_per_second_squared: 1.0; "m·s⁻²", "meter per second squared", "meters per second squared"; + @newton_per_kg: 1.0; "N·kg⁻¹", "newton per kilogram", "newtons per kilogram"; + @newton_per_ton: 1.0E-3; "N·t⁻¹", "newton per ton", "newtons per ton"; + } +} diff --git a/editoast/common/src/unit_system/force.rs b/editoast/common/src/unit_system/force.rs new file mode 100644 index 00000000000..b0e1cf0d4af --- /dev/null +++ b/editoast/common/src/unit_system/force.rs @@ -0,0 +1,20 @@ +//! Force (base unit newton, kg · m · s⁻²). +//! +//! It represents the traction force of a train. +//! It has the same dimensions as solid friction (resistance to movement) also known as coefficient A. +//! A typical value is 100 kN. +quantity! { + /// Force (base unit newton, kg · m · s⁻²). + quantity: Force; "force"; + /// Dimension of force, LMT⁻² (base unit newton, kg · m · s⁻²). + dimension: ESQ< + P1, // length + P1, // mass + N2>; // time + + units { + /// Derived unit of force. + @newton: 1.0; "N", "newton", "newtons"; + @kilonewton: 1.0E3; "kN", "kilonewton", "kilonewtons"; + } +} diff --git a/editoast/common/src/unit_system/frequency.rs b/editoast/common/src/unit_system/frequency.rs new file mode 100644 index 00000000000..a5ea9364db6 --- /dev/null +++ b/editoast/common/src/unit_system/frequency.rs @@ -0,0 +1,19 @@ +//! Frequency (base unit hertz, s⁻¹). +//! +//! It has the same dimension as viscosity friction per weight. +//! A typical value is 0.01 daN/km/h/t or 100 mN/km/h/t. +quantity! { + /// Frequency (base unit hertz, s⁻¹). + quantity: Frequency; "frequency"; + /// Dimension of frequency, T⁻¹ (base unit hertz, s⁻¹). + dimension: ESQ< + Z0, // length + Z0, // mass + N1>; // time + + units { + /// The hertz is one cycle per second. + @hertz: 1.0; "Hz", "hertz", "hertz"; + @newton_per_meter_per_second_per_kilogram: 1.0; "N·(m/s)⁻¹·kg⁻¹", "newton per meter per second per kilogram", "newtons per meter per second per kilogram"; + } +} diff --git a/editoast/common/src/unit_system/linear_mass_density.rs b/editoast/common/src/unit_system/linear_mass_density.rs new file mode 100644 index 00000000000..2bd604cb1fd --- /dev/null +++ b/editoast/common/src/unit_system/linear_mass_density.rs @@ -0,0 +1,19 @@ +//! Linear mass density (base unit kilogram per meter, kg·m⁻¹). +//! +//! It has the same dimension as aerodynamic drag, also known as coefficient C. +//! A typical value is 0.036 daN/(km/h)². +quantity! { + /// Linear mass density (base unit kilogram per meter, kg·m⁻¹). + quantity: LinearMassDensity; "linear mass density"; + /// Dimension of linear mass density, L⁻¹M (base unit kilogram per meter, kg·m⁻¹). + dimension: ESQ< + N1, // length + P1, // mass + Z0>; // time + + units { + @kilogram_per_meter: 1.0; "kg·m⁻¹", "kilogram per meter", "kilograms per meter"; + @newton_per_meter_per_second_squared: 1.0; "N·(m/s)⁻²", "newton per meter per second squared", "newtons per meter per second squared"; + @kilonewton_per_kilometer_per_hour_squared: 12960.0; "kN·(km/h)⁻²", "kilonewton per kilometer per hour squared", "kilonewtons per kilometer per hour squared"; + } +} diff --git a/editoast/common/src/unit_system/linear_number_density.rs b/editoast/common/src/unit_system/linear_number_density.rs new file mode 100644 index 00000000000..3eb3d918a06 --- /dev/null +++ b/editoast/common/src/unit_system/linear_number_density.rs @@ -0,0 +1,18 @@ +//! Linear number density (base unit 1 per meter, m⁻¹). +//! +//! It has the same dimension as aerodynamic drag per weight. +//! A typical value is 0.1 N/(km/h)²/t. +quantity! { + /// Linear number density (base unit 1 per meter, m⁻¹). + quantity: LinearNumberDensity; "linear number density"; + /// Dimension of linear number density, L⁻¹ (base unit per meter, m⁻¹). + dimension: ESQ< + N1, // length + Z0, // mass + Z0>; // time + + units { + @per_meter: 1.0; "m⁻¹", "per meter", "per meter"; + @newton_per_meter_per_second_squared_per_kilogram: 1.0; "N·(m/s)⁻²·kg⁻¹", "newton per meter per second squared per kilogram", "newtons per meter per second squared per kilogram"; + } +} diff --git a/editoast/common/src/unit_system/mass_rate.rs b/editoast/common/src/unit_system/mass_rate.rs new file mode 100644 index 00000000000..c0a881ccb77 --- /dev/null +++ b/editoast/common/src/unit_system/mass_rate.rs @@ -0,0 +1,19 @@ +//! Mass rate (base unit kilogram per second, kg · s⁻¹). +//! +//! It has the same dimension as viscosity friction. +//! A typical value is 1.6 daN/(km/h), or 5.76 daN/(m/s). +quantity! { + /// Mass rate (base unit kilogram per second, kg · s⁻¹). + quantity: MassRate; "mass rate"; + /// Dimension of mass rate, MT⁻¹ (base unit kilogram per second, kg · s⁻¹). + dimension: ESQ< + Z0, // length + P1, // mass + N1>; // time + + units { + @kilogram_per_second: 1.0; "kg·s⁻¹", "kilogram per second", "kilograms per second"; + @newton_per_meter_per_second: 1.0; "N·(m/s)⁻¹", "newton per meter per second", "newtons per meter per second"; + @newton_per_kilometer_per_hour: 3.6; "N·(km/h)⁻¹", "newton per kilometer per hour", "newtons per kilometer per hour"; + } +} diff --git a/editoast/common/src/unit_system/velocity.rs b/editoast/common/src/unit_system/velocity.rs new file mode 100644 index 00000000000..6bb67cf79d5 --- /dev/null +++ b/editoast/common/src/unit_system/velocity.rs @@ -0,0 +1,15 @@ +//! Velocity (base unit meter per second, m · s⁻¹). +quantity! { + /// Velocity (base unit meter per second, m · s⁻¹). + quantity: Velocity; "velocity"; + /// Dimension of velocity, LT⁻¹ (base unit meter per second, m · s⁻¹). + dimension: ESQ< + P1, // length + Z0, // mass + N1>; // time + + units { + @kilometer_per_hour: 1000.0 / 3600.0; "km·h⁻¹", "kilometer per hour", "kilometers per hour"; + @meter_per_second: 1.0; "m·s⁻¹", "meter per second", "meters per second"; + } +} diff --git a/editoast/common/src/units.rs b/editoast/common/src/units.rs index 19e88567069..4601a8b6f4f 100644 --- a/editoast/common/src/units.rs +++ b/editoast/common/src/units.rs @@ -286,12 +286,29 @@ use quantities::*; define_unit!(meter, Length); define_unit!(millimeter, Length); define_unit!(meter_per_second, Velocity); +define_unit!(kilometer_per_hour, Velocity); define_unit!(meter_per_second_squared, Acceleration); +define_unit!(newton_per_kg, Acceleration); +define_unit!(newton_per_ton, Acceleration); define_unit!(kilogram, Mass); +define_unit!(ton, Mass); define_unit!(newton, SolidFriction); +define_unit!(kilonewton, SolidFriction); define_unit!(kilogram_per_second, ViscosityFriction); +define_unit!(newton_per_meter_per_second, ViscosityFriction); +define_unit!(newton_per_kilometer_per_hour, ViscosityFriction); define_unit!(hertz, ViscosityFrictionPerWeight); +define_unit!( + newton_per_meter_per_second_per_kilogram, + ViscosityFrictionPerWeight +); define_unit!(kilogram_per_meter, AerodynamicDrag); +define_unit!(newton_per_meter_per_second_squared, AerodynamicDrag); +define_unit!(kilonewton_per_kilometer_per_hour_squared, AerodynamicDrag); define_unit!(per_meter, AerodynamicDragPerWeight); +define_unit!( + newton_per_meter_per_second_squared_per_kilogram, + AerodynamicDragPerWeight +); define_unit!(second, Time); define_unit!(millisecond, Time); From d59f77f6ce724b390e722d8ace5d16f7555bd232 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tristram=20Gr=C3=A4bener?= Date: Wed, 26 Nov 2025 14:06:45 +0100 Subject: [PATCH 3/5] editoast: units: use our own system MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This results in a measurable compilation time - before 165 seconds - after 150 seconds as we no longer have uom’s whole SI This will also later on to adapt the base values for each quantity in order to store them as integers. Signed-off-by: Tristram Gräbener --- editoast/Cargo.toml | 2 +- editoast/common/src/units.rs | 108 ++++++----------- .../core_client/src/conflict_detection.rs | 2 +- editoast/core_client/src/simulation.rs | 12 +- .../core_task/src/envs/simulation/inputs.rs | 6 +- .../core_task/src/envs/simulation/request.rs | 2 +- .../editoast_derive/src/annotate_units.rs | 17 ++- editoast/models/src/rolling_stock.rs | 12 +- editoast/models/src/timetable.rs | 2 +- editoast/models/src/towed_rolling_stock.rs | 10 +- editoast/models/src/train_schedule.rs | 4 +- editoast/schemas/src/fixtures.rs | 3 +- editoast/schemas/src/paced_train.rs | 2 +- .../schemas/src/primitives/time_window.rs | 2 +- editoast/schemas/src/rolling_stock.rs | 14 +-- .../src/rolling_stock/rolling_resistance.rs | 12 +- .../src/rolling_stock/towed_rolling_stock.rs | 10 +- editoast/schemas/src/train_schedule.rs | 2 +- .../src/client/stdcm_search_env_commands.rs | 2 +- .../src/views/level_crossing_occupancy.rs | 2 +- editoast/src/views/rolling_stock/light.rs | 6 +- editoast/src/views/timetable.rs | 10 +- editoast/src/views/timetable/conflicts.rs | 4 +- editoast/src/views/timetable/simulation.rs | 7 +- editoast/src/views/timetable/stdcm.rs | 111 ++++++++---------- editoast/src/views/timetable/stdcm/request.rs | 12 +- 26 files changed, 176 insertions(+), 200 deletions(-) diff --git a/editoast/Cargo.toml b/editoast/Cargo.toml index b1121598490..00e97116cae 100644 --- a/editoast/Cargo.toml +++ b/editoast/Cargo.toml @@ -150,7 +150,7 @@ tracing-opentelemetry = { version = "0.33.0", default-features = false, features "tracing-log", ] } tracing-subscriber = { version = "0.3.23", features = ["env-filter"] } -uom = { version = "0.38.0", default-features = false, features = ["f64", "si"] } +uom = { version = "0.38.0", default-features = false, features = ["f64"] } url = { version = "2.5.8", features = ["serde"] } urlencoding = "2.1.3" utoipa = { git = "https://github.com/osrd-project/utoipa.git", rev = "5103a24a6d6", features = [ diff --git a/editoast/common/src/units.rs b/editoast/common/src/units.rs index 4601a8b6f4f..0a850fd55c9 100644 --- a/editoast/common/src/units.rs +++ b/editoast/common/src/units.rs @@ -34,107 +34,78 @@ //! } //! ``` -/// Re-export the Quantities that are used in OSRD -pub mod quantities { - pub use uom::si::f64::Acceleration; - pub use uom::si::f64::Length; - pub use uom::si::f64::Mass; - pub use uom::si::f64::Time; - pub use uom::si::f64::Velocity; - pub type SolidFriction = uom::si::f64::Force; - pub type SolidFrictionPerWeight = uom::si::f64::Acceleration; - pub type ViscosityFriction = uom::si::f64::MassRate; - pub type ViscosityFrictionPerWeight = uom::si::f64::Frequency; - pub type AerodynamicDrag = uom::si::f64::LinearMassDensity; - pub type AerodynamicDragPerWeight = uom::si::f64::LinearNumberDensity; - pub type Deceleration = uom::si::f64::Acceleration; - pub type Offset = uom::si::f64::Time; - - pub fn quantity_eq( - a: &uom::si::Quantity, - b: &uom::si::Quantity, - ) -> bool - where - D: uom::si::Dimension + ?Sized, - U: uom::si::Units + ?Sized, - V: uom::num_traits::Num + uom::num_traits::float::TotalOrder + uom::Conversion, - { - crate::float_eq(&a.value, &b.value) - } -} - macro_rules! quantity_to_path { (Length, $unit:ident) => { - uom::si::length::$unit + crate::unit_system::length::$unit }; (Velocity, $unit:ident) => { - uom::si::velocity::$unit + crate::unit_system::velocity::$unit }; (Acceleration, $unit:ident) => { - uom::si::acceleration::$unit + crate::unit_system::acceleration::$unit }; (Mass, $unit:ident) => { - uom::si::mass::$unit + crate::unit_system::mass::$unit }; (SolidFriction, $unit:ident) => { - uom::si::force::$unit + crate::unit_system::force::$unit }; (ViscosityFriction, $unit:ident) => { - uom::si::mass_rate::$unit + crate::unit_system::mass_rate::$unit }; (ViscosityFrictionPerWeight, $unit:ident) => { - uom::si::frequency::$unit + crate::unit_system::frequency::$unit }; (AerodynamicDrag, $unit:ident) => { - uom::si::linear_mass_density::$unit + crate::unit_system::linear_mass_density::$unit }; (AerodynamicDragPerWeight, $unit:ident) => { - uom::si::linear_number_density::$unit + crate::unit_system::linear_number_density::$unit }; (Time, $unit:ident) => { - uom::si::time::$unit + crate::unit_system::time::$unit }; } macro_rules! define_unit { ($unit:ident, $quantity:ident) => { pub mod $unit { - use super::*; use serde::Deserialize; use serde::Deserializer; use serde::Serialize; use serde::Serializer; + pub type Quantity = crate::unit_system::quantities::$quantity; type Unit = quantity_to_path!($quantity, $unit); pub type ReprType = f64; - pub fn serialize(value: &$quantity, serializer: S) -> Result + pub fn serialize(value: &Quantity, serializer: S) -> Result where S: Serializer, { value.get::().serialize(serializer) } - pub fn deserialize<'de, D>(deserializer: D) -> Result<$quantity, D::Error> + pub fn deserialize<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { let value = ReprType::deserialize(deserializer)?; - Ok($quantity::new::(value)) + Ok(Quantity::new::(value)) } - pub fn new(value: ReprType) -> $quantity { - $quantity::new::(value) + pub fn new(value: ReprType) -> Quantity { + Quantity::new::(value) } - pub fn from(qty: $quantity) -> ReprType { + pub fn from(qty: Quantity) -> ReprType { qty.get::() } - pub fn hash(value: &$quantity, state: &mut H) { + pub fn hash(value: &Quantity, state: &mut H) { crate::hash_float::<5, H>(&from(*value), state); } - pub fn eq(a: &$quantity, b: &$quantity) -> bool { + pub fn eq(a: &Quantity, b: &Quantity) -> bool { $crate::float_eq(&a.get::(), &b.get::()) } @@ -143,7 +114,7 @@ macro_rules! define_unit { pub type ReprType = Option; pub fn serialize( - value: &Option<$quantity>, + value: &Option, serializer: S, ) -> Result where @@ -152,27 +123,27 @@ macro_rules! define_unit { value.map(|value| value.get::()).serialize(serializer) } - pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { let value = Option::deserialize(deserializer)?; - Ok(value.map(|value| $quantity::new::(value))) + Ok(value.map(|value| Quantity::new::(value))) } - pub fn new(value: ReprType) -> Option<$quantity> { - value.map(|v| $quantity::new::(v)) + pub fn new(value: ReprType) -> Option { + value.map(|v| Quantity::new::(v)) } - pub fn from(qty: Option<$quantity>) -> ReprType { + pub fn from(qty: Option) -> ReprType { qty.map(|q| q.get::()) } - pub fn hash(value: &Option<$quantity>, state: &mut H) { + pub fn hash(value: &Option, state: &mut H) { super::hash(&value.unwrap_or_default(), state); } - pub fn eq(a: &Option<$quantity>, b: &Option<$quantity>) -> bool { + pub fn eq(a: &Option, b: &Option) -> bool { match (a, b) { (Some(a), Some(b)) => $crate::float_eq(&a.get::(), &b.get::()), (None, None) => true, @@ -184,14 +155,14 @@ macro_rules! define_unit { pub mod u64 { use super::*; - pub fn serialize(value: &$quantity, serializer: S) -> Result + pub fn serialize(value: &Quantity, serializer: S) -> Result where S: Serializer, { (value.get::() as u64).serialize(serializer) } - pub fn deserialize<'de, D>(deserializer: D) -> Result<$quantity, D::Error> + pub fn deserialize<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { @@ -203,7 +174,7 @@ macro_rules! define_unit { pub type ReprType = Option; pub fn serialize( - value: &Option<$quantity>, + value: &Option, serializer: S, ) -> Result where @@ -216,7 +187,7 @@ macro_rules! define_unit { pub fn deserialize<'de, D>( deserializer: D, - ) -> Result, D::Error> + ) -> Result, D::Error> where D: Deserializer<'de>, { @@ -229,25 +200,25 @@ macro_rules! define_unit { use super::*; pub type ReprType = i64; - pub fn serialize(value: &$quantity, serializer: S) -> Result + pub fn serialize(value: &Quantity, serializer: S) -> Result where S: Serializer, { (value.get::() as i64).serialize(serializer) } - pub fn deserialize<'de, D>(deserializer: D) -> Result<$quantity, D::Error> + pub fn deserialize<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { super::deserialize(deserializer) } - pub fn new(value: ReprType) -> $quantity { - $quantity::new::(value as f64) + pub fn new(value: ReprType) -> Quantity { + Quantity::new::(value as f64) } - pub fn from(qty: $quantity) -> ReprType { + pub fn from(qty: Quantity) -> ReprType { qty.get::() as i64 } @@ -256,7 +227,7 @@ macro_rules! define_unit { pub type ReprType = Option; pub fn serialize( - value: &Option<$quantity>, + value: &Option, serializer: S, ) -> Result where @@ -269,7 +240,7 @@ macro_rules! define_unit { pub fn deserialize<'de, D>( deserializer: D, - ) -> Result, D::Error> + ) -> Result, D::Error> where D: Deserializer<'de>, { @@ -282,9 +253,8 @@ macro_rules! define_unit { } // Any new value here must also be added in editoast_derive/src/annotate_units.rs -use quantities::*; -define_unit!(meter, Length); define_unit!(millimeter, Length); +define_unit!(meter, Length); define_unit!(meter_per_second, Velocity); define_unit!(kilometer_per_hour, Velocity); define_unit!(meter_per_second_squared, Acceleration); diff --git a/editoast/core_client/src/conflict_detection.rs b/editoast/core_client/src/conflict_detection.rs index a2fdcc976c1..22d60401b69 100644 --- a/editoast/core_client/src/conflict_detection.rs +++ b/editoast/core_client/src/conflict_detection.rs @@ -1,4 +1,4 @@ -use common::units::quantities::Offset; +use common::unit_system::quantities::Offset; use serde::Deserialize; use serde::Serialize; use std::collections::HashMap; diff --git a/editoast/core_client/src/simulation.rs b/editoast/core_client/src/simulation.rs index bf42bbc88c9..f2282837bc2 100644 --- a/editoast/core_client/src/simulation.rs +++ b/editoast/core_client/src/simulation.rs @@ -2,13 +2,13 @@ use std::collections::BTreeMap; use std::collections::HashMap; use std::hash::Hash; +use common::unit_system::quantities::Acceleration; +use common::unit_system::quantities::Deceleration; +use common::unit_system::quantities::Length; +use common::unit_system::quantities::Mass; +use common::unit_system::quantities::Time; +use common::unit_system::quantities::Velocity; use common::units; -use common::units::quantities::Acceleration; -use common::units::quantities::Deceleration; -use common::units::quantities::Length; -use common::units::quantities::Mass; -use common::units::quantities::Time; -use common::units::quantities::Velocity; use educe::Educe; use schemas::rolling_stock::EffortCurves; use schemas::rolling_stock::EtcsBrakeParams; diff --git a/editoast/core_task/src/envs/simulation/inputs.rs b/editoast/core_task/src/envs/simulation/inputs.rs index cfb7987c786..3047cb5b2f1 100644 --- a/editoast/core_task/src/envs/simulation/inputs.rs +++ b/editoast/core_task/src/envs/simulation/inputs.rs @@ -49,7 +49,7 @@ pub struct SimulationTrainParameters { #[educe(Hash(method(common::units::meter_per_second::hash)))] #[educe(PartialEq(method(common::units::meter_per_second::eq)))] - initial_speed: uom::si::f64::Velocity, + initial_speed: common::unit_system::quantities::Velocity, constraint_distribution: Distribution, comfort: Comfort, speed_limit_tag: Option, @@ -73,7 +73,7 @@ impl ScheduleItem { impl SimulationTrainParameters { pub fn new( - initial_speed: uom::si::f64::Velocity, + initial_speed: common::unit_system::quantities::Velocity, constraint_distribution: Distribution, comfort: Comfort, speed_limit_tag: Option, @@ -103,7 +103,7 @@ impl SimulationTrainParameters { &self.margins } - pub fn initial_speed(&self) -> uom::si::f64::Velocity { + pub fn initial_speed(&self) -> common::unit_system::quantities::Velocity { self.initial_speed } diff --git a/editoast/core_task/src/envs/simulation/request.rs b/editoast/core_task/src/envs/simulation/request.rs index 84bc2f39802..44006a1241d 100644 --- a/editoast/core_task/src/envs/simulation/request.rs +++ b/editoast/core_task/src/envs/simulation/request.rs @@ -116,7 +116,7 @@ pub(super) fn build_request( power_restrictions, initial_speed: params .initial_speed() - .get::(), + .get::(), comfort: params.comfort(), constraint_distribution: params.constraint_distribution(), speed_limit_tag: params.speed_limit_tag().map(|s| s.to_owned()), diff --git a/editoast/editoast_derive/src/annotate_units.rs b/editoast/editoast_derive/src/annotate_units.rs index 20be746d99d..61688624cdd 100644 --- a/editoast/editoast_derive/src/annotate_units.rs +++ b/editoast/editoast_derive/src/annotate_units.rs @@ -34,13 +34,28 @@ fn get_abbreviation(value: &str) -> Option<&'static str> { "meter" => Some("Length in m"), "millimeter" => Some("Length in mm"), "meter_per_second" => Some("Velocity in m·s⁻¹"), + "kilometer_per_hour" => Some("Velocity in km·h⁻¹"), "meter_per_second_squared" => Some("Acceleration in m·s⁻²"), + "newton_per_kg" => Some("Acceleration in N·kg⁻¹"), + "newton_per_ton" => Some("Acceleration in N·t⁻¹"), "kilogram" => Some("Mass in kg"), + "ton" => Some("Mass in t"), "newton" => Some("Solid Friction in N"), + "kilonewton" => Some("Solid Friction in kN"), + "kilogram_per_second" => Some("Viscosity friction in kg·s⁻¹"), + "newton_per_meter_per_second" => Some("Viscosity friction in N·(m/s)⁻¹"), + "newton_per_kilometer_per_hour" => Some("Viscosity friction in N·(km/h)⁻¹"), "hertz" => Some("Viscosity friction per weight in s⁻¹"), + "newton_per_meter_per_second_per_kilogram" => { + Some("Viscosity friction per weight in N·(m/s)⁻¹·kg⁻¹") + } "kilogram_per_meter" => Some("Aerodynamic drag in kg·m⁻¹"), - "kilogram_per_second" => Some("Viscosity friction in kg·s⁻¹"), + "newton_per_meter_per_second_squared" => Some("Aerodynamic drag in N·(m/s)⁻²"), + "kilonewton_per_kilometer_per_hour_squared" => Some("Aerodynamic drag in kN·(km/h)⁻²"), "per_meter" => Some("Aerodynamic drag per kg in m⁻¹"), + "newton_per_meter_per_second_squared_per_kilogram" => { + Some("Aerodynamic drag per kg in N·(m/s)⁻²·kg⁻¹") + } _ => None, } } diff --git a/editoast/models/src/rolling_stock.rs b/editoast/models/src/rolling_stock.rs index 18aa0316167..3bf2028de7e 100644 --- a/editoast/models/src/rolling_stock.rs +++ b/editoast/models/src/rolling_stock.rs @@ -3,13 +3,13 @@ mod power_restrictions; use std::collections::HashMap; use std::collections::HashSet; +use common::unit_system::quantities::Acceleration; +use common::unit_system::quantities::Deceleration; +use common::unit_system::quantities::Length; +use common::unit_system::quantities::Mass; +use common::unit_system::quantities::Time; +use common::unit_system::quantities::Velocity; use common::units; -use common::units::quantities::Acceleration; -use common::units::quantities::Deceleration; -use common::units::quantities::Length; -use common::units::quantities::Mass; -use common::units::quantities::Time; -use common::units::quantities::Velocity; use editoast_derive::Model; use schemas::rolling_stock::EffortCurves; use schemas::rolling_stock::EnergySource; diff --git a/editoast/models/src/timetable.rs b/editoast/models/src/timetable.rs index 0d8d475ba61..e6f9b1c8832 100644 --- a/editoast/models/src/timetable.rs +++ b/editoast/models/src/timetable.rs @@ -1,5 +1,5 @@ +use common::unit_system::quantities::Offset; use common::units::millisecond; -use common::units::quantities::Offset; use database::DatabaseError; use database::tables::sql_types; use diesel::prelude::*; diff --git a/editoast/models/src/towed_rolling_stock.rs b/editoast/models/src/towed_rolling_stock.rs index 5e1692ff193..76b73bfd5e6 100644 --- a/editoast/models/src/towed_rolling_stock.rs +++ b/editoast/models/src/towed_rolling_stock.rs @@ -1,9 +1,9 @@ +use common::unit_system::quantities::Acceleration; +use common::unit_system::quantities::Deceleration; +use common::unit_system::quantities::Length; +use common::unit_system::quantities::Mass; +use common::unit_system::quantities::Velocity; use common::units; -use common::units::quantities::Acceleration; -use common::units::quantities::Deceleration; -use common::units::quantities::Length; -use common::units::quantities::Mass; -use common::units::quantities::Velocity; use editoast_derive::Model; use schemas::rolling_stock::RollingResistancePerWeight; use serde::Deserialize; diff --git a/editoast/models/src/train_schedule.rs b/editoast/models/src/train_schedule.rs index ee611744e5e..5e44e2a92f4 100644 --- a/editoast/models/src/train_schedule.rs +++ b/editoast/models/src/train_schedule.rs @@ -2,8 +2,8 @@ use crate::prelude::*; use crate::rolling_stock::TrainMainCategory; use crate::tags::Tags; use chrono::Duration as ChronoDuration; +use common::unit_system::quantities::Offset; use common::units::millisecond; -use common::units::quantities::Offset; use derive_more::Display; use editoast_derive::Model; use itertools::Itertools as _; @@ -504,7 +504,7 @@ mod tests { use super::OccurrenceId; use super::TrainSchedule; - use common::units::quantities::Offset; + use common::unit_system::quantities::Offset; use database::DbConnectionPoolV2; use pretty_assertions::assert_eq; use rstest::rstest; diff --git a/editoast/schemas/src/fixtures.rs b/editoast/schemas/src/fixtures.rs index c7caaca6bc3..36c07f73848 100644 --- a/editoast/schemas/src/fixtures.rs +++ b/editoast/schemas/src/fixtures.rs @@ -4,6 +4,7 @@ use std::str::FromStr as _; use chrono::DateTime; use chrono::Utc; +use common::unit_system; use common::units; use crate::RollingStock; @@ -95,6 +96,6 @@ pub fn small_infra() -> crate::infra::RailJson { .expect("Unable to parse small infra RailJson") } -pub fn ms_since_epoch(s: &str) -> units::quantities::Time { +pub fn ms_since_epoch(s: &str) -> unit_system::quantities::Time { units::millisecond::i64::new(DateTime::::from_str(s).unwrap().timestamp_millis()) } diff --git a/editoast/schemas/src/paced_train.rs b/editoast/schemas/src/paced_train.rs index 4f02fc57cf7..6c602453ada 100644 --- a/editoast/schemas/src/paced_train.rs +++ b/editoast/schemas/src/paced_train.rs @@ -11,7 +11,7 @@ use crate::train_schedule::ScheduleItem; use crate::train_schedule::TrainOccurrence; use crate::train_schedule::TrainScheduleOptions; use chrono::Duration; -use common::units::quantities::Offset; +use common::unit_system::quantities::Offset; use serde::Deserialize; use serde::Deserializer; use serde::Serialize; diff --git a/editoast/schemas/src/primitives/time_window.rs b/editoast/schemas/src/primitives/time_window.rs index 19b0c12312d..9fe20289d70 100644 --- a/editoast/schemas/src/primitives/time_window.rs +++ b/editoast/schemas/src/primitives/time_window.rs @@ -1,5 +1,5 @@ use super::PositiveDuration; -use common::units::quantities::Offset; +use common::unit_system::quantities::Offset; use serde::Deserialize; use serde::Serialize; use utoipa::ToSchema; diff --git a/editoast/schemas/src/rolling_stock.rs b/editoast/schemas/src/rolling_stock.rs index f4beabb7c71..18bb1685246 100644 --- a/editoast/schemas/src/rolling_stock.rs +++ b/editoast/schemas/src/rolling_stock.rs @@ -48,13 +48,13 @@ pub use sub_category::SubCategoryColor; mod train_category; pub use train_category::TrainCategory; +use common::unit_system::quantities::Acceleration; +use common::unit_system::quantities::Deceleration; +use common::unit_system::quantities::Length; +use common::unit_system::quantities::Mass; +use common::unit_system::quantities::Time; +use common::unit_system::quantities::Velocity; use common::units; -use common::units::quantities::Acceleration; -use common::units::quantities::Deceleration; -use common::units::quantities::Length; -use common::units::quantities::Mass; -use common::units::quantities::Time; -use common::units::quantities::Velocity; use itertools::Itertools as _; use serde::Deserialize; use serde::Deserializer; @@ -194,7 +194,7 @@ impl From> for RollingStock() as u64; + .get::() as u64; let final_spacing_requirements = spacing_requirements .into_iter() diff --git a/editoast/src/views/timetable/simulation.rs b/editoast/src/views/timetable/simulation.rs index af9241c4790..9e751cbb516 100644 --- a/editoast/src/views/timetable/simulation.rs +++ b/editoast/src/views/timetable/simulation.rs @@ -40,7 +40,6 @@ use std::iter; use std::sync::Arc; use tracing::Instrument as _; use tracing::info; -use uom::si::f64::Velocity; use utoipa::ToSchema; use crate::error::InternalError; @@ -652,11 +651,11 @@ pub fn build_pathfinding_consist( maximum_speed: OrderedFloat( physics_consist_parameters .compute_max_speed() - .get::(), + .get::(), ), length: physics_consist_parameters .compute_length() - .get::() + .get::() .round() as u64, speed_limit_tag, } @@ -692,7 +691,7 @@ pub fn build_simulation_train( let simulation_consist = SimulationConsist(PhysicsConsist::from(physics_consist_parameters.clone())); let simulation_train_parameters = SimulationTrainParameters::new( - Velocity::new::(*initial_speed), + common::units::meter_per_second::new(*initial_speed), *constraint_distribution, *comfort, speed_limit_tag diff --git a/editoast/src/views/timetable/stdcm.rs b/editoast/src/views/timetable/stdcm.rs index 9f848c7773c..ef5201518eb 100644 --- a/editoast/src/views/timetable/stdcm.rs +++ b/editoast/src/views/timetable/stdcm.rs @@ -735,6 +735,7 @@ mod tests { use axum::http::StatusCode; use chrono::DateTime; use common::units; + use common::units::*; use core_client; use core_client::mocking::MockingClient; use core_client::pathfinding::TrainPath; @@ -751,16 +752,6 @@ mod tests { use schemas::train_schedule::OperationalPointReference; use schemas::train_schedule::PathItemLocation; use std::str::FromStr as _; - use uom::si::SI; - use uom::si::acceleration::meter_per_second_squared; - use uom::si::length::Length; - use uom::si::length::meter; - use uom::si::length::millimeter; - use uom::si::mass::Mass; - use uom::si::mass::kilogram; - use uom::si::velocity::Velocity; - use uom::si::velocity::kilometer_per_hour; - use uom::si::velocity::meter_per_second; use uuid::Uuid; use crate::error::InternalError; @@ -856,9 +847,9 @@ mod tests { request::ConsistConfiguration { rolling_stock_id, towed_rolling_stock_id, - total_mass: total_mass.map(Mass::new::), - total_length: total_length.map(Length::new::), - max_speed: max_speed.map(Velocity::new::), + total_mass: total_mass.map(kilogram::new), + total_length: total_length.map(meter::new), + max_speed: max_speed.map(kilometer_per_hour::new), speed_limit_tag: Some("AR120".to_string()), loading_gauge_type, } @@ -1186,28 +1177,28 @@ mod tests { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn stdcm_return_success() { - let mass = Mass::, f64>::new::(1000000.0); - let length = Length::, f64>::new::(400.0); - let maximum_speed = Velocity::, f64>::new::(30.0); + let mass = kilogram::new(1000000.0); + let length = meter::new(400.0); + let maximum_speed = kilometer_per_hour::new(30.0); let core = { let mut core = MockingClient::new(); core.stub("/pathfinding/blocks") .on_body("/rolling_stock_loading_gauge", "GLOTT") .on_body( "/rolling_stock_maximum_speed", - maximum_speed.get::(), + meter_per_second::from(maximum_speed), ) - .on_body("/rolling_stock_length", length.get::() as u64) + .on_body("/rolling_stock_length", millimeter::from(length) as u64) .response(StatusCode::OK) .json(PathfindingResult::Success(pathfinding_result_success())) .finish(); core.stub("/standalone_simulation") - .on_body("/physics_consist/length", length.get::() as u64) + .on_body("/physics_consist/length", millimeter::from(length) as u64) .on_body( "/physics_consist/max_speed", - maximum_speed.get::(), + meter_per_second::from(maximum_speed), ) - .on_body("/physics_consist/mass", mass.get::() as u64) + .on_body("/physics_consist/mass", kilogram::from(mass) as u64) .response(StatusCode::OK) .json(simulation_empty_response()) .finish(); @@ -1215,15 +1206,15 @@ mod tests { .on_body("/consist_schedule/values/0/loading_gauge_type", "GLOTT") .on_body( "/consist_schedule/values/0/physics_consist/length", - length.get::() as u64, + millimeter::from(length) as u64, ) .on_body( "/consist_schedule/values/0/physics_consist/max_speed", - maximum_speed.get::(), + meter_per_second::from(maximum_speed), ) .on_body( "/consist_schedule/values/0/physics_consist/mass", - mass.get::() as u64, + kilogram::from(mass) as u64, ) .response(StatusCode::OK) .json(core_client::stdcm::FinalEvent { @@ -1253,9 +1244,9 @@ mod tests { .await; let consist_schedule = build_single_consist(build_consist_config( rolling_stock.id, - Some(mass.get::()), - Some(length.get::()), - Some(maximum_speed.get::()), + Some(kilogram::from(mass)), + Some(meter::from(length)), + Some(kilometer_per_hour::from(maximum_speed)), Some(LoadingGaugeType::Glott), None, )); @@ -1982,39 +1973,39 @@ mod tests { async fn stdcm_with_towed_rolling_stock() { let mut core: MockingClient = MockingClient::new(); // Added masses of both the rolling stock and the towed rolling stock - let mass = Mass::, f64>::new::(950000.0); + let mass = kilogram::new(950000.0); // Added lengths of both the rolling stock and the towed rolling stock - let length = Length::, f64>::new::(430.0); + let length = meter::new(430.0); // Minimum of both the rolling stock and the towed rolling stock maximum speeds - let maximum_speed = Velocity::, f64>::new::(35.0); + let maximum_speed = meter_per_second::new(35.0); // The maximum startup acceleration of both the rolling stock and the towed rolling stock let startup_acceleration = units::meter_per_second_squared::new(0.06); // The minimum comfort acceleration of both the rolling stock and the towed rolling stock let comfort_acceleration = units::meter_per_second_squared::new(0.2); core.stub("/pathfinding/blocks") .on_body("/rolling_stock_loading_gauge", "G1") - .on_body("/rolling_stock_length", length.get::() as u64) + .on_body("/rolling_stock_length", millimeter::from(length) as u64) .on_body( "/rolling_stock_maximum_speed", - maximum_speed.get::(), + meter_per_second::from(maximum_speed), ) .response(StatusCode::OK) .json(PathfindingResult::Success(pathfinding_result_success())) .finish(); core.stub("/standalone_simulation") - .on_body("/physics_consist/length", length.get::() as u64) + .on_body("/physics_consist/length", millimeter::from(length) as u64) .on_body( "/physics_consist/max_speed", - maximum_speed.get::(), + meter_per_second::from(maximum_speed), ) - .on_body("/physics_consist/mass", mass.get::() as u64) + .on_body("/physics_consist/mass", kilogram::from(mass) as u64) .on_body( "/physics_consist/startup_acceleration", - startup_acceleration.get::(), + meter_per_second_squared::from(startup_acceleration), ) .on_body( "/physics_consist/comfort_acceleration", - comfort_acceleration.get::(), + meter_per_second_squared::from(comfort_acceleration), ) .response(StatusCode::OK) .json(simulation_empty_response()) @@ -2022,23 +2013,23 @@ mod tests { core.stub("/stdcm") .on_body( "/consist_schedule/values/0/physics_consist/length", - length.get::() as u64, + millimeter::from(length) as u64, ) .on_body( "/consist_schedule/values/0/physics_consist/max_speed", - maximum_speed.get::(), + meter_per_second::from(maximum_speed), ) .on_body( "/consist_schedule/values/0/physics_consist/mass", - mass.get::() as u64, + kilogram::from(mass) as u64, ) .on_body( "/consist_schedule/values/0/physics_consist/startup_acceleration", - startup_acceleration.get::(), + meter_per_second_squared::from(startup_acceleration), ) .on_body( "/consist_schedule/values/0/physics_consist/comfort_acceleration", - comfort_acceleration.get::(), + meter_per_second_squared::from(comfort_acceleration), ) .response(StatusCode::OK) .json(core_client::stdcm::FinalEvent { @@ -2096,9 +2087,9 @@ mod tests { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn user_with_no_grant_is_forbidden() { - let mass = Mass::, f64>::new::(1000000.0); - let length = Length::, f64>::new::(400.0); - let maximum_speed = Velocity::, f64>::new::(30.0); + let mass = kilogram::new(1000000.0); + let length = meter::new(400.0); + let maximum_speed = kilometer_per_hour::new(30.0); let app = test_app!().build(); let db_pool = app.db_pool(); let small_infra = create_small_infra(&mut db_pool.get_ok()).await; @@ -2112,9 +2103,9 @@ mod tests { .await; let consist_schedule = build_single_consist(build_consist_config( rolling_stock.id, - Some(mass.get::()), - Some(length.get::()), - Some(maximum_speed.get::()), + Some(kilogram::from(mass)), + Some(meter::from(length)), + Some(kilometer_per_hour::from(maximum_speed)), Some(LoadingGaugeType::Glott), None, )); @@ -2128,9 +2119,9 @@ mod tests { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn user_without_stdcm_role_is_forbidden() { - let mass = Mass::, f64>::new::(1000000.0); - let length = Length::, f64>::new::(400.0); - let maximum_speed = Velocity::, f64>::new::(30.0); + let mass = kilogram::new(1000000.0); + let length = meter::new(400.0); + let maximum_speed = kilometer_per_hour::new(30.0); let app = test_app!().build(); let db_pool = app.db_pool(); let small_infra = create_small_infra(&mut db_pool.get_ok()).await; @@ -2145,9 +2136,9 @@ mod tests { .await; let consist_schedule = build_single_consist(build_consist_config( rolling_stock.id, - Some(mass.get::()), - Some(length.get::()), - Some(maximum_speed.get::()), + Some(kilogram::from(mass)), + Some(meter::from(length)), + Some(kilometer_per_hour::from(maximum_speed)), Some(LoadingGaugeType::Glott), None, )); @@ -2161,9 +2152,9 @@ mod tests { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn user_without_infra_grant_is_forbidden() { - let mass = Mass::, f64>::new::(1000000.0); - let length = Length::, f64>::new::(400.0); - let maximum_speed = Velocity::, f64>::new::(30.0); + let mass = kilogram::new(1000000.0); + let length = meter::new(400.0); + let maximum_speed = kilometer_per_hour::new(30.0); let app = test_app!().build(); let db_pool = app.db_pool(); let small_infra = create_small_infra(&mut db_pool.get_ok()).await; @@ -2178,9 +2169,9 @@ mod tests { .await; let consist_schedule = build_single_consist(build_consist_config( rolling_stock.id, - Some(mass.get::()), - Some(length.get::()), - Some(maximum_speed.get::()), + Some(kilogram::from(mass)), + Some(meter::from(length)), + Some(kilometer_per_hour::from(maximum_speed)), Some(LoadingGaugeType::Glott), None, )); diff --git a/editoast/src/views/timetable/stdcm/request.rs b/editoast/src/views/timetable/stdcm/request.rs index 03f1155be6b..775ba0aff29 100644 --- a/editoast/src/views/timetable/stdcm/request.rs +++ b/editoast/src/views/timetable/stdcm/request.rs @@ -7,6 +7,10 @@ use common::units; use core_client::pathfinding::PathfindingInputError; use database::DbConnection; +use common::unit_system::length::meter; +use common::unit_system::mass::kilogram; +use common::unit_system::quantities; +use common::unit_system::velocity::meter_per_second; use schemas::RollingStock; use schemas::rolling_stock::LoadingGaugeType; use schemas::rolling_stock::RollingResistance; @@ -17,10 +21,6 @@ use serde::Deserialize; use serde::Deserializer; use serde::Serialize; use serde::Serializer; -use units::quantities; -use uom::si::length::meter; -use uom::si::mass::kilogram; -use uom::si::velocity::meter_per_second; use utoipa::ToSchema; use crate::error::Result; @@ -379,8 +379,8 @@ impl ConsistConfiguration { && request_total_length < consist_length { return Err(StdcmError::InvalidConsistLength { - expected_min: consist_length.value, - provided_consist_length: request_total_length.value, + expected_min: units::meter::from(consist_length), + provided_consist_length: units::meter::from(request_total_length), } .into()); } From fb904c2447a93c2dc4423a416bdfb52b659ee72c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tristram=20Gr=C3=A4bener?= Date: Thu, 24 Sep 2026 09:40:22 +0200 Subject: [PATCH 4/5] editoast: remove uom dependency when not needed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tristram Gräbener --- editoast/Cargo.lock | 4 ---- editoast/Cargo.toml | 1 - editoast/core_task/Cargo.toml | 1 - editoast/models/Cargo.toml | 1 - editoast/schemas/Cargo.toml | 1 - 5 files changed, 8 deletions(-) diff --git a/editoast/Cargo.lock b/editoast/Cargo.lock index 1887495cb71..57eaa088085 100644 --- a/editoast/Cargo.lock +++ b/editoast/Cargo.lock @@ -955,7 +955,6 @@ dependencies = [ "tokio", "tokio-stream", "tracing", - "uom", "zstd 0.14.0", ] @@ -1493,7 +1492,6 @@ dependencies = [ "tower-http 0.7.1", "tracing", "tracing-subscriber", - "uom", "url", "utoipa", "uuid", @@ -3085,7 +3083,6 @@ dependencies = [ "tokio", "tokio-postgres", "tracing", - "uom", "url", "utoipa", "uuid", @@ -4574,7 +4571,6 @@ dependencies = [ "serde_with", "strum", "thiserror 2.0.20", - "uom", "utoipa", "uuid", ] diff --git a/editoast/Cargo.toml b/editoast/Cargo.toml index 00e97116cae..0865b2bfde6 100644 --- a/editoast/Cargo.toml +++ b/editoast/Cargo.toml @@ -250,7 +250,6 @@ tower-http = { version = "0.7", features = [ ] } tracing.workspace = true tracing-subscriber.workspace = true -uom.workspace = true url.workspace = true utoipa.workspace = true uuid.workspace = true diff --git a/editoast/core_task/Cargo.toml b/editoast/core_task/Cargo.toml index 5ca11f1944e..4fb6b7ad0d6 100644 --- a/editoast/core_task/Cargo.toml +++ b/editoast/core_task/Cargo.toml @@ -21,7 +21,6 @@ serde_json.workspace = true tokio.workspace = true tokio-stream.workspace = true tracing.workspace = true -uom.workspace = true [dev-dependencies] cache = { workspace = true, features = ["mock"] } diff --git a/editoast/models/Cargo.toml b/editoast/models/Cargo.toml index 7f700794982..8248f06b79f 100644 --- a/editoast/models/Cargo.toml +++ b/editoast/models/Cargo.toml @@ -38,7 +38,6 @@ thiserror.workspace = true tokio.workspace = true tokio-postgres.workspace = true tracing.workspace = true -uom.workspace = true url.workspace = true utoipa.workspace = true uuid.workspace = true diff --git a/editoast/schemas/Cargo.toml b/editoast/schemas/Cargo.toml index 1b14468d323..92b8edf614e 100644 --- a/editoast/schemas/Cargo.toml +++ b/editoast/schemas/Cargo.toml @@ -23,7 +23,6 @@ serde_json.workspace = true serde_with.workspace = true strum.workspace = true thiserror.workspace = true -uom.workspace = true utoipa.workspace = true uuid.workspace = true From 2e7949d1abcca2b008831e54b097b472906fa2f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tristram=20Gr=C3=A4bener?= Date: Fri, 25 Sep 2026 09:55:52 +0200 Subject: [PATCH 5/5] editoast: extract unit_system in a separate crate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The goal is to continue the effort to split editoast in smaller crates. The units were implemented in common that was inclued nearly everywhere, even when not needed. This is also the occasion to be more explicit about quantities vs. units. Signed-off-by: Tristram Gräbener --- editoast/.dockerignore | 3 -- editoast/Cargo.lock | 15 ++++++++- editoast/Cargo.toml | 3 +- editoast/common/Cargo.toml | 1 - editoast/common/src/lib.rs | 10 +----- editoast/core_client/Cargo.toml | 1 + .../core_client/src/conflict_detection.rs | 6 ++-- editoast/core_client/src/simulation.rs | 14 ++++----- editoast/core_task/Cargo.toml | 1 + .../core_task/src/envs/simulation/inputs.rs | 10 +++--- .../core_task/src/envs/simulation/request.rs | 4 +-- editoast/editoast_derive/src/lib.rs | 2 +- editoast/models/Cargo.toml | 1 + editoast/models/src/rolling_stock.rs | 14 ++++----- editoast/models/src/timetable.rs | 4 +-- editoast/models/src/towed_rolling_stock.rs | 12 +++---- editoast/models/src/train_schedule.rs | 8 ++--- editoast/schemas/Cargo.toml | 1 + editoast/schemas/src/fixtures.rs | 4 +-- editoast/schemas/src/paced_train.rs | 4 +-- .../schemas/src/primitives/time_window.rs | 4 +-- editoast/schemas/src/rolling_stock.rs | 17 +++++----- .../src/rolling_stock/rolling_resistance.rs | 14 ++++----- .../src/rolling_stock/towed_rolling_stock.rs | 12 +++---- editoast/schemas/src/train_schedule.rs | 4 +-- editoast/src/client/import_rolling_stock.rs | 2 +- .../src/client/stdcm_search_env_commands.rs | 4 +-- .../src/views/level_crossing_occupancy.rs | 11 +++++-- editoast/src/views/path/pathfinding.rs | 2 +- editoast/src/views/rolling_stock/light.rs | 8 ++--- editoast/src/views/rolling_stock/towed.rs | 2 +- editoast/src/views/search_journeys.rs | 3 +- editoast/src/views/timetable.rs | 14 ++++----- editoast/src/views/timetable/conflicts.rs | 12 +++---- editoast/src/views/timetable/simulation.rs | 16 ++++------ editoast/src/views/timetable/stdcm.rs | 6 ++-- editoast/src/views/timetable/stdcm/request.rs | 17 +++++----- .../src/views/timetable/track_occupancy.rs | 4 +-- .../src/views/timetable/train_schedule.rs | 2 +- .../timetable/train_schedule_exceptions.rs | 2 +- editoast/src/views/train_schedule_set.rs | 2 +- editoast/unit_system/Cargo.toml | 16 ++++++++++ editoast/unit_system/src/lib.rs | 5 +++ .../src/quantities.rs} | 31 ++++++------------- .../src/quantities}/acceleration.rs | 0 .../src/quantities}/force.rs | 1 - .../src/quantities}/frequency.rs | 1 - .../src/quantities}/length.rs | 0 .../src/quantities}/linear_mass_density.rs | 0 .../src/quantities}/linear_number_density.rs | 0 .../src/quantities}/mass.rs | 0 .../src/quantities}/mass_rate.rs | 0 .../src/quantities}/time.rs | 0 .../src/quantities}/velocity.rs | 0 editoast/{common => unit_system}/src/units.rs | 30 +++++++++--------- 55 files changed, 185 insertions(+), 175 deletions(-) delete mode 100644 editoast/.dockerignore create mode 100644 editoast/unit_system/Cargo.toml create mode 100644 editoast/unit_system/src/lib.rs rename editoast/{common/src/unit_system.rs => unit_system/src/quantities.rs} (74%) rename editoast/{common/src/unit_system => unit_system/src/quantities}/acceleration.rs (100%) rename editoast/{common/src/unit_system => unit_system/src/quantities}/force.rs (94%) rename editoast/{common/src/unit_system => unit_system/src/quantities}/frequency.rs (93%) rename editoast/{common/src/unit_system => unit_system/src/quantities}/length.rs (100%) rename editoast/{common/src/unit_system => unit_system/src/quantities}/linear_mass_density.rs (100%) rename editoast/{common/src/unit_system => unit_system/src/quantities}/linear_number_density.rs (100%) rename editoast/{common/src/unit_system => unit_system/src/quantities}/mass.rs (100%) rename editoast/{common/src/unit_system => unit_system/src/quantities}/mass_rate.rs (100%) rename editoast/{common/src/unit_system => unit_system/src/quantities}/time.rs (100%) rename editoast/{common/src/unit_system => unit_system/src/quantities}/velocity.rs (100%) rename editoast/{common => unit_system}/src/units.rs (92%) diff --git a/editoast/.dockerignore b/editoast/.dockerignore deleted file mode 100644 index 7b388420334..00000000000 --- a/editoast/.dockerignore +++ /dev/null @@ -1,3 +0,0 @@ -target -Dockerfile -.env diff --git a/editoast/Cargo.lock b/editoast/Cargo.lock index 57eaa088085..3a9449c10f9 100644 --- a/editoast/Cargo.lock +++ b/editoast/Cargo.lock @@ -798,7 +798,6 @@ dependencies = [ "tracing", "tracing-opentelemetry", "tracing-subscriber", - "uom", "url", "utoipa", ] @@ -928,6 +927,7 @@ dependencies = [ "tokio-stream", "tracing", "tracing-opentelemetry", + "unit_system", "url", "utoipa", "uuid", @@ -955,6 +955,7 @@ dependencies = [ "tokio", "tokio-stream", "tracing", + "unit_system", "zstd 0.14.0", ] @@ -1492,6 +1493,7 @@ dependencies = [ "tower-http 0.7.1", "tracing", "tracing-subscriber", + "unit_system", "url", "utoipa", "uuid", @@ -3083,6 +3085,7 @@ dependencies = [ "tokio", "tokio-postgres", "tracing", + "unit_system", "url", "utoipa", "uuid", @@ -4571,6 +4574,7 @@ dependencies = [ "serde_with", "strum", "thiserror 2.0.20", + "unit_system", "utoipa", "uuid", ] @@ -5583,6 +5587,15 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "unit_system" +version = "0.1.0" +dependencies = [ + "common", + "serde", + "uom", +] + [[package]] name = "unsafe-libyaml-norway" version = "0.2.15" diff --git a/editoast/Cargo.toml b/editoast/Cargo.toml index 0865b2bfde6..fd79050f0a4 100644 --- a/editoast/Cargo.toml +++ b/editoast/Cargo.toml @@ -150,7 +150,7 @@ tracing-opentelemetry = { version = "0.33.0", default-features = false, features "tracing-log", ] } tracing-subscriber = { version = "0.3.23", features = ["env-filter"] } -uom = { version = "0.38.0", default-features = false, features = ["f64"] } +unit_system = { path = "./unit_system" } url = { version = "2.5.8", features = ["serde"] } urlencoding = "2.1.3" utoipa = { git = "https://github.com/osrd-project/utoipa.git", rev = "5103a24a6d6", features = [ @@ -250,6 +250,7 @@ tower-http = { version = "0.7", features = [ ] } tracing.workspace = true tracing-subscriber.workspace = true +unit_system.workspace = true url.workspace = true utoipa.workspace = true uuid.workspace = true diff --git a/editoast/common/Cargo.toml b/editoast/common/Cargo.toml index 67bd758bb52..110242e31bd 100644 --- a/editoast/common/Cargo.toml +++ b/editoast/common/Cargo.toml @@ -16,7 +16,6 @@ serde_json.workspace = true tracing.workspace = true tracing-opentelemetry.workspace = true tracing-subscriber.workspace = true -uom.workspace = true url.workspace = true utoipa.workspace = true diff --git a/editoast/common/src/lib.rs b/editoast/common/src/lib.rs index 318e5377beb..72e8e2a324f 100644 --- a/editoast/common/src/lib.rs +++ b/editoast/common/src/lib.rs @@ -1,12 +1,7 @@ -#[macro_use] -extern crate uom; - pub mod geometry; mod hash_rounded_float; pub mod rangemap_utils; pub mod tracing; -pub mod unit_system; -pub mod units; use std::collections::HashSet; use std::hash::Hash; @@ -39,10 +34,7 @@ pub struct Version { /// Allows implementing Eq for floats considering all NaN values to be equal /// /// Tip: provide this to Educe. -pub fn float_eq(a: &V, b: &V) -> bool -where - V: uom::num_traits::Num + uom::num_traits::float::TotalOrder + uom::Conversion, -{ +pub fn float_eq(a: &f64, b: &f64) -> bool { matches!(a.total_cmp(b), std::cmp::Ordering::Equal) } diff --git a/editoast/core_client/Cargo.toml b/editoast/core_client/Cargo.toml index d7efcc650e1..81c06aab77a 100644 --- a/editoast/core_client/Cargo.toml +++ b/editoast/core_client/Cargo.toml @@ -28,6 +28,7 @@ tokio.workspace = true tokio-stream = "0.1.18" tracing.workspace = true tracing-opentelemetry.workspace = true +unit_system.workspace = true url.workspace = true utoipa.workspace = true uuid.workspace = true diff --git a/editoast/core_client/src/conflict_detection.rs b/editoast/core_client/src/conflict_detection.rs index 22d60401b69..3a21389bb42 100644 --- a/editoast/core_client/src/conflict_detection.rs +++ b/editoast/core_client/src/conflict_detection.rs @@ -1,7 +1,7 @@ -use common::unit_system::quantities::Offset; use serde::Deserialize; use serde::Serialize; use std::collections::HashMap; +use unit_system::quantities::Offset; use utoipa::ToSchema; use uuid::Uuid; @@ -65,7 +65,7 @@ pub struct Conflict { /// (`trains_requirements` and `work_schedules`) and response. /// Example: `1970-01-01T00:00:00Z` for calendar timetables; the timetable start for hourly /// timetables. - #[serde(with = "common::units::millisecond::i64")] + #[serde(with = "unit_system::units::millisecond::i64")] pub start_time: Offset, /// Duration of the conflict in ms. pub duration: u64, @@ -90,7 +90,7 @@ pub struct ConflictRequirement { /// (`trains_requirements` and `work_schedules`) and response. /// Example: `1970-01-01T00:00:00Z` for calendar timetables; the timetable start for hourly /// timetables. - #[serde(with = "common::units::millisecond::i64")] + #[serde(with = "unit_system::units::millisecond::i64")] #[schema(value_type = i64)] pub start_time: Offset, /// Duration of the time range in ms (difference between the latest end time and the earliest start_time for any zone use in this conflict). diff --git a/editoast/core_client/src/simulation.rs b/editoast/core_client/src/simulation.rs index f2282837bc2..3f905ff9a4d 100644 --- a/editoast/core_client/src/simulation.rs +++ b/editoast/core_client/src/simulation.rs @@ -2,13 +2,6 @@ use std::collections::BTreeMap; use std::collections::HashMap; use std::hash::Hash; -use common::unit_system::quantities::Acceleration; -use common::unit_system::quantities::Deceleration; -use common::unit_system::quantities::Length; -use common::unit_system::quantities::Mass; -use common::unit_system::quantities::Time; -use common::unit_system::quantities::Velocity; -use common::units; use educe::Educe; use schemas::rolling_stock::EffortCurves; use schemas::rolling_stock::EtcsBrakeParams; @@ -20,6 +13,13 @@ use schemas::train_schedule::ReceptionSignal; use schemas::train_schedule::TrainScheduleOptions; use serde::Deserialize; use serde::Serialize; +use unit_system::quantities::Acceleration; +use unit_system::quantities::Deceleration; +use unit_system::quantities::Length; +use unit_system::quantities::Mass; +use unit_system::quantities::Time; +use unit_system::quantities::Velocity; +use unit_system::units; use utoipa::ToSchema; use super::RawError; diff --git a/editoast/core_task/Cargo.toml b/editoast/core_task/Cargo.toml index 4fb6b7ad0d6..d55883c22b0 100644 --- a/editoast/core_task/Cargo.toml +++ b/editoast/core_task/Cargo.toml @@ -21,6 +21,7 @@ serde_json.workspace = true tokio.workspace = true tokio-stream.workspace = true tracing.workspace = true +unit_system.workspace = true [dev-dependencies] cache = { workspace = true, features = ["mock"] } diff --git a/editoast/core_task/src/envs/simulation/inputs.rs b/editoast/core_task/src/envs/simulation/inputs.rs index 3047cb5b2f1..e7691df8cb6 100644 --- a/editoast/core_task/src/envs/simulation/inputs.rs +++ b/editoast/core_task/src/envs/simulation/inputs.rs @@ -47,9 +47,9 @@ pub struct SimulationTrainParameters { power_restrictions: rangemap::RangeMap, margins: rangemap::RangeMap, - #[educe(Hash(method(common::units::meter_per_second::hash)))] - #[educe(PartialEq(method(common::units::meter_per_second::eq)))] - initial_speed: common::unit_system::quantities::Velocity, + #[educe(Hash(method(unit_system::units::meter_per_second::hash)))] + #[educe(PartialEq(method(unit_system::units::meter_per_second::eq)))] + initial_speed: unit_system::quantities::Velocity, constraint_distribution: Distribution, comfort: Comfort, speed_limit_tag: Option, @@ -73,7 +73,7 @@ impl ScheduleItem { impl SimulationTrainParameters { pub fn new( - initial_speed: common::unit_system::quantities::Velocity, + initial_speed: unit_system::quantities::Velocity, constraint_distribution: Distribution, comfort: Comfort, speed_limit_tag: Option, @@ -103,7 +103,7 @@ impl SimulationTrainParameters { &self.margins } - pub fn initial_speed(&self) -> common::unit_system::quantities::Velocity { + pub fn initial_speed(&self) -> unit_system::quantities::Velocity { self.initial_speed } diff --git a/editoast/core_task/src/envs/simulation/request.rs b/editoast/core_task/src/envs/simulation/request.rs index 44006a1241d..13c9709c9ca 100644 --- a/editoast/core_task/src/envs/simulation/request.rs +++ b/editoast/core_task/src/envs/simulation/request.rs @@ -114,9 +114,7 @@ pub(super) fn build_request( values: margin_values, }, power_restrictions, - initial_speed: params - .initial_speed() - .get::(), + initial_speed: unit_system::units::meter_per_second::from(params.initial_speed()), comfort: params.comfort(), constraint_distribution: params.constraint_distribution(), speed_limit_tag: params.speed_limit_tag().map(|s| s.to_owned()), diff --git a/editoast/editoast_derive/src/lib.rs b/editoast/editoast_derive/src/lib.rs index 838c22e7c25..dcf9f06ff5b 100644 --- a/editoast/editoast_derive/src/lib.rs +++ b/editoast/editoast_derive/src/lib.rs @@ -226,7 +226,7 @@ pub fn search_config_store(input: proc_macro::TokenStream) -> proc_macro::TokenS /// * `#[model(to_string)]`: calls `to_string()` before writing the field to the database and calls `String::from` after reading (diesel column type: String) /// * `#[model(to_enum)]`: is converted as `u8` before writing the field to the database and calls `FromRepr::from_repr` after reading (diesel column type: TinyInt) /// * `#[model(remote = "T")]`: calls `Into::::into` before writing the field to the database and calls `T::from` after reading (diesel column type: T) -/// * `#[model(uom_unit = "path::to::unit")]`: the value is the path to an unit defined in common, e.g. `"common::units::meter"` +/// * `#[model(uom_unit = "path::to::unit")]`: the value is the path to an unit defined in common, e.g. `"unit_system::units::meter"` /// * `#[model(geo)]` **TODO**: TBD /// * `#[model(non_null_array = "T")]`: wraps type `T` into an `Option` when interfacing with diesel to satisfy the nullable property of postgres arrays /// diff --git a/editoast/models/Cargo.toml b/editoast/models/Cargo.toml index 8248f06b79f..ca567b3eddf 100644 --- a/editoast/models/Cargo.toml +++ b/editoast/models/Cargo.toml @@ -38,6 +38,7 @@ thiserror.workspace = true tokio.workspace = true tokio-postgres.workspace = true tracing.workspace = true +unit_system.workspace = true url.workspace = true utoipa.workspace = true uuid.workspace = true diff --git a/editoast/models/src/rolling_stock.rs b/editoast/models/src/rolling_stock.rs index 3bf2028de7e..d4cfbf05046 100644 --- a/editoast/models/src/rolling_stock.rs +++ b/editoast/models/src/rolling_stock.rs @@ -3,13 +3,6 @@ mod power_restrictions; use std::collections::HashMap; use std::collections::HashSet; -use common::unit_system::quantities::Acceleration; -use common::unit_system::quantities::Deceleration; -use common::unit_system::quantities::Length; -use common::unit_system::quantities::Mass; -use common::unit_system::quantities::Time; -use common::unit_system::quantities::Velocity; -use common::units; use editoast_derive::Model; use schemas::rolling_stock::EffortCurves; use schemas::rolling_stock::EnergySource; @@ -20,6 +13,13 @@ use schemas::rolling_stock::RollingStockMetadata; use schemas::rolling_stock::SupportedSignalingSystem; use serde::Deserialize; use serde::Serialize; +use unit_system::quantities::Acceleration; +use unit_system::quantities::Deceleration; +use unit_system::quantities::Length; +use unit_system::quantities::Mass; +use unit_system::quantities::Time; +use unit_system::quantities::Velocity; +use unit_system::units; use utoipa::ToSchema; use crate::prelude::*; diff --git a/editoast/models/src/timetable.rs b/editoast/models/src/timetable.rs index e6f9b1c8832..2debf64ecd3 100644 --- a/editoast/models/src/timetable.rs +++ b/editoast/models/src/timetable.rs @@ -1,5 +1,3 @@ -use common::unit_system::quantities::Offset; -use common::units::millisecond; use database::DatabaseError; use database::tables::sql_types; use diesel::prelude::*; @@ -15,6 +13,8 @@ use editoast_derive::Model; use itertools::Itertools as _; use std::collections::HashSet; use std::ops::DerefMut as _; +use unit_system::quantities::Offset; +use unit_system::units::millisecond; use database::DbConnection; diff --git a/editoast/models/src/towed_rolling_stock.rs b/editoast/models/src/towed_rolling_stock.rs index 76b73bfd5e6..8157710957a 100644 --- a/editoast/models/src/towed_rolling_stock.rs +++ b/editoast/models/src/towed_rolling_stock.rs @@ -1,13 +1,13 @@ -use common::unit_system::quantities::Acceleration; -use common::unit_system::quantities::Deceleration; -use common::unit_system::quantities::Length; -use common::unit_system::quantities::Mass; -use common::unit_system::quantities::Velocity; -use common::units; use editoast_derive::Model; use schemas::rolling_stock::RollingResistancePerWeight; use serde::Deserialize; use serde::Serialize; +use unit_system::quantities::Acceleration; +use unit_system::quantities::Deceleration; +use unit_system::quantities::Length; +use unit_system::quantities::Mass; +use unit_system::quantities::Velocity; +use unit_system::units; use crate::prelude::*; diff --git a/editoast/models/src/train_schedule.rs b/editoast/models/src/train_schedule.rs index 5e44e2a92f4..5c36bebedbc 100644 --- a/editoast/models/src/train_schedule.rs +++ b/editoast/models/src/train_schedule.rs @@ -2,8 +2,6 @@ use crate::prelude::*; use crate::rolling_stock::TrainMainCategory; use crate::tags::Tags; use chrono::Duration as ChronoDuration; -use common::unit_system::quantities::Offset; -use common::units::millisecond; use derive_more::Display; use editoast_derive::Model; use itertools::Itertools as _; @@ -24,6 +22,8 @@ use schemas::train_schedule::TrainScheduleOptions; use serde::Deserialize; use serde::Serialize; use std::fmt::Display; +use unit_system::quantities::Offset; +use unit_system::units::millisecond; use utoipa::ToSchema; #[derive(Debug, Clone, Model)] @@ -37,7 +37,7 @@ pub struct TrainSchedule { pub labels: Tags, pub rolling_stock_name: String, pub train_schedule_set_id: i64, - #[model(uom_unit = "common::units::millisecond::i64")] + #[model(uom_unit = "unit_system::units::millisecond::i64")] /// For calendar timetables: elapsed ms since 1970-01-01T00:00:00Z. /// For hourly timetables: elapsed ms since the timetable start. pub start_time: Offset, @@ -504,7 +504,6 @@ mod tests { use super::OccurrenceId; use super::TrainSchedule; - use common::unit_system::quantities::Offset; use database::DbConnectionPoolV2; use pretty_assertions::assert_eq; use rstest::rstest; @@ -512,6 +511,7 @@ mod tests { use schemas::fixtures::ms_since_epoch; use schemas::paced_train::RollingStockCategoryChangeGroup; use schemas::paced_train::StartTimeChangeGroup; + use unit_system::quantities::Offset; use crate::prelude::*; use schemas::train_schedule::Comfort; diff --git a/editoast/schemas/Cargo.toml b/editoast/schemas/Cargo.toml index 92b8edf614e..92b7d05d4a4 100644 --- a/editoast/schemas/Cargo.toml +++ b/editoast/schemas/Cargo.toml @@ -23,6 +23,7 @@ serde_json.workspace = true serde_with.workspace = true strum.workspace = true thiserror.workspace = true +unit_system.workspace = true utoipa.workspace = true uuid.workspace = true diff --git a/editoast/schemas/src/fixtures.rs b/editoast/schemas/src/fixtures.rs index 36c07f73848..ca70aab4293 100644 --- a/editoast/schemas/src/fixtures.rs +++ b/editoast/schemas/src/fixtures.rs @@ -4,8 +4,8 @@ use std::str::FromStr as _; use chrono::DateTime; use chrono::Utc; -use common::unit_system; -use common::units; +use unit_system; +use unit_system::units; use crate::RollingStock; use crate::rolling_stock::EffortCurves; diff --git a/editoast/schemas/src/paced_train.rs b/editoast/schemas/src/paced_train.rs index 6c602453ada..af0735c2340 100644 --- a/editoast/schemas/src/paced_train.rs +++ b/editoast/schemas/src/paced_train.rs @@ -11,13 +11,13 @@ use crate::train_schedule::ScheduleItem; use crate::train_schedule::TrainOccurrence; use crate::train_schedule::TrainScheduleOptions; use chrono::Duration; -use common::unit_system::quantities::Offset; use serde::Deserialize; use serde::Deserializer; use serde::Serialize; use serde_with::DefaultOnNull; use serde_with::serde_as; use serde_with::skip_serializing_none; +use unit_system::quantities::Offset; use utoipa::ToSchema; use utoipa::openapi::ObjectBuilder; use utoipa::openapi::RefOr; @@ -176,7 +176,7 @@ pub struct SpeedLimitTagChangeGroup { pub struct StartTimeChangeGroup { /// For calendar timetables: elapsed ms since 1970-01-01T00:00:00Z. /// For hourly timetables: elapsed ms since the timetable start. - #[serde(with = "common::units::millisecond::i64")] + #[serde(with = "unit_system::units::millisecond::i64")] #[schema(value_type = i64)] pub value: Offset, } diff --git a/editoast/schemas/src/primitives/time_window.rs b/editoast/schemas/src/primitives/time_window.rs index 9fe20289d70..ee30b532d4a 100644 --- a/editoast/schemas/src/primitives/time_window.rs +++ b/editoast/schemas/src/primitives/time_window.rs @@ -1,12 +1,12 @@ use super::PositiveDuration; -use common::unit_system::quantities::Offset; use serde::Deserialize; use serde::Serialize; +use unit_system::quantities::Offset; use utoipa::ToSchema; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ToSchema)] pub struct TimeWindow { - #[serde(with = "common::units::millisecond::i64")] + #[serde(with = "unit_system::units::millisecond::i64")] #[schema(value_type = i64)] pub time_begin: Offset, #[schema(value_type = chrono::Duration, example = "PT5M")] diff --git a/editoast/schemas/src/rolling_stock.rs b/editoast/schemas/src/rolling_stock.rs index 18bb1685246..c1c688e7944 100644 --- a/editoast/schemas/src/rolling_stock.rs +++ b/editoast/schemas/src/rolling_stock.rs @@ -46,15 +46,6 @@ pub use sub_category::SubCategory; pub use sub_category::SubCategoryColor; mod train_category; -pub use train_category::TrainCategory; - -use common::unit_system::quantities::Acceleration; -use common::unit_system::quantities::Deceleration; -use common::unit_system::quantities::Length; -use common::unit_system::quantities::Mass; -use common::unit_system::quantities::Time; -use common::unit_system::quantities::Velocity; -use common::units; use itertools::Itertools as _; use serde::Deserialize; use serde::Deserializer; @@ -62,6 +53,14 @@ use serde::Serialize; use serde::Serializer; use std::collections::HashMap; use std::collections::HashSet; +pub use train_category::TrainCategory; +use unit_system::quantities::Acceleration; +use unit_system::quantities::Deceleration; +use unit_system::quantities::Length; +use unit_system::quantities::Mass; +use unit_system::quantities::Time; +use unit_system::quantities::Velocity; +use unit_system::units; use utoipa::ToSchema; pub const ROLLING_STOCK_RAILJSON_VERSION: &str = "3.4"; diff --git a/editoast/schemas/src/rolling_stock/rolling_resistance.rs b/editoast/schemas/src/rolling_stock/rolling_resistance.rs index 232ddea8145..9a4ce03c448 100644 --- a/editoast/schemas/src/rolling_stock/rolling_resistance.rs +++ b/editoast/schemas/src/rolling_stock/rolling_resistance.rs @@ -1,13 +1,13 @@ -use common::unit_system::quantities::AerodynamicDrag; -use common::unit_system::quantities::AerodynamicDragPerWeight; -use common::unit_system::quantities::SolidFriction; -use common::unit_system::quantities::SolidFrictionPerWeight; -use common::unit_system::quantities::ViscosityFriction; -use common::unit_system::quantities::ViscosityFrictionPerWeight; -use common::units; use educe::Educe; use serde::Deserialize; use serde::Serialize; +use unit_system::quantities::AerodynamicDrag; +use unit_system::quantities::AerodynamicDragPerWeight; +use unit_system::quantities::SolidFriction; +use unit_system::quantities::SolidFrictionPerWeight; +use unit_system::quantities::ViscosityFriction; +use unit_system::quantities::ViscosityFrictionPerWeight; +use unit_system::units; use utoipa::ToSchema; pub trait RollingResistance: Serialize + for<'de> Deserialize<'de> {} diff --git a/editoast/schemas/src/rolling_stock/towed_rolling_stock.rs b/editoast/schemas/src/rolling_stock/towed_rolling_stock.rs index 60c1889a879..e925f9ee754 100644 --- a/editoast/schemas/src/rolling_stock/towed_rolling_stock.rs +++ b/editoast/schemas/src/rolling_stock/towed_rolling_stock.rs @@ -1,12 +1,12 @@ use crate::rolling_stock::default_rolling_stock_railjson_version; use super::RollingResistancePerWeight; -use common::unit_system::quantities::Acceleration; -use common::unit_system::quantities::Deceleration; -use common::unit_system::quantities::Length; -use common::unit_system::quantities::Mass; -use common::unit_system::quantities::Velocity; -use common::units; +use unit_system::quantities::Acceleration; +use unit_system::quantities::Deceleration; +use unit_system::quantities::Length; +use unit_system::quantities::Mass; +use unit_system::quantities::Velocity; +use unit_system::units; #[editoast_derive::annotate_units] #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] diff --git a/editoast/schemas/src/train_schedule.rs b/editoast/schemas/src/train_schedule.rs index 97bf9bee7a1..dd6c1e0367b 100644 --- a/editoast/schemas/src/train_schedule.rs +++ b/editoast/schemas/src/train_schedule.rs @@ -38,12 +38,12 @@ pub use rjs_power_restriction_range::RjsPowerRestrictionRange; use std::collections::HashMap; use std::collections::HashSet; -use common::unit_system::quantities::Offset; use serde::Deserialize; use serde::Serialize; use serde::de::Error as SerdeError; use serde_with::DefaultOnNull; use serde_with::serde_as; +use unit_system::quantities::Offset; use utoipa::ToSchema; use crate::primitives::NonBlankString; @@ -60,7 +60,7 @@ pub struct TrainOccurrence { pub rolling_stock_name: String, /// For calendar timetables: elapsed ms since 1970-01-01T00:00:00Z. /// For hourly timetables: elapsed ms since the timetable start. - #[serde(with = "common::units::millisecond::i64")] + #[serde(with = "unit_system::units::millisecond::i64")] #[schema(value_type = i64)] pub start_time: Offset, pub path: Vec, diff --git a/editoast/src/client/import_rolling_stock.rs b/editoast/src/client/import_rolling_stock.rs index aefd221ee32..30d24649053 100644 --- a/editoast/src/client/import_rolling_stock.rs +++ b/editoast/src/client/import_rolling_stock.rs @@ -123,8 +123,8 @@ mod tests { use crate::client::generate_temp_file; - use common::units; use database::DbConnectionPoolV2; + use unit_system::units; fn get_fast_rolling_stock_schema( name: &str, diff --git a/editoast/src/client/stdcm_search_env_commands.rs b/editoast/src/client/stdcm_search_env_commands.rs index 0f16d4a8cec..c09ac91693d 100644 --- a/editoast/src/client/stdcm_search_env_commands.rs +++ b/editoast/src/client/stdcm_search_env_commands.rs @@ -3,7 +3,6 @@ use chrono::Duration; use chrono::Utc; use clap::Args; use clap::Subcommand; -use common::units::millisecond; use database::DbConnection; use database::DbConnectionPoolV2; use models::ElectricalProfileSet; @@ -18,6 +17,7 @@ use std::collections::HashSet; use std::fs::File; use std::io::BufReader; use std::path::PathBuf; +use unit_system::units::millisecond; #[derive(Subcommand, Debug)] pub enum StdcmSearchEnvCommands { @@ -322,12 +322,12 @@ mod tests { use super::*; use chrono::DateTime; use chrono::Utc; - use common::unit_system::quantities::Offset; use database::DbConnection; use database::DbConnectionPoolV2; use rstest::rstest; use schemas::fixtures::ms_since_epoch; use serde_json::json; + use unit_system::quantities::Offset; fn make_datetime(s: &str) -> DateTime { DateTime::parse_from_rfc3339(s).unwrap().to_utc() diff --git a/editoast/src/views/level_crossing_occupancy.rs b/editoast/src/views/level_crossing_occupancy.rs index 3a2ff9f7757..d866871bfd3 100644 --- a/editoast/src/views/level_crossing_occupancy.rs +++ b/editoast/src/views/level_crossing_occupancy.rs @@ -21,8 +21,6 @@ use axum::Extension; use axum::extract::Json; use axum::extract::State; use chrono::Duration; -use common::unit_system::quantities::Offset; -use common::units::millisecond; use core_client::pathfinding::TrackRange; use core_client::simulation::ReportTrain; use editoast_derive::EditoastError; @@ -41,6 +39,8 @@ use serde::Serialize; use std::collections::HashMap; use std::collections::HashSet; use thiserror::Error; +use unit_system::quantities::Offset; +use unit_system::units::millisecond; use utoipa::ToSchema; #[derive(Debug, Error, EditoastError)] @@ -209,7 +209,12 @@ pub(in crate::views) async fn occupancy( let rolling_stock_lengths: HashMap<_, _> = rolling_stocks .into_iter() - .map(|rs| (rs.name, common::units::millimeter::from(rs.length) as u64)) + .map(|rs| { + ( + rs.name, + unit_system::units::millimeter::from(rs.length) as u64, + ) + }) .collect(); // For each occurrence + simulation result, compute level crossing occupancy and group by level crossing id diff --git a/editoast/src/views/path/pathfinding.rs b/editoast/src/views/path/pathfinding.rs index 9a7cd26b641..eaa63412e23 100644 --- a/editoast/src/views/path/pathfinding.rs +++ b/editoast/src/views/path/pathfinding.rs @@ -12,7 +12,6 @@ use axum::Extension; use axum::extract::Json; use axum::extract::Path; use axum::extract::State; -use common::units; use core_client::AsCoreRequest as _; use core_client::CoreClient; use core_client::pathfinding::PathfindingCoreResult; @@ -33,6 +32,7 @@ use serde::Deserialize; use serde::Serialize; use tracing::debug; use tracing::info; +use unit_system::units; use utoipa::ToSchema; use crate::AppState; diff --git a/editoast/src/views/rolling_stock/light.rs b/editoast/src/views/rolling_stock/light.rs index f5bc1ff1a69..64cf0cbbc54 100644 --- a/editoast/src/views/rolling_stock/light.rs +++ b/editoast/src/views/rolling_stock/light.rs @@ -6,10 +6,6 @@ use axum::extract::Json; use axum::extract::Path; use axum::extract::Query; use axum::extract::State; -use common::unit_system::quantities::Length; -use common::unit_system::quantities::Mass; -use common::unit_system::quantities::Velocity; -use common::units; use database::DbConnection; use itertools::Itertools as _; use models::prelude::*; @@ -24,6 +20,10 @@ use schemas::rolling_stock::SupportedSignalingSystem; use serde::Serialize; use std::collections::HashMap; use std::collections::HashSet; +use unit_system::quantities::Length; +use unit_system::quantities::Mass; +use unit_system::quantities::Velocity; +use unit_system::units; use utoipa::ToSchema; use super::RollingStockError; diff --git a/editoast/src/views/rolling_stock/towed.rs b/editoast/src/views/rolling_stock/towed.rs index ca3e50ba756..0822e9e4dff 100644 --- a/editoast/src/views/rolling_stock/towed.rs +++ b/editoast/src/views/rolling_stock/towed.rs @@ -233,8 +233,8 @@ mod tests { use super::TowedRollingStockCountList; use crate::views::test_app; use crate::views::test_app::TestApp; - use common::units; use models::TowedRollingStock; + use unit_system::units; use serde_json::json; use uuid::Uuid; diff --git a/editoast/src/views/search_journeys.rs b/editoast/src/views/search_journeys.rs index 00e4e0298d0..c6beb9b3d3e 100644 --- a/editoast/src/views/search_journeys.rs +++ b/editoast/src/views/search_journeys.rs @@ -265,7 +265,8 @@ pub(in crate::views) async fn search_journeys( .enumerate() .flat_map(|(train_schedule_index, train_schedule)| { // Timetables are only Calendar so we can use the raw start_time - let offset_ms = common::units::millisecond::i64::from(train_schedule.start_time); + let offset_ms = + unit_system::units::millisecond::i64::from(train_schedule.start_time); // avoid moving them into the filter_map closure let op_index_by_id = &op_index_by_id; diff --git a/editoast/src/views/timetable.rs b/editoast/src/views/timetable.rs index feb72ee34e7..fe22a02210b 100644 --- a/editoast/src/views/timetable.rs +++ b/editoast/src/views/timetable.rs @@ -22,12 +22,6 @@ use axum::extract::Query; use axum::extract::State; use axum::http::StatusCode; use axum::response::IntoResponse; -use common::unit_system::quantities::Acceleration; -use common::unit_system::quantities::Length; -use common::unit_system::quantities::Mass; -use common::unit_system::quantities::Offset; -use common::unit_system::quantities::Velocity; -use common::units::millisecond; use core_client::conflict_detection::TrainRequirements; use core_client::conflict_detection::TrainRequirementsById; use core_client::simulation::CompleteReportTrain; @@ -57,6 +51,12 @@ use simulation::train_simulation_ordered_batch; use thiserror::Error; use tokio::time::timeout; use train_schedule::TrainScheduleResponse; +use unit_system::quantities::Acceleration; +use unit_system::quantities::Length; +use unit_system::quantities::Mass; +use unit_system::quantities::Offset; +use unit_system::quantities::Velocity; +use unit_system::units::millisecond; use utoipa::IntoParams; use utoipa::ToSchema; @@ -988,7 +988,6 @@ mod tests { use axum::http::StatusCode; use chrono::Duration; - use common::units; use core_client::simulation::RoutingZoneRequirement; use models::train_schedule::TrainScheduleChangeset; use pretty_assertions::assert_eq; @@ -998,6 +997,7 @@ mod tests { use schemas::train_schedule::OperationalPointPartReference; use schemas::train_schedule::PathItem; use schemas::train_schedule::ScheduleItem; + use unit_system::units; use super::*; use crate::error::InternalError; diff --git a/editoast/src/views/timetable/conflicts.rs b/editoast/src/views/timetable/conflicts.rs index 2426d73486d..54cc70ba075 100644 --- a/editoast/src/views/timetable/conflicts.rs +++ b/editoast/src/views/timetable/conflicts.rs @@ -12,14 +12,14 @@ use axum::extract::Path; use axum::extract::Query; use axum::extract::State; use chrono::Duration; -use common::unit_system::quantities::Offset; -use common::units::millisecond; use itertools::Itertools as _; use itertools::izip; use models::prelude::*; use schemas::timetable_type::TimetableType; use serde::Deserialize; use serde::Serialize; +use unit_system::quantities::Offset; +use unit_system::units::millisecond; use utoipa::ToSchema; use crate::AppState; @@ -62,7 +62,7 @@ pub struct Conflict { /// frame in this timetable. /// Example: `1970-01-01T00:00:00Z` for calendar timetables; the timetable start for hourly /// timetables. - #[serde(with = "common::units::millisecond::i64")] + #[serde(with = "unit_system::units::millisecond::i64")] #[schema(value_type = i64)] pub start_time: Offset, /// Duration of the conflict in ms. @@ -705,8 +705,8 @@ fn get_linking_requirements( .times .last() .expect("times should not be empty"); - let target_start_time = (target_occurrence.start_time() - source_occurrence.start_time()) - .get::() as u64; + let target_start_time = + millisecond::from(target_occurrence.start_time() - source_occurrence.start_time()) as u64; let final_spacing_requirements = spacing_requirements .into_iter() @@ -771,7 +771,6 @@ mod tests { use crate::views::path::pathfinding::PathfindingResult; use authz::InfraGrant; use authz::RollingStockGrant; - use common::units; use core_client::conflict_detection::ConflictDetectionResponse; use core_client::mocking::MockingClient; use core_client::pathfinding::PathfindingResultSuccess; @@ -792,6 +791,7 @@ mod tests { use schemas::train_schedule::Comfort; use schemas::train_schedule::Margins; use schemas::train_schedule::PathItem; + use unit_system::units; fn spacing(zone: &str, begin_time: u64, end_time: u64) -> SpacingRequirement { SpacingRequirement { diff --git a/editoast/src/views/timetable/simulation.rs b/editoast/src/views/timetable/simulation.rs index 9e751cbb516..5ec1e5ae5a5 100644 --- a/editoast/src/views/timetable/simulation.rs +++ b/editoast/src/views/timetable/simulation.rs @@ -40,6 +40,7 @@ use std::iter; use std::sync::Arc; use tracing::Instrument as _; use tracing::info; +use unit_system::units; use utoipa::ToSchema; use crate::error::InternalError; @@ -648,15 +649,10 @@ pub fn build_pathfinding_consist( .iter() .map_into() .collect(), - maximum_speed: OrderedFloat( - physics_consist_parameters - .compute_max_speed() - .get::(), - ), - length: physics_consist_parameters - .compute_length() - .get::() - .round() as u64, + maximum_speed: OrderedFloat(units::meter_per_second::from( + physics_consist_parameters.compute_max_speed(), + )), + length: units::millimeter::from(physics_consist_parameters.compute_length()).round() as u64, speed_limit_tag, } } @@ -691,7 +687,7 @@ pub fn build_simulation_train( let simulation_consist = SimulationConsist(PhysicsConsist::from(physics_consist_parameters.clone())); let simulation_train_parameters = SimulationTrainParameters::new( - common::units::meter_per_second::new(*initial_speed), + units::meter_per_second::new(*initial_speed), *constraint_distribution, *comfort, speed_limit_tag diff --git a/editoast/src/views/timetable/stdcm.rs b/editoast/src/views/timetable/stdcm.rs index ef5201518eb..5a978466431 100644 --- a/editoast/src/views/timetable/stdcm.rs +++ b/editoast/src/views/timetable/stdcm.rs @@ -28,7 +28,6 @@ use chrono::DateTime; use chrono::Duration; use chrono::Utc; use common::geometry::GeoJsonPoint; -use common::units::millisecond; use core_client::AsCoreStreaming as _; use core_client::CoreClient; use core_client::Progress; @@ -71,6 +70,7 @@ use std::sync::Arc; use thiserror::Error; use tokio::sync::mpsc; use tracing::Instrument as _; +use unit_system::units::millisecond; use utoipa::IntoParams; use utoipa::ToSchema; @@ -734,8 +734,6 @@ mod tests { use authz::RollingStockGrant; use axum::http::StatusCode; use chrono::DateTime; - use common::units; - use common::units::*; use core_client; use core_client::mocking::MockingClient; use core_client::pathfinding::TrainPath; @@ -752,6 +750,8 @@ mod tests { use schemas::train_schedule::OperationalPointReference; use schemas::train_schedule::PathItemLocation; use std::str::FromStr as _; + use unit_system::units; + use unit_system::units::*; use uuid::Uuid; use crate::error::InternalError; diff --git a/editoast/src/views/timetable/stdcm/request.rs b/editoast/src/views/timetable/stdcm/request.rs index 775ba0aff29..5737fd24f64 100644 --- a/editoast/src/views/timetable/stdcm/request.rs +++ b/editoast/src/views/timetable/stdcm/request.rs @@ -3,14 +3,9 @@ use std::collections::HashSet; use chrono::DateTime; use chrono::Duration; use chrono::Utc; -use common::units; use core_client::pathfinding::PathfindingInputError; use database::DbConnection; -use common::unit_system::length::meter; -use common::unit_system::mass::kilogram; -use common::unit_system::quantities; -use common::unit_system::velocity::meter_per_second; use schemas::RollingStock; use schemas::rolling_stock::LoadingGaugeType; use schemas::rolling_stock::RollingResistance; @@ -21,6 +16,8 @@ use serde::Deserialize; use serde::Deserializer; use serde::Serialize; use serde::Serializer; +use unit_system::quantities; +use unit_system::units; use utoipa::ToSchema; use crate::error::Result; @@ -351,7 +348,7 @@ impl ConsistConfiguration { .as_ref() .map(|t| t.mass) .unwrap_or_default(); - let consist_mass = consist_mass.floor::(); + let consist_mass = consist_mass.floor::(); if let Some(request_total_mass) = self.total_mass && request_total_mass < consist_mass @@ -373,7 +370,7 @@ impl ConsistConfiguration { ) -> Result<()> { let consist_length = traction_engine.length + towed_rolling_stock.map(|t| t.length).unwrap_or_default(); - let consist_length = consist_length.floor::(); + let consist_length = consist_length.floor::(); if let Some(request_total_length) = self.total_length && request_total_length < consist_length @@ -397,12 +394,12 @@ impl ConsistConfiguration { traction_engine.max_speed, towed_rolling_stock .and_then(|t| t.max_speed) - .unwrap_or(quantities::Velocity::new::(f64::INFINITY)), + .unwrap_or(units::meter_per_second::new(f64::INFINITY)), ); - let consist_max_speed = consist_max_speed.ceil::(); + let consist_max_speed = consist_max_speed.ceil::(); if let Some(request_max_speed) = self.max_speed - && (request_max_speed < quantities::Velocity::new::(0.0) + && (request_max_speed < units::meter_per_second::new(0.0) || request_max_speed > consist_max_speed) { return Err(StdcmError::InvalidConsistMaxSpeed { diff --git a/editoast/src/views/timetable/track_occupancy.rs b/editoast/src/views/timetable/track_occupancy.rs index 3610fff675d..982653b7778 100644 --- a/editoast/src/views/timetable/track_occupancy.rs +++ b/editoast/src/views/timetable/track_occupancy.rs @@ -1,4 +1,3 @@ -use common::units::millisecond; use core_client::pathfinding::PathfindingResultSuccess; use core_client::simulation::ReportTrain; use schemas::infra::TrackOffset; @@ -9,6 +8,7 @@ use schemas::train_schedule::PathItemLocation; use schemas::train_schedule::ScheduleItem; use serde::Deserialize; use serde::Serialize; +use unit_system::units::millisecond; use utoipa::ToSchema; use crate::views::path::operational_point_cache::OperationalPointCache; @@ -323,7 +323,6 @@ pub mod tests { use crate::views::path::pathfinding::PathfindingFailure; use crate::views::timetable::simulation::SimulationResponseSuccess; use chrono::Duration; - use common::units::millisecond; use core_client::pathfinding::PathfindingNotFound; use core_client::pathfinding::TrackRange; use core_client::simulation::CompleteReportTrain; @@ -341,6 +340,7 @@ pub mod tests { use schemas::train_schedule::OperationalPointReference; use schemas::train_schedule::ReceptionSignal; use std::collections::HashMap; + use unit_system::units::millisecond; use super::*; diff --git a/editoast/src/views/timetable/train_schedule.rs b/editoast/src/views/timetable/train_schedule.rs index 232d854b225..3d98e99c07e 100644 --- a/editoast/src/views/timetable/train_schedule.rs +++ b/editoast/src/views/timetable/train_schedule.rs @@ -16,7 +16,6 @@ use axum::extract::Path; use axum::extract::Query; use axum::extract::State; use axum::response::IntoResponse; -use common::units::millisecond; use core_client::AsCoreRequest as _; use core_client::CoreClient; use core_client::pathfinding::PathfindingInputError; @@ -55,6 +54,7 @@ use schemas::train_schedule::TrainScheduleLike as _; use serde::Deserialize; use serde::Serialize; use thiserror::Error; +use unit_system::units::millisecond; use utoipa::IntoParams; use utoipa::ToSchema; diff --git a/editoast/src/views/timetable/train_schedule_exceptions.rs b/editoast/src/views/timetable/train_schedule_exceptions.rs index 4da1ae6612e..4237efa1713 100644 --- a/editoast/src/views/timetable/train_schedule_exceptions.rs +++ b/editoast/src/views/timetable/train_schedule_exceptions.rs @@ -273,7 +273,6 @@ pub(in crate::views) async fn update( #[cfg(test)] mod tests { - use common::units::millisecond; use models; use models::TrainScheduleException; use models::prelude::Retrieve as _; @@ -283,6 +282,7 @@ mod tests { use schemas::paced_train::StartTimeChangeGroup; use schemas::paced_train::TrainNameChangeGroup; use serde_json::json; + use unit_system::units::millisecond; use crate::error::InternalError; use crate::fixtures::create_timetable_with_simple_paced_train; diff --git a/editoast/src/views/train_schedule_set.rs b/editoast/src/views/train_schedule_set.rs index 393ad95530c..19559a75143 100644 --- a/editoast/src/views/train_schedule_set.rs +++ b/editoast/src/views/train_schedule_set.rs @@ -360,12 +360,12 @@ mod tests { use crate::views::train_schedule_set::TrainScheduleSetResponse; use crate::views::train_schedule_set::TrainScheduleSetUpdateForm; use chrono::Duration; - use common::units::second; use database::DbConnection; use models::CatalogEntry; use models::TrainScheduleSet; use models::prelude::*; use reqwest::StatusCode; + use unit_system::units::second; async fn create_train_schedule_set_linked_to_catalog_entry( conn: &mut DbConnection, diff --git a/editoast/unit_system/Cargo.toml b/editoast/unit_system/Cargo.toml new file mode 100644 index 00000000000..bb499f67cdb --- /dev/null +++ b/editoast/unit_system/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "unit_system" +license.workspace = true +version.workspace = true +edition.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +common.workspace = true +serde = { workspace = true, features = ["derive"] } +uom = { version = "0.38.0", default-features = false, features = ["f64"] } + + +[lints] +workspace = true diff --git a/editoast/unit_system/src/lib.rs b/editoast/unit_system/src/lib.rs new file mode 100644 index 00000000000..9a322459b4c --- /dev/null +++ b/editoast/unit_system/src/lib.rs @@ -0,0 +1,5 @@ +#[macro_use] +extern crate uom; + +pub mod quantities; +pub mod units; diff --git a/editoast/common/src/unit_system.rs b/editoast/unit_system/src/quantities.rs similarity index 74% rename from editoast/common/src/unit_system.rs rename to editoast/unit_system/src/quantities.rs index 87fcc5c6ea9..fc8cb8ab2ec 100644 --- a/editoast/common/src/unit_system.rs +++ b/editoast/unit_system/src/quantities.rs @@ -54,24 +54,13 @@ system! { } } -pub mod quantities { - ESQ!(self::super, f64); - // Editoast aliases for existing units - pub type Offset = Time; - pub type SolidFriction = Force; - pub type SolidFrictionPerWeight = Acceleration; - pub type Deceleration = Acceleration; - pub type ViscosityFriction = MassRate; - pub type ViscosityFrictionPerWeight = Frequency; - pub type AerodynamicDrag = LinearMassDensity; - pub type AerodynamicDragPerWeight = LinearNumberDensity; -} - -pub fn quantity_eq(a: &Quantity, b: &Quantity) -> bool -where - D: Dimension + ?Sized, - U: Units + ?Sized, - V: uom::num_traits::Num + uom::num_traits::float::TotalOrder + uom::Conversion, -{ - crate::float_eq(&a.value, &b.value) -} +ESQ!(self, f64); +// Editoast aliases for existing units +pub type Offset = Time; +pub type SolidFriction = Force; +pub type SolidFrictionPerWeight = Acceleration; +pub type Deceleration = Acceleration; +pub type ViscosityFriction = MassRate; +pub type ViscosityFrictionPerWeight = Frequency; +pub type AerodynamicDrag = LinearMassDensity; +pub type AerodynamicDragPerWeight = LinearNumberDensity; diff --git a/editoast/common/src/unit_system/acceleration.rs b/editoast/unit_system/src/quantities/acceleration.rs similarity index 100% rename from editoast/common/src/unit_system/acceleration.rs rename to editoast/unit_system/src/quantities/acceleration.rs diff --git a/editoast/common/src/unit_system/force.rs b/editoast/unit_system/src/quantities/force.rs similarity index 94% rename from editoast/common/src/unit_system/force.rs rename to editoast/unit_system/src/quantities/force.rs index b0e1cf0d4af..8c55d8388e2 100644 --- a/editoast/common/src/unit_system/force.rs +++ b/editoast/unit_system/src/quantities/force.rs @@ -13,7 +13,6 @@ quantity! { N2>; // time units { - /// Derived unit of force. @newton: 1.0; "N", "newton", "newtons"; @kilonewton: 1.0E3; "kN", "kilonewton", "kilonewtons"; } diff --git a/editoast/common/src/unit_system/frequency.rs b/editoast/unit_system/src/quantities/frequency.rs similarity index 93% rename from editoast/common/src/unit_system/frequency.rs rename to editoast/unit_system/src/quantities/frequency.rs index a5ea9364db6..9757ef12c2a 100644 --- a/editoast/common/src/unit_system/frequency.rs +++ b/editoast/unit_system/src/quantities/frequency.rs @@ -12,7 +12,6 @@ quantity! { N1>; // time units { - /// The hertz is one cycle per second. @hertz: 1.0; "Hz", "hertz", "hertz"; @newton_per_meter_per_second_per_kilogram: 1.0; "N·(m/s)⁻¹·kg⁻¹", "newton per meter per second per kilogram", "newtons per meter per second per kilogram"; } diff --git a/editoast/common/src/unit_system/length.rs b/editoast/unit_system/src/quantities/length.rs similarity index 100% rename from editoast/common/src/unit_system/length.rs rename to editoast/unit_system/src/quantities/length.rs diff --git a/editoast/common/src/unit_system/linear_mass_density.rs b/editoast/unit_system/src/quantities/linear_mass_density.rs similarity index 100% rename from editoast/common/src/unit_system/linear_mass_density.rs rename to editoast/unit_system/src/quantities/linear_mass_density.rs diff --git a/editoast/common/src/unit_system/linear_number_density.rs b/editoast/unit_system/src/quantities/linear_number_density.rs similarity index 100% rename from editoast/common/src/unit_system/linear_number_density.rs rename to editoast/unit_system/src/quantities/linear_number_density.rs diff --git a/editoast/common/src/unit_system/mass.rs b/editoast/unit_system/src/quantities/mass.rs similarity index 100% rename from editoast/common/src/unit_system/mass.rs rename to editoast/unit_system/src/quantities/mass.rs diff --git a/editoast/common/src/unit_system/mass_rate.rs b/editoast/unit_system/src/quantities/mass_rate.rs similarity index 100% rename from editoast/common/src/unit_system/mass_rate.rs rename to editoast/unit_system/src/quantities/mass_rate.rs diff --git a/editoast/common/src/unit_system/time.rs b/editoast/unit_system/src/quantities/time.rs similarity index 100% rename from editoast/common/src/unit_system/time.rs rename to editoast/unit_system/src/quantities/time.rs diff --git a/editoast/common/src/unit_system/velocity.rs b/editoast/unit_system/src/quantities/velocity.rs similarity index 100% rename from editoast/common/src/unit_system/velocity.rs rename to editoast/unit_system/src/quantities/velocity.rs diff --git a/editoast/common/src/units.rs b/editoast/unit_system/src/units.rs similarity index 92% rename from editoast/common/src/units.rs rename to editoast/unit_system/src/units.rs index 0a850fd55c9..80a4c05273a 100644 --- a/editoast/common/src/units.rs +++ b/editoast/unit_system/src/units.rs @@ -36,34 +36,34 @@ macro_rules! quantity_to_path { (Length, $unit:ident) => { - crate::unit_system::length::$unit + crate::quantities::length::$unit }; (Velocity, $unit:ident) => { - crate::unit_system::velocity::$unit + crate::quantities::velocity::$unit }; (Acceleration, $unit:ident) => { - crate::unit_system::acceleration::$unit + crate::quantities::acceleration::$unit }; (Mass, $unit:ident) => { - crate::unit_system::mass::$unit + crate::quantities::mass::$unit }; (SolidFriction, $unit:ident) => { - crate::unit_system::force::$unit + crate::quantities::force::$unit }; (ViscosityFriction, $unit:ident) => { - crate::unit_system::mass_rate::$unit + crate::quantities::mass_rate::$unit }; (ViscosityFrictionPerWeight, $unit:ident) => { - crate::unit_system::frequency::$unit + crate::quantities::frequency::$unit }; (AerodynamicDrag, $unit:ident) => { - crate::unit_system::linear_mass_density::$unit + crate::quantities::linear_mass_density::$unit }; (AerodynamicDragPerWeight, $unit:ident) => { - crate::unit_system::linear_number_density::$unit + crate::quantities::linear_number_density::$unit }; (Time, $unit:ident) => { - crate::unit_system::time::$unit + crate::quantities::time::$unit }; } @@ -74,7 +74,7 @@ macro_rules! define_unit { use serde::Deserializer; use serde::Serialize; use serde::Serializer; - pub type Quantity = crate::unit_system::quantities::$quantity; + pub type Quantity = $crate::quantities::$quantity; type Unit = quantity_to_path!($quantity, $unit); pub type ReprType = f64; @@ -102,11 +102,11 @@ macro_rules! define_unit { } pub fn hash(value: &Quantity, state: &mut H) { - crate::hash_float::<5, H>(&from(*value), state); + common::hash_float::<5, H>(&from(*value), state); } pub fn eq(a: &Quantity, b: &Quantity) -> bool { - $crate::float_eq(&a.get::(), &b.get::()) + common::float_eq(&a.get::(), &b.get::()) } pub mod option { @@ -145,7 +145,7 @@ macro_rules! define_unit { pub fn eq(a: &Option, b: &Option) -> bool { match (a, b) { - (Some(a), Some(b)) => $crate::float_eq(&a.get::(), &b.get::()), + (Some(a), Some(b)) => a == b, (None, None) => true, _ => false, } @@ -253,8 +253,8 @@ macro_rules! define_unit { } // Any new value here must also be added in editoast_derive/src/annotate_units.rs -define_unit!(millimeter, Length); define_unit!(meter, Length); +define_unit!(millimeter, Length); define_unit!(meter_per_second, Velocity); define_unit!(kilometer_per_hour, Velocity); define_unit!(meter_per_second_squared, Acceleration);