siderust-js 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. package/.github/workflows/ci.yml +166 -0
  2. package/.gitmodules +9 -0
  3. package/CHANGELOG.md +26 -0
  4. package/LICENSE +661 -0
  5. package/README.md +138 -0
  6. package/package.json +12 -0
  7. package/qtty-js/.github/workflows/ci.yml +151 -0
  8. package/qtty-js/.gitmodules +3 -0
  9. package/qtty-js/CHANGELOG.md +31 -0
  10. package/qtty-js/LICENSE +661 -0
  11. package/qtty-js/README.md +132 -0
  12. package/qtty-js/package.json +20 -0
  13. package/qtty-js/qtty/.github/workflows/ci.yml +155 -0
  14. package/qtty-js/qtty/CHANGELOG.md +120 -0
  15. package/qtty-js/qtty/Cargo.lock +1462 -0
  16. package/qtty-js/qtty/Cargo.toml +12 -0
  17. package/qtty-js/qtty/LICENSE +661 -0
  18. package/qtty-js/qtty/README.md +9 -0
  19. package/qtty-js/qtty/qtty/Cargo.toml +41 -0
  20. package/qtty-js/qtty/qtty/README.md +8 -0
  21. package/qtty-js/qtty/qtty/examples/angles.rs +14 -0
  22. package/qtty-js/qtty/qtty/examples/astronomy.rs +17 -0
  23. package/qtty-js/qtty/qtty/examples/dimensional_arithmetic.rs +83 -0
  24. package/qtty-js/qtty/qtty/examples/python_integration.rs +61 -0
  25. package/qtty-js/qtty/qtty/examples/quickstart.rs +15 -0
  26. package/qtty-js/qtty/qtty/examples/ratios.rs +12 -0
  27. package/qtty-js/qtty/qtty/examples/serde_with_unit.rs +234 -0
  28. package/qtty-js/qtty/qtty/examples/serialization.rs +141 -0
  29. package/qtty-js/qtty/qtty/examples/serialization_advanced.rs +155 -0
  30. package/qtty-js/qtty/qtty/src/f32.rs +108 -0
  31. package/qtty-js/qtty/qtty/src/f64.rs +30 -0
  32. package/qtty-js/qtty/qtty/src/i128.rs +111 -0
  33. package/qtty-js/qtty/qtty/src/i16.rs +111 -0
  34. package/qtty-js/qtty/qtty/src/i32.rs +111 -0
  35. package/qtty-js/qtty/qtty/src/i64.rs +111 -0
  36. package/qtty-js/qtty/qtty/src/i8.rs +111 -0
  37. package/qtty-js/qtty/qtty/src/lib.rs +238 -0
  38. package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std/Cargo.lock +83 -0
  39. package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std/Cargo.toml +10 -0
  40. package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std/src/lib.rs +7 -0
  41. package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std-alloc/Cargo.lock +83 -0
  42. package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std-alloc/Cargo.toml +10 -0
  43. package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std-alloc/src/lib.rs +7 -0
  44. package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-std/Cargo.lock +83 -0
  45. package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-std/Cargo.toml +10 -0
  46. package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-std/src/lib.rs +5 -0
  47. package/qtty-js/qtty/qtty/tests/integration_tests.rs +529 -0
  48. package/qtty-js/qtty/qtty/tests/qtty_vec_feature_matrix.rs +58 -0
  49. package/qtty-js/qtty/qtty-core/Cargo.toml +41 -0
  50. package/qtty-js/qtty/qtty-core/README.md +8 -0
  51. package/qtty-js/qtty/qtty-core/examples/diesel_integration.rs +145 -0
  52. package/qtty-js/qtty/qtty-core/examples/quantity_db_serde.rs +215 -0
  53. package/qtty-js/qtty/qtty-core/src/dimension.rs +249 -0
  54. package/qtty-js/qtty/qtty-core/src/feature_diesel.rs +318 -0
  55. package/qtty-js/qtty/qtty-core/src/feature_pyo3.rs +27 -0
  56. package/qtty-js/qtty/qtty-core/src/feature_serde.rs +203 -0
  57. package/qtty-js/qtty/qtty-core/src/feature_tiberius.rs +28 -0
  58. package/qtty-js/qtty/qtty-core/src/lib.rs +744 -0
  59. package/qtty-js/qtty/qtty-core/src/macros.rs +93 -0
  60. package/qtty-js/qtty/qtty-core/src/quantity.rs +810 -0
  61. package/qtty-js/qtty/qtty-core/src/scalar.rs +1742 -0
  62. package/qtty-js/qtty/qtty-core/src/unit.rs +332 -0
  63. package/qtty-js/qtty/qtty-core/src/units/angular.rs +1228 -0
  64. package/qtty-js/qtty/qtty-core/src/units/area.rs +243 -0
  65. package/qtty-js/qtty/qtty-core/src/units/frequency.rs +179 -0
  66. package/qtty-js/qtty/qtty-core/src/units/length.rs +1270 -0
  67. package/qtty-js/qtty/qtty-core/src/units/mass.rs +488 -0
  68. package/qtty-js/qtty/qtty-core/src/units/mod.rs +26 -0
  69. package/qtty-js/qtty/qtty-core/src/units/power.rs +324 -0
  70. package/qtty-js/qtty/qtty-core/src/units/time.rs +667 -0
  71. package/qtty-js/qtty/qtty-core/src/units/unitless.rs +212 -0
  72. package/qtty-js/qtty/qtty-core/src/units/velocity.rs +210 -0
  73. package/qtty-js/qtty/qtty-core/src/units/volume.rs +269 -0
  74. package/qtty-js/qtty/qtty-core/tests/core.rs +628 -0
  75. package/qtty-js/qtty/qtty-core/tests/diesel.rs +461 -0
  76. package/qtty-js/qtty/qtty-core/tests/integers.rs +632 -0
  77. package/qtty-js/qtty/qtty-core/tests/no_cross_unit_ops.rs +35 -0
  78. package/qtty-js/qtty/qtty-core/tests/pyo3.rs +334 -0
  79. package/qtty-js/qtty/qtty-core/tests/quantity_f32.rs +276 -0
  80. package/qtty-js/qtty/qtty-core/tests/scalar_decimal.rs +258 -0
  81. package/qtty-js/qtty/qtty-core/tests/scalar_f32.rs +286 -0
  82. package/qtty-js/qtty/qtty-core/tests/scalar_f64_real.rs +287 -0
  83. package/qtty-js/qtty/qtty-core/tests/scalar_rational.rs +260 -0
  84. package/qtty-js/qtty/qtty-core/tests/serde.rs +256 -0
  85. package/qtty-js/qtty/qtty-core/tests/tiberius.rs +208 -0
  86. package/qtty-js/qtty/qtty-derive/Cargo.toml +23 -0
  87. package/qtty-js/qtty/qtty-derive/README.md +8 -0
  88. package/qtty-js/qtty/qtty-derive/src/lib.rs +340 -0
  89. package/qtty-js/qtty/qtty-ffi/ARCHITECTURE.md +3 -0
  90. package/qtty-js/qtty/qtty-ffi/Cargo.toml +31 -0
  91. package/qtty-js/qtty/qtty-ffi/README.md +9 -0
  92. package/qtty-js/qtty/qtty-ffi/build.rs +326 -0
  93. package/qtty-js/qtty/qtty-ffi/cbindgen.toml +105 -0
  94. package/qtty-js/qtty/qtty-ffi/include/qtty_ffi.h +1126 -0
  95. package/qtty-js/qtty/qtty-ffi/src/ffi.rs +1251 -0
  96. package/qtty-js/qtty/qtty-ffi/src/ffi_serde.rs +294 -0
  97. package/qtty-js/qtty/qtty-ffi/src/helpers.rs +310 -0
  98. package/qtty-js/qtty/qtty-ffi/src/lib.rs +229 -0
  99. package/qtty-js/qtty/qtty-ffi/src/macros.rs +121 -0
  100. package/qtty-js/qtty/qtty-ffi/src/registry.rs +274 -0
  101. package/qtty-js/qtty/qtty-ffi/src/types.rs +620 -0
  102. package/qtty-js/qtty/qtty-ffi/tests/integration_tests.rs +842 -0
  103. package/qtty-js/qtty/qtty-ffi/units.csv +156 -0
  104. package/qtty-js/qtty/qtty-ffi/units.csv.md +3 -0
  105. package/qtty-js/qtty-node/.prettierignore +6 -0
  106. package/qtty-js/qtty-node/.prettierrc.json +6 -0
  107. package/qtty-js/qtty-node/README.md +250 -0
  108. package/qtty-js/qtty-node/c8.config.json +11 -0
  109. package/qtty-js/qtty-node/eslint.config.js +31 -0
  110. package/qtty-js/qtty-node/examples/arithmetic.mjs +64 -0
  111. package/qtty-js/qtty-node/examples/astronomy.mjs +90 -0
  112. package/qtty-js/qtty-node/examples/quickstart.mjs +36 -0
  113. package/qtty-js/qtty-node/examples/serialization.mjs +125 -0
  114. package/qtty-js/qtty-node/examples/unit_factories.mjs +74 -0
  115. package/qtty-js/qtty-node/index.d.ts +219 -0
  116. package/qtty-js/qtty-node/index.js +323 -0
  117. package/qtty-js/qtty-node/lib/DerivedQuantity.js +122 -0
  118. package/qtty-js/qtty-node/lib/Quantity.js +151 -0
  119. package/qtty-js/qtty-node/lib/backend.js +25 -0
  120. package/qtty-js/qtty-node/native.cjs +306 -0
  121. package/qtty-js/qtty-node/package-lock.json +3223 -0
  122. package/qtty-js/qtty-node/package.json +70 -0
  123. package/qtty-js/qtty-node/units.d.ts +299 -0
  124. package/qtty-js/qtty-node/units.js +210 -0
  125. package/qtty-js/qtty-web/Cargo.lock +767 -0
  126. package/qtty-js/qtty-web/Cargo.toml +21 -0
  127. package/qtty-js/qtty-web/index.d.ts +140 -0
  128. package/qtty-js/qtty-web/index.js +20 -0
  129. package/qtty-js/qtty-web/lib/DerivedQuantity.js +58 -0
  130. package/qtty-js/qtty-web/lib/Quantity.js +75 -0
  131. package/qtty-js/qtty-web/lib/backend.js +80 -0
  132. package/qtty-js/qtty-web/package.json +45 -0
  133. package/qtty-js/qtty-web/src/lib.rs +111 -0
  134. package/qtty-js/scripts/ci.sh +73 -0
  135. package/scripts/ci.sh +123 -0
  136. package/siderust-core/Cargo.lock +787 -0
  137. package/siderust-core/Cargo.toml +18 -0
  138. package/siderust-core/DEDUPLICATION.md +124 -0
  139. package/siderust-core/src/body.rs +120 -0
  140. package/siderust-core/src/events.rs +184 -0
  141. package/siderust-core/src/lib.rs +20 -0
  142. package/siderust-core/src/observer.rs +55 -0
  143. package/siderust-core/src/position.rs +213 -0
  144. package/siderust-node/.prettierignore +7 -0
  145. package/siderust-node/.prettierrc.json +6 -0
  146. package/siderust-node/Cargo.lock +906 -0
  147. package/siderust-node/Cargo.toml +29 -0
  148. package/siderust-node/README.md +109 -0
  149. package/siderust-node/__test__/index.test.mjs +248 -0
  150. package/siderust-node/build.rs +5 -0
  151. package/siderust-node/c8.config.json +3 -0
  152. package/siderust-node/eslint.config.js +31 -0
  153. package/siderust-node/examples/01_basic_coordinates.mjs +24 -0
  154. package/siderust-node/examples/02_coordinate_transformations.mjs +25 -0
  155. package/siderust-node/examples/03_all_frames_conversions.mjs +26 -0
  156. package/siderust-node/examples/04_all_center_conversions.mjs +24 -0
  157. package/siderust-node/examples/05_target_tracking.mjs +22 -0
  158. package/siderust-node/examples/06_night_events.mjs +18 -0
  159. package/siderust-node/examples/07_moon_properties.mjs +21 -0
  160. package/siderust-node/examples/08_solar_system.mjs +19 -0
  161. package/siderust-node/examples/09_star_observability.mjs +22 -0
  162. package/siderust-node/examples/10_time_periods.mjs +9 -0
  163. package/siderust-node/examples/11_serialization.mjs +31 -0
  164. package/siderust-node/examples/12_runtime_ephemeris.mjs +27 -0
  165. package/siderust-node/examples/13_coordinate_operations.mjs +20 -0
  166. package/siderust-node/index.d.ts +623 -0
  167. package/siderust-node/index.js +79 -0
  168. package/siderust-node/lib/Observer.js +112 -0
  169. package/siderust-node/lib/Star.js +118 -0
  170. package/siderust-node/lib/backend.js +63 -0
  171. package/siderust-node/lib/wrappers.js +566 -0
  172. package/siderust-node/main.js +20 -0
  173. package/siderust-node/native.cjs +360 -0
  174. package/siderust-node/package-lock.json +3261 -0
  175. package/siderust-node/package.json +71 -0
  176. package/siderust-node/src/body.rs +74 -0
  177. package/siderust-node/src/coordinates.rs +372 -0
  178. package/siderust-node/src/ephemeris.rs +462 -0
  179. package/siderust-node/src/events.rs +577 -0
  180. package/siderust-node/src/lib.rs +43 -0
  181. package/siderust-node/src/observer.rs +132 -0
  182. package/siderust-node/src/phase.rs +218 -0
  183. package/siderust-node/src/position.rs +292 -0
  184. package/siderust-node/src/star.rs +200 -0
  185. package/siderust-web/Cargo.lock +855 -0
  186. package/siderust-web/Cargo.toml +34 -0
  187. package/siderust-web/README.md +100 -0
  188. package/siderust-web/__test__/index.test.mjs +118 -0
  189. package/siderust-web/examples/github-pages/README.md +31 -0
  190. package/siderust-web/examples/github-pages/index.html +135 -0
  191. package/siderust-web/index.d.ts +311 -0
  192. package/siderust-web/index.js +66 -0
  193. package/siderust-web/lib/Observer.js +103 -0
  194. package/siderust-web/lib/Star.js +116 -0
  195. package/siderust-web/lib/backend.js +400 -0
  196. package/siderust-web/lib/wrappers.js +512 -0
  197. package/siderust-web/package.json +55 -0
  198. package/siderust-web/src/body.rs +69 -0
  199. package/siderust-web/src/coordinates.rs +302 -0
  200. package/siderust-web/src/ephemeris.rs +456 -0
  201. package/siderust-web/src/events.rs +520 -0
  202. package/siderust-web/src/lib.rs +51 -0
  203. package/siderust-web/src/observer.rs +117 -0
  204. package/siderust-web/src/phase.rs +190 -0
  205. package/siderust-web/src/position.rs +291 -0
  206. package/siderust-web/src/star.rs +178 -0
  207. package/tempoch-js/.github/workflows/ci.yml +142 -0
  208. package/tempoch-js/.gitmodules +3 -0
  209. package/tempoch-js/CHANGELOG.md +25 -0
  210. package/tempoch-js/LICENSE +661 -0
  211. package/tempoch-js/README.md +126 -0
  212. package/tempoch-js/package.json +20 -0
  213. package/tempoch-js/scripts/ci.sh +73 -0
  214. package/tempoch-js/tempoch/.github/workflows/ci.yml +113 -0
  215. package/tempoch-js/tempoch/CHANGELOG.md +82 -0
  216. package/tempoch-js/tempoch/Cargo.lock +947 -0
  217. package/tempoch-js/tempoch/Cargo.toml +3 -0
  218. package/tempoch-js/tempoch/LICENSE +661 -0
  219. package/tempoch-js/tempoch/README.md +76 -0
  220. package/tempoch-js/tempoch/tempoch/Cargo.toml +27 -0
  221. package/tempoch-js/tempoch/tempoch/examples/periods.rs +45 -0
  222. package/tempoch-js/tempoch/tempoch/examples/quickstart.rs +13 -0
  223. package/tempoch-js/tempoch/tempoch/src/lib.rs +49 -0
  224. package/tempoch-js/tempoch/tempoch/tests/integration.rs +57 -0
  225. package/tempoch-js/tempoch/tempoch-core/Cargo.toml +24 -0
  226. package/tempoch-js/tempoch/tempoch-core/src/delta_t.rs +345 -0
  227. package/tempoch-js/tempoch/tempoch-core/src/instant.rs +811 -0
  228. package/tempoch-js/tempoch/tempoch-core/src/julian_date_ext.rs +142 -0
  229. package/tempoch-js/tempoch/tempoch-core/src/lib.rs +81 -0
  230. package/tempoch-js/tempoch/tempoch-core/src/period.rs +1168 -0
  231. package/tempoch-js/tempoch/tempoch-core/src/scales.rs +779 -0
  232. package/tempoch-js/tempoch/tempoch-ffi/Cargo.lock +889 -0
  233. package/tempoch-js/tempoch/tempoch-ffi/Cargo.toml +26 -0
  234. package/tempoch-js/tempoch/tempoch-ffi/build.rs +24 -0
  235. package/tempoch-js/tempoch/tempoch-ffi/cbindgen.toml +30 -0
  236. package/tempoch-js/tempoch/tempoch-ffi/src/error.rs +19 -0
  237. package/tempoch-js/tempoch/tempoch-ffi/src/lib.rs +82 -0
  238. package/tempoch-js/tempoch/tempoch-ffi/src/period.rs +101 -0
  239. package/tempoch-js/tempoch/tempoch-ffi/src/time.rs +711 -0
  240. package/tempoch-js/tempoch/tempoch-ffi/tests/ffi.rs +265 -0
  241. package/tempoch-js/tempoch-node/.prettierignore +6 -0
  242. package/tempoch-js/tempoch-node/.prettierrc.json +6 -0
  243. package/tempoch-js/tempoch-node/Cargo.lock +496 -0
  244. package/tempoch-js/tempoch-node/Cargo.toml +29 -0
  245. package/tempoch-js/tempoch-node/README.md +265 -0
  246. package/tempoch-js/tempoch-node/__test__/index.test.mjs +598 -0
  247. package/tempoch-js/tempoch-node/build.rs +5 -0
  248. package/tempoch-js/tempoch-node/c8.config.json +3 -0
  249. package/tempoch-js/tempoch-node/eslint.config.js +31 -0
  250. package/tempoch-js/tempoch-node/examples/periods.mjs +79 -0
  251. package/tempoch-js/tempoch-node/examples/quickstart.mjs +71 -0
  252. package/tempoch-js/tempoch-node/examples/timescales.mjs +92 -0
  253. package/tempoch-js/tempoch-node/index.d.ts +280 -0
  254. package/tempoch-js/tempoch-node/index.js +32 -0
  255. package/tempoch-js/tempoch-node/lib/JulianDate.js +176 -0
  256. package/tempoch-js/tempoch-node/lib/ModifiedJulianDate.js +156 -0
  257. package/tempoch-js/tempoch-node/lib/Period.js +133 -0
  258. package/tempoch-js/tempoch-node/lib/backend.js +38 -0
  259. package/tempoch-js/tempoch-node/lib/qttyCompat.js +92 -0
  260. package/tempoch-js/tempoch-node/native.cjs +317 -0
  261. package/tempoch-js/tempoch-node/package-lock.json +3223 -0
  262. package/tempoch-js/tempoch-node/package.json +56 -0
  263. package/tempoch-js/tempoch-node/src/lib.rs +573 -0
  264. package/tempoch-js/tempoch-web/Cargo.toml +23 -0
  265. package/tempoch-js/tempoch-web/index.d.ts +95 -0
  266. package/tempoch-js/tempoch-web/index.js +27 -0
  267. package/tempoch-js/tempoch-web/lib/JulianDate.js +170 -0
  268. package/tempoch-js/tempoch-web/lib/ModifiedJulianDate.js +145 -0
  269. package/tempoch-js/tempoch-web/lib/Period.js +121 -0
  270. package/tempoch-js/tempoch-web/lib/backend.js +118 -0
  271. package/tempoch-js/tempoch-web/package.json +46 -0
  272. package/tempoch-js/tempoch-web/src/lib.rs +184 -0
@@ -0,0 +1,212 @@
1
+ //! Dimensionless helpers.
2
+ //!
3
+ //! This module contains small adapters for working with dimensionless values.
4
+ //!
5
+ //! The provided conversion from a dimensioned quantity to a unitless quantity is *lossy*: it drops the unit type
6
+ //! without performing any normalization. The numeric value is preserved as-is.
7
+ //!
8
+ //! ```rust
9
+ //! use qtty_core::time::Seconds;
10
+ //! use qtty_core::{Quantity, Unitless};
11
+ //!
12
+ //! let t = Seconds::new(3.0);
13
+ //! let u: Quantity<Unitless> = t.into();
14
+ //! assert_eq!(u.value(), 3.0);
15
+ //! ```
16
+
17
+ use crate::dimension::{
18
+ Acceleration, AmountOfSubstance, Angular, Area, Current, Energy, Force, FrequencyDim, Length,
19
+ LuminousIntensity, Mass, Power, Temperature, Time, VelocityDim, Volume,
20
+ };
21
+ use crate::scalar::Scalar;
22
+ use crate::{Quantity, Unit, Unitless};
23
+
24
+ trait SupportedDimension {}
25
+ impl SupportedDimension for Length {}
26
+ impl SupportedDimension for Time {}
27
+ impl SupportedDimension for Mass {}
28
+ impl SupportedDimension for Temperature {}
29
+ impl SupportedDimension for Current {}
30
+ impl SupportedDimension for AmountOfSubstance {}
31
+ impl SupportedDimension for LuminousIntensity {}
32
+ impl SupportedDimension for Angular {}
33
+ impl SupportedDimension for Area {}
34
+ impl SupportedDimension for Volume {}
35
+ impl SupportedDimension for VelocityDim {}
36
+ impl SupportedDimension for Acceleration {}
37
+ impl SupportedDimension for Force {}
38
+ impl SupportedDimension for Energy {}
39
+ impl SupportedDimension for Power {}
40
+ impl SupportedDimension for FrequencyDim {}
41
+
42
+ trait DimensionedUnit: Unit {}
43
+ impl<U: Unit> DimensionedUnit for U where U::Dim: SupportedDimension {}
44
+
45
+ impl<U: DimensionedUnit, S: Scalar> From<Quantity<U, S>> for Quantity<Unitless, S> {
46
+ #[inline]
47
+ fn from(quantity: Quantity<U, S>) -> Self {
48
+ Self::new(quantity.value())
49
+ }
50
+ }
51
+
52
+ #[cfg(test)]
53
+ mod tests {
54
+ use super::*;
55
+ use crate::units::angular::Degrees;
56
+ use crate::units::length::Meters;
57
+ use crate::units::mass::Kilogram;
58
+ use crate::units::mass::Kilograms;
59
+ use crate::units::time::Seconds;
60
+ use crate::Unit;
61
+ use approx::assert_abs_diff_eq;
62
+ use proptest::prelude::*;
63
+
64
+ // ─────────────────────────────────────────────────────────────────────────────
65
+ // Basic Unitless behavior
66
+ // ─────────────────────────────────────────────────────────────────────────────
67
+
68
+ #[test]
69
+ fn unitless_new_and_value() {
70
+ let u: Quantity<Unitless> = Quantity::new(42.0);
71
+ assert_eq!(u.value(), 42.0);
72
+ }
73
+
74
+ #[test]
75
+ fn unitless_from_f64() {
76
+ let u: Quantity<Unitless> = 1.23456.into();
77
+ assert_abs_diff_eq!(u.value(), 1.23456, epsilon = 1e-12);
78
+ }
79
+
80
+ // ─────────────────────────────────────────────────────────────────────────────
81
+ // Display formatting
82
+ // ─────────────────────────────────────────────────────────────────────────────
83
+
84
+ #[test]
85
+ fn display_unitless() {
86
+ let u: Quantity<Unitless> = Quantity::new(123.456);
87
+ let s = format!("{}", u);
88
+ assert_eq!(s, "123.456");
89
+ }
90
+
91
+ #[test]
92
+ fn display_unitless_integer() {
93
+ let u: Quantity<Unitless> = Quantity::new(42.0);
94
+ let s = format!("{}", u);
95
+ assert_eq!(s, "42");
96
+ }
97
+
98
+ // ─────────────────────────────────────────────────────────────────────────────
99
+ // Conversion from dimensioned quantities
100
+ // ─────────────────────────────────────────────────────────────────────────────
101
+
102
+ #[test]
103
+ fn from_length() {
104
+ let m = Meters::new(42.0);
105
+ let u: Quantity<Unitless> = m.into();
106
+ assert_eq!(u.value(), 42.0);
107
+ }
108
+
109
+ #[test]
110
+ fn from_time() {
111
+ let t = Seconds::new(5.0);
112
+ let u: Quantity<Unitless> = t.into();
113
+ assert_eq!(u.value(), 5.0);
114
+ }
115
+
116
+ #[test]
117
+ fn from_mass() {
118
+ let m = Kilograms::new(2.5);
119
+ let u: Quantity<Unitless> = m.into();
120
+ assert_eq!(u.value(), 2.5);
121
+ }
122
+
123
+ #[test]
124
+ fn from_angular() {
125
+ let a = Degrees::new(90.0);
126
+ let u: Quantity<Unitless> = a.into();
127
+ assert_eq!(u.value(), 90.0);
128
+ }
129
+
130
+ #[test]
131
+ fn from_mass_preserves_non_default_scalar_type() {
132
+ let m: Quantity<Kilogram, i32> = Quantity::new(7);
133
+ let u: Quantity<Unitless, i32> = m.into();
134
+ assert_eq!(u.value(), 7);
135
+ }
136
+
137
+ // ─────────────────────────────────────────────────────────────────────────────
138
+ // Arithmetic operations
139
+ // ─────────────────────────────────────────────────────────────────────────────
140
+
141
+ #[test]
142
+ fn unitless_addition() {
143
+ let a: Quantity<Unitless> = Quantity::new(3.0);
144
+ let b: Quantity<Unitless> = Quantity::new(4.0);
145
+ assert_eq!((a + b).value(), 7.0);
146
+ }
147
+
148
+ #[test]
149
+ fn unitless_subtraction() {
150
+ let a: Quantity<Unitless> = Quantity::new(10.0);
151
+ let b: Quantity<Unitless> = Quantity::new(3.0);
152
+ assert_eq!((a - b).value(), 7.0);
153
+ }
154
+
155
+ #[test]
156
+ fn unitless_multiplication() {
157
+ let a: Quantity<Unitless> = Quantity::new(3.0);
158
+ assert_eq!((a * 4.0).value(), 12.0);
159
+ }
160
+
161
+ #[test]
162
+ fn unitless_division() {
163
+ let a: Quantity<Unitless> = Quantity::new(12.0);
164
+ assert_eq!((a / 4.0).value(), 3.0);
165
+ }
166
+
167
+ // ─────────────────────────────────────────────────────────────────────────────
168
+ // Unit trait implementation
169
+ // ─────────────────────────────────────────────────────────────────────────────
170
+
171
+ #[test]
172
+ fn unitless_ratio() {
173
+ assert_eq!(Unitless::RATIO, 1.0);
174
+ }
175
+
176
+ #[test]
177
+ fn unitless_symbol() {
178
+ assert_eq!(Unitless::SYMBOL, "");
179
+ }
180
+
181
+ // ─────────────────────────────────────────────────────────────────────────────
182
+ // Property-based tests
183
+ // ─────────────────────────────────────────────────────────────────────────────
184
+
185
+ proptest! {
186
+ #[test]
187
+ fn prop_unitless_arithmetic(a in -1e6..1e6f64, b in -1e6..1e6f64) {
188
+ let qa: Quantity<Unitless> = Quantity::new(a);
189
+ let qb: Quantity<Unitless> = Quantity::new(b);
190
+
191
+ // Addition is commutative
192
+ prop_assert!((((qa + qb).value() - (qb + qa).value()).abs() < 1e-9));
193
+
194
+ // Value is preserved
195
+ prop_assert!(((qa + qb).value() - (a + b)).abs() < 1e-9);
196
+ }
197
+
198
+ #[test]
199
+ fn prop_from_length_preserves_value(v in -1e6..1e6f64) {
200
+ let m = Meters::new(v);
201
+ let u: Quantity<Unitless> = m.into();
202
+ prop_assert!((u.value() - v).abs() < 1e-12);
203
+ }
204
+
205
+ #[test]
206
+ fn prop_from_time_preserves_value(v in -1e6..1e6f64) {
207
+ let t = Seconds::new(v);
208
+ let u: Quantity<Unitless> = t.into();
209
+ prop_assert!((u.value() - v).abs() < 1e-12);
210
+ }
211
+ }
212
+ }
@@ -0,0 +1,210 @@
1
+ //! Velocity unit aliases (`Length / Time`).
2
+ //!
3
+ //! This module defines velocity units as *pure type aliases* over [`Per`] using
4
+ //! length and time units already defined elsewhere in the crate.
5
+ //!
6
+ //! No standalone velocity units are introduced: every velocity is represented as
7
+ //! `Length / Time` at the type level.
8
+ //!
9
+ //! ## Design notes
10
+ //!
11
+ //! - The velocity *dimension* is [`Velocity`] = [`Length`] / [`Time`].
12
+ //! - All velocity units are zero-cost type aliases.
13
+ //! - Conversions are handled automatically via the underlying length and time units.
14
+ //! - No assumptions are made about reference frames, relativistic effects, or media.
15
+ //!
16
+ //! ## Examples
17
+ //!
18
+ //! ```rust
19
+ //! use qtty_core::length::{Kilometer, Kilometers};
20
+ //! use qtty_core::time::{Second, Seconds};
21
+ //! use qtty_core::velocity::Velocity;
22
+ //!
23
+ //! let d = Kilometers::new(42.0);
24
+ //! let t = Seconds::new(2.0);
25
+ //! let v: Velocity<Kilometer, Second> = d / t;
26
+ //! assert!((v.value() - 21.0).abs() < 1e-12);
27
+ //! ```
28
+ //!
29
+ //! ```rust
30
+ //! use qtty_core::length::{Meter, Meters};
31
+ //! use qtty_core::time::{Hour, Hours};
32
+ //! use qtty_core::velocity::Velocity;
33
+ //!
34
+ //! let v: Velocity<Meter, Hour> = Meters::new(3_600.0) / Hours::new(1.0);
35
+ //! assert!((v.value() - 3_600.0).abs() < 1e-12);
36
+ //! ```
37
+
38
+ use crate::{Per, Quantity, Unit};
39
+
40
+ /// Re-export the velocity dimension from the dimension module.
41
+ pub use crate::dimension::VelocityDim;
42
+
43
+ /// Marker trait for any unit whose dimension is [`VelocityDim`].
44
+ pub trait VelocityUnit: Unit<Dim = VelocityDim> {}
45
+ impl<T: Unit<Dim = VelocityDim>> VelocityUnit for T {}
46
+
47
+ /// A velocity quantity parameterized by length and time units.
48
+ ///
49
+ /// # Examples
50
+ ///
51
+ /// ```rust
52
+ /// use qtty_core::length::{Kilometer, Meter};
53
+ /// use qtty_core::time::{Second, Hour};
54
+ /// use qtty_core::velocity::Velocity;
55
+ ///
56
+ /// let v1: Velocity<Meter, Second> = Velocity::new(10.0);
57
+ /// let v2: Velocity<Kilometer, Hour> = Velocity::new(36.0);
58
+ /// ```
59
+ pub type Velocity<N, D> = Quantity<Per<N, D>>;
60
+
61
+ #[cfg(test)]
62
+ mod tests {
63
+ use super::*;
64
+ use crate::units::length::{Au, Kilometer, Kilometers, Meter};
65
+ use crate::units::time::{Day, Hour, Second, Seconds};
66
+ use crate::Per;
67
+ use approx::{assert_abs_diff_eq, assert_relative_eq};
68
+ use proptest::prelude::*;
69
+
70
+ // ─────────────────────────────────────────────────────────────────────────────
71
+ // Basic velocity conversions
72
+ // ─────────────────────────────────────────────────────────────────────────────
73
+
74
+ #[test]
75
+ fn km_per_s_to_m_per_s() {
76
+ let v: Velocity<Kilometer, Second> = Velocity::new(1.0);
77
+ let v_mps: Velocity<Meter, Second> = v.to();
78
+ assert_abs_diff_eq!(v_mps.value(), 1000.0, epsilon = 1e-9);
79
+ }
80
+
81
+ #[test]
82
+ fn m_per_s_to_km_per_s() {
83
+ let v: Velocity<Meter, Second> = Velocity::new(1000.0);
84
+ let v_kps: Velocity<Kilometer, Second> = v.to();
85
+ assert_abs_diff_eq!(v_kps.value(), 1.0, epsilon = 1e-12);
86
+ }
87
+
88
+ #[test]
89
+ fn km_per_h_to_m_per_s() {
90
+ let v: Velocity<Kilometer, Hour> = Velocity::new(3.6);
91
+ let v_mps: Velocity<Meter, Second> = v.to();
92
+ // 3.6 km/h = 1 m/s
93
+ assert_abs_diff_eq!(v_mps.value(), 1.0, epsilon = 1e-12);
94
+ }
95
+
96
+ #[test]
97
+ fn km_per_h_to_km_per_s() {
98
+ let v: Velocity<Kilometer, Hour> = Velocity::new(3600.0);
99
+ let v_kps: Velocity<Kilometer, Second> = v.to();
100
+ // 3600 km/h = 1 km/s
101
+ assert_abs_diff_eq!(v_kps.value(), 1.0, epsilon = 1e-12);
102
+ }
103
+
104
+ #[test]
105
+ fn au_per_day_to_km_per_s() {
106
+ let v: Velocity<Au, Day> = Velocity::new(1.0);
107
+ let v_kps: Velocity<Kilometer, Second> = v.to();
108
+ // 1 AU/day = 149,597,870.7 km / 86400 s ≈ 1731.5 km/s
109
+ assert_relative_eq!(v_kps.value(), 1731.5, max_relative = 1e-3);
110
+ }
111
+
112
+ // ─────────────────────────────────────────────────────────────────────────────
113
+ // Per ratio behavior
114
+ // ─────────────────────────────────────────────────────────────────────────────
115
+
116
+ #[test]
117
+ fn per_ratio_km_s() {
118
+ // Per<Kilometer, Second> should have RATIO = 1000 / 1 = 1000
119
+ let ratio = <Per<Kilometer, Second>>::RATIO;
120
+ // Kilometer::RATIO = 1000, Second::RATIO = 1.0
121
+ // So Per ratio = 1000 / 1.0 = 1000
122
+ assert_relative_eq!(ratio, 1000.0, max_relative = 1e-12);
123
+ }
124
+
125
+ #[test]
126
+ fn per_ratio_m_s() {
127
+ // Per<Meter, Second> has RATIO = 1 / 1 = 1
128
+ let ratio = <Per<Meter, Second>>::RATIO;
129
+ assert_relative_eq!(ratio, 1.0, max_relative = 1e-12);
130
+ }
131
+
132
+ // ─────────────────────────────────────────────────────────────────────────────
133
+ // Velocity * Time = Length
134
+ // ─────────────────────────────────────────────────────────────────────────────
135
+
136
+ #[test]
137
+ fn velocity_times_time() {
138
+ let v: Velocity<Kilometer, Second> = Velocity::new(10.0);
139
+ let t: Seconds = Seconds::new(5.0);
140
+ let d: Kilometers = (v * t).to();
141
+ assert_abs_diff_eq!(d.value(), 50.0, epsilon = 1e-9);
142
+ }
143
+
144
+ #[test]
145
+ fn time_times_velocity() {
146
+ let v: Velocity<Kilometer, Second> = Velocity::new(10.0);
147
+ let t: Seconds = Seconds::new(5.0);
148
+ let d: Kilometers = (t * v).to();
149
+ assert_abs_diff_eq!(d.value(), 50.0, epsilon = 1e-9);
150
+ }
151
+
152
+ // ─────────────────────────────────────────────────────────────────────────────
153
+ // Length / Time = Velocity
154
+ // ─────────────────────────────────────────────────────────────────────────────
155
+
156
+ #[test]
157
+ fn length_div_time() {
158
+ let d: Kilometers = Kilometers::new(100.0);
159
+ let t: Seconds = Seconds::new(10.0);
160
+ let v: Velocity<Kilometer, Second> = d / t;
161
+ assert_abs_diff_eq!(v.value(), 10.0, epsilon = 1e-9);
162
+ }
163
+
164
+ // ─────────────────────────────────────────────────────────────────────────────
165
+ // Roundtrip conversions
166
+ // ─────────────────────────────────────────────────────────────────────────────
167
+
168
+ #[test]
169
+ fn roundtrip_mps_kps() {
170
+ let original: Velocity<Meter, Second> = Velocity::new(500.0);
171
+ let converted: Velocity<Kilometer, Second> = original.to();
172
+ let back: Velocity<Meter, Second> = converted.to();
173
+ assert_abs_diff_eq!(back.value(), original.value(), epsilon = 1e-9);
174
+ }
175
+
176
+ // ─────────────────────────────────────────────────────────────────────────────
177
+ // Property-based tests
178
+ // ─────────────────────────────────────────────────────────────────────────────
179
+
180
+ proptest! {
181
+ #[test]
182
+ fn prop_roundtrip_mps_kps(v in 1e-6..1e6f64) {
183
+ let original: Velocity<Meter, Second> = Velocity::new(v);
184
+ let converted: Velocity<Kilometer, Second> = original.to();
185
+ let back: Velocity<Meter, Second> = converted.to();
186
+ prop_assert!((back.value() - original.value()).abs() < 1e-9 * v.abs().max(1.0));
187
+ }
188
+
189
+ #[test]
190
+ fn prop_mps_kps_ratio(v in 1e-6..1e6f64) {
191
+ let mps: Velocity<Meter, Second> = Velocity::new(v);
192
+ let kps: Velocity<Kilometer, Second> = mps.to();
193
+ // 1000 m/s = 1 km/s
194
+ prop_assert!((mps.value() / kps.value() - 1000.0).abs() < 1e-9);
195
+ }
196
+
197
+ #[test]
198
+ fn prop_velocity_time_roundtrip(
199
+ v_val in 1e-3..1e3f64,
200
+ t_val in 1e-3..1e3f64
201
+ ) {
202
+ let v: Velocity<Kilometer, Second> = Velocity::new(v_val);
203
+ let t: Seconds = Seconds::new(t_val);
204
+ let d: Kilometers = (v * t).to();
205
+ // d / t should give back v
206
+ let v_back: Velocity<Kilometer, Second> = d / t;
207
+ prop_assert!((v_back.value() - v.value()).abs() / v.value() < 1e-12);
208
+ }
209
+ }
210
+ }
@@ -0,0 +1,269 @@
1
+ //! Volume units.
2
+ //!
3
+ //! The canonical scaling unit for this dimension is the **cubic metre** (`CubicMeter::RATIO == 1.0`).
4
+ //! All other volume units are expressed as exact ratios to cubic metres.
5
+ //!
6
+ //! This module provides:
7
+ //!
8
+ //! - **Metric cubes**: cubic millimetre, cubic centimetre, cubic metre, cubic kilometre.
9
+ //! - **Litre family**: microlitre, millilitre, centilitre, decilitre, litre.
10
+ //! - **Imperial/US**: cubic inch, cubic foot, US gallon, US fluid ounce.
11
+ //!
12
+ //! Volume units can also arise *automatically* from multiplying length × area quantities:
13
+ //!
14
+ //! ```rust
15
+ //! use qtty_core::length::{Meter, Meters};
16
+ //! use qtty_core::area::{SquareMeter, SquareMeters};
17
+ //! use qtty_core::volume::{CubicMeters, CubicMeter};
18
+ //! use qtty_core::Prod;
19
+ //!
20
+ //! let side = Meters::new(3.0);
21
+ //! let face: SquareMeters = (side * side).to();
22
+ //! let vol_prod = face * side; // Quantity<Prod<SquareMeter, Meter>>
23
+ //! let vol: CubicMeters = vol_prod.to();
24
+ //! assert!((vol.value() - 27.0).abs() < 1e-12);
25
+ //! ```
26
+ //!
27
+ //! ## All volume units
28
+ //!
29
+ //! ```rust
30
+ //! use qtty_core::volume::*;
31
+ //!
32
+ //! macro_rules! touch {
33
+ //! ($T:ty, $v:expr) => {{ let q = <$T>::new($v); let _c = q; assert!(q == q); }};
34
+ //! }
35
+ //!
36
+ //! touch!(CubicMeters, 1.0); touch!(CubicKilometers, 1.0);
37
+ //! touch!(CubicCentimeters, 1.0); touch!(CubicMillimeters, 1.0);
38
+ //! touch!(Liters, 1.0); touch!(Milliliters, 1.0);
39
+ //! touch!(Microliters, 1.0); touch!(Centiliters, 1.0);
40
+ //! touch!(Deciliters, 1.0); touch!(CubicInches, 1.0);
41
+ //! touch!(CubicFeet, 1.0); touch!(UsGallons, 1.0);
42
+ //! touch!(UsFluidOunces, 1.0);
43
+ //! ```
44
+
45
+ use crate::{Quantity, Unit};
46
+ use qtty_derive::Unit;
47
+
48
+ /// Re-export the volume dimension from the dimension module.
49
+ pub use crate::dimension::Volume;
50
+
51
+ /// Marker trait for any [`Unit`] whose dimension is [`Volume`].
52
+ pub trait VolumeUnit: Unit<Dim = Volume> {}
53
+ impl<T: Unit<Dim = Volume>> VolumeUnit for T {}
54
+
55
+ // ─────────────────────────────────────────────────────────────────────────────
56
+ // SI / metric volume units
57
+ // ─────────────────────────────────────────────────────────────────────────────
58
+
59
+ /// Cubic metre (SI derived unit of volume).
60
+ #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
61
+ #[unit(symbol = "m³", dimension = Volume, ratio = 1.0)]
62
+ pub struct CubicMeter;
63
+ /// A quantity measured in cubic metres.
64
+ pub type CubicMeters = Quantity<CubicMeter>;
65
+
66
+ /// Cubic kilometre (`1e9 m³`).
67
+ #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
68
+ #[unit(symbol = "km³", dimension = Volume, ratio = 1e9)]
69
+ pub struct CubicKilometer;
70
+ /// A quantity measured in cubic kilometres.
71
+ pub type CubicKilometers = Quantity<CubicKilometer>;
72
+
73
+ /// Cubic centimetre (`1e-6 m³`).
74
+ #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
75
+ #[unit(symbol = "cm³", dimension = Volume, ratio = 1e-6)]
76
+ pub struct CubicCentimeter;
77
+ /// A quantity measured in cubic centimetres.
78
+ pub type CubicCentimeters = Quantity<CubicCentimeter>;
79
+
80
+ /// Cubic millimetre (`1e-9 m³`).
81
+ #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
82
+ #[unit(symbol = "mm³", dimension = Volume, ratio = 1e-9)]
83
+ pub struct CubicMillimeter;
84
+ /// A quantity measured in cubic millimetres.
85
+ pub type CubicMillimeters = Quantity<CubicMillimeter>;
86
+
87
+ // ─────────────────────────────────────────────────────────────────────────────
88
+ // Litre family
89
+ // ─────────────────────────────────────────────────────────────────────────────
90
+
91
+ /// Litre (`1e-3 m³`, exact).
92
+ #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
93
+ #[unit(symbol = "L", dimension = Volume, ratio = 1e-3)]
94
+ pub struct Liter;
95
+ /// A quantity measured in litres.
96
+ pub type Liters = Quantity<Liter>;
97
+
98
+ /// Millilitre (`1e-6 m³`, exact).
99
+ #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
100
+ #[unit(symbol = "mL", dimension = Volume, ratio = 1e-6)]
101
+ pub struct Milliliter;
102
+ /// A quantity measured in millilitres.
103
+ pub type Milliliters = Quantity<Milliliter>;
104
+
105
+ /// Microlitre (`1e-9 m³`, exact).
106
+ #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
107
+ #[unit(symbol = "µL", dimension = Volume, ratio = 1e-9)]
108
+ pub struct Microliter;
109
+ /// A quantity measured in microlitres.
110
+ pub type Microliters = Quantity<Microliter>;
111
+
112
+ /// Centilitre (`1e-5 m³`, exact).
113
+ #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
114
+ #[unit(symbol = "cL", dimension = Volume, ratio = 1e-5)]
115
+ pub struct Centiliter;
116
+ /// A quantity measured in centilitres.
117
+ pub type Centiliters = Quantity<Centiliter>;
118
+
119
+ /// Decilitre (`1e-4 m³`, exact).
120
+ #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
121
+ #[unit(symbol = "dL", dimension = Volume, ratio = 1e-4)]
122
+ pub struct Deciliter;
123
+ /// A quantity measured in decilitres.
124
+ pub type Deciliters = Quantity<Deciliter>;
125
+
126
+ // ─────────────────────────────────────────────────────────────────────────────
127
+ // Imperial / US customary volume units
128
+ // ─────────────────────────────────────────────────────────────────────────────
129
+
130
+ /// Cubic inch (`1.6387064e-5 m³`, exact: `0.0254³ m³`).
131
+ #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
132
+ #[unit(symbol = "in³", dimension = Volume, ratio = 1.638_706_4e-5)]
133
+ pub struct CubicInch;
134
+ /// A quantity measured in cubic inches.
135
+ pub type CubicInches = Quantity<CubicInch>;
136
+
137
+ /// Cubic foot (`0.028316846592 m³`, exact: `0.3048³ m³`).
138
+ #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
139
+ #[unit(symbol = "ft³", dimension = Volume, ratio = 0.028_316_846_592)]
140
+ pub struct CubicFoot;
141
+ /// A quantity measured in cubic feet.
142
+ pub type CubicFeet = Quantity<CubicFoot>;
143
+
144
+ /// US liquid gallon (`0.003785411784 m³`, exact: `231 in³`).
145
+ #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
146
+ #[unit(symbol = "gal", dimension = Volume, ratio = 0.003_785_411_784)]
147
+ pub struct UsGallon;
148
+ /// A quantity measured in US gallons.
149
+ pub type UsGallons = Quantity<UsGallon>;
150
+
151
+ /// US fluid ounce (`2.95735295625e-5 m³`, exact: `gal / 128`).
152
+ #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
153
+ #[unit(symbol = "fl oz", dimension = Volume, ratio = 2.957_352_956_25e-5)]
154
+ pub struct UsFluidOunce;
155
+ /// A quantity measured in US fluid ounces.
156
+ pub type UsFluidOunces = Quantity<UsFluidOunce>;
157
+
158
+ #[cfg(test)]
159
+ mod tests {
160
+ use super::*;
161
+ use approx::assert_abs_diff_eq;
162
+
163
+ #[test]
164
+ fn liter_to_cubic_meter() {
165
+ let l = Liters::new(1.0);
166
+ let m: CubicMeters = l.to();
167
+ assert_abs_diff_eq!(m.value(), 0.001, epsilon = 1e-15);
168
+ }
169
+
170
+ #[test]
171
+ fn milliliter_to_liter() {
172
+ let ml = Milliliters::new(1000.0);
173
+ let l: Liters = ml.to();
174
+ assert_abs_diff_eq!(l.value(), 1.0, epsilon = 1e-12);
175
+ }
176
+
177
+ #[test]
178
+ fn cubic_cm_to_ml() {
179
+ let cc = CubicCentimeters::new(1.0);
180
+ let ml: Milliliters = cc.to();
181
+ assert_abs_diff_eq!(ml.value(), 1.0, epsilon = 1e-12);
182
+ }
183
+
184
+ #[test]
185
+ fn us_gallon_to_liter() {
186
+ let g = UsGallons::new(1.0);
187
+ let l: Liters = g.to();
188
+ assert_abs_diff_eq!(l.value(), 3.785_411_784, epsilon = 1e-6);
189
+ }
190
+
191
+ #[test]
192
+ fn cubic_foot_to_liter() {
193
+ let cf = CubicFeet::new(1.0);
194
+ let l: Liters = cf.to();
195
+ assert_abs_diff_eq!(l.value(), 28.316_846_592, epsilon = 1e-6);
196
+ }
197
+
198
+ #[test]
199
+ fn length_times_area_to_volume() {
200
+ use crate::area::{SquareMeter, SquareMeters};
201
+ use crate::length::{Meter, Meters};
202
+ use crate::Prod;
203
+
204
+ let side = Meters::new(3.0);
205
+ let face: SquareMeters = (side * side).to();
206
+ let vol_prod: Quantity<Prod<SquareMeter, Meter>> = face * side;
207
+ let vol: CubicMeters = vol_prod.to();
208
+ assert_abs_diff_eq!(vol.value(), 27.0, epsilon = 1e-12);
209
+ }
210
+
211
+ #[test]
212
+ fn cubic_km_to_liter() {
213
+ let ckm = CubicKilometers::new(1.0);
214
+ let l: Liters = ckm.to();
215
+ assert_abs_diff_eq!(l.value(), 1e12, epsilon = 1e3);
216
+ }
217
+
218
+ #[test]
219
+ fn cubic_mm_to_cubic_cm() {
220
+ let mm3 = CubicMillimeters::new(1000.0);
221
+ let cm3: CubicCentimeters = mm3.to();
222
+ assert_abs_diff_eq!(cm3.value(), 1.0, epsilon = 1e-12);
223
+ }
224
+
225
+ #[test]
226
+ fn microliter_to_milliliter() {
227
+ let ul = Microliters::new(1000.0);
228
+ let ml: Milliliters = ul.to();
229
+ assert_abs_diff_eq!(ml.value(), 1.0, epsilon = 1e-12);
230
+ }
231
+
232
+ #[test]
233
+ fn centiliter_to_liter() {
234
+ let cl = Centiliters::new(100.0);
235
+ let l: Liters = cl.to();
236
+ assert_abs_diff_eq!(l.value(), 1.0, epsilon = 1e-12);
237
+ }
238
+
239
+ #[test]
240
+ fn deciliter_to_liter() {
241
+ let dl = Deciliters::new(10.0);
242
+ let l: Liters = dl.to();
243
+ assert_abs_diff_eq!(l.value(), 1.0, epsilon = 1e-12);
244
+ }
245
+
246
+ #[test]
247
+ fn cubic_inch_to_cubic_cm() {
248
+ let cin = CubicInches::new(1.0);
249
+ let cc: CubicCentimeters = cin.to();
250
+ // 1 in³ = 16.387064 cm³
251
+ assert_abs_diff_eq!(cc.value(), 16.387_064, epsilon = 1e-4);
252
+ }
253
+
254
+ #[test]
255
+ fn us_fluid_ounce_to_milliliter() {
256
+ let floz = UsFluidOunces::new(1.0);
257
+ let ml: Milliliters = floz.to();
258
+ // 1 US fl oz ≈ 29.5735 mL
259
+ assert_abs_diff_eq!(ml.value(), 29.573_529_562_5, epsilon = 1e-6);
260
+ }
261
+
262
+ #[test]
263
+ fn symbols_are_correct() {
264
+ assert_eq!(CubicMeter::SYMBOL, "m³");
265
+ assert_eq!(Liter::SYMBOL, "L");
266
+ assert_eq!(Milliliter::SYMBOL, "mL");
267
+ assert_eq!(UsGallon::SYMBOL, "gal");
268
+ }
269
+ }