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.
- package/.github/workflows/ci.yml +166 -0
- package/.gitmodules +9 -0
- package/CHANGELOG.md +26 -0
- package/LICENSE +661 -0
- package/README.md +138 -0
- package/package.json +12 -0
- package/qtty-js/.github/workflows/ci.yml +151 -0
- package/qtty-js/.gitmodules +3 -0
- package/qtty-js/CHANGELOG.md +31 -0
- package/qtty-js/LICENSE +661 -0
- package/qtty-js/README.md +132 -0
- package/qtty-js/package.json +20 -0
- package/qtty-js/qtty/.github/workflows/ci.yml +155 -0
- package/qtty-js/qtty/CHANGELOG.md +120 -0
- package/qtty-js/qtty/Cargo.lock +1462 -0
- package/qtty-js/qtty/Cargo.toml +12 -0
- package/qtty-js/qtty/LICENSE +661 -0
- package/qtty-js/qtty/README.md +9 -0
- package/qtty-js/qtty/qtty/Cargo.toml +41 -0
- package/qtty-js/qtty/qtty/README.md +8 -0
- package/qtty-js/qtty/qtty/examples/angles.rs +14 -0
- package/qtty-js/qtty/qtty/examples/astronomy.rs +17 -0
- package/qtty-js/qtty/qtty/examples/dimensional_arithmetic.rs +83 -0
- package/qtty-js/qtty/qtty/examples/python_integration.rs +61 -0
- package/qtty-js/qtty/qtty/examples/quickstart.rs +15 -0
- package/qtty-js/qtty/qtty/examples/ratios.rs +12 -0
- package/qtty-js/qtty/qtty/examples/serde_with_unit.rs +234 -0
- package/qtty-js/qtty/qtty/examples/serialization.rs +141 -0
- package/qtty-js/qtty/qtty/examples/serialization_advanced.rs +155 -0
- package/qtty-js/qtty/qtty/src/f32.rs +108 -0
- package/qtty-js/qtty/qtty/src/f64.rs +30 -0
- package/qtty-js/qtty/qtty/src/i128.rs +111 -0
- package/qtty-js/qtty/qtty/src/i16.rs +111 -0
- package/qtty-js/qtty/qtty/src/i32.rs +111 -0
- package/qtty-js/qtty/qtty/src/i64.rs +111 -0
- package/qtty-js/qtty/qtty/src/i8.rs +111 -0
- package/qtty-js/qtty/qtty/src/lib.rs +238 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std/Cargo.lock +83 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std/Cargo.toml +10 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std/src/lib.rs +7 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std-alloc/Cargo.lock +83 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std-alloc/Cargo.toml +10 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std-alloc/src/lib.rs +7 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-std/Cargo.lock +83 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-std/Cargo.toml +10 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-std/src/lib.rs +5 -0
- package/qtty-js/qtty/qtty/tests/integration_tests.rs +529 -0
- package/qtty-js/qtty/qtty/tests/qtty_vec_feature_matrix.rs +58 -0
- package/qtty-js/qtty/qtty-core/Cargo.toml +41 -0
- package/qtty-js/qtty/qtty-core/README.md +8 -0
- package/qtty-js/qtty/qtty-core/examples/diesel_integration.rs +145 -0
- package/qtty-js/qtty/qtty-core/examples/quantity_db_serde.rs +215 -0
- package/qtty-js/qtty/qtty-core/src/dimension.rs +249 -0
- package/qtty-js/qtty/qtty-core/src/feature_diesel.rs +318 -0
- package/qtty-js/qtty/qtty-core/src/feature_pyo3.rs +27 -0
- package/qtty-js/qtty/qtty-core/src/feature_serde.rs +203 -0
- package/qtty-js/qtty/qtty-core/src/feature_tiberius.rs +28 -0
- package/qtty-js/qtty/qtty-core/src/lib.rs +744 -0
- package/qtty-js/qtty/qtty-core/src/macros.rs +93 -0
- package/qtty-js/qtty/qtty-core/src/quantity.rs +810 -0
- package/qtty-js/qtty/qtty-core/src/scalar.rs +1742 -0
- package/qtty-js/qtty/qtty-core/src/unit.rs +332 -0
- package/qtty-js/qtty/qtty-core/src/units/angular.rs +1228 -0
- package/qtty-js/qtty/qtty-core/src/units/area.rs +243 -0
- package/qtty-js/qtty/qtty-core/src/units/frequency.rs +179 -0
- package/qtty-js/qtty/qtty-core/src/units/length.rs +1270 -0
- package/qtty-js/qtty/qtty-core/src/units/mass.rs +488 -0
- package/qtty-js/qtty/qtty-core/src/units/mod.rs +26 -0
- package/qtty-js/qtty/qtty-core/src/units/power.rs +324 -0
- package/qtty-js/qtty/qtty-core/src/units/time.rs +667 -0
- package/qtty-js/qtty/qtty-core/src/units/unitless.rs +212 -0
- package/qtty-js/qtty/qtty-core/src/units/velocity.rs +210 -0
- package/qtty-js/qtty/qtty-core/src/units/volume.rs +269 -0
- package/qtty-js/qtty/qtty-core/tests/core.rs +628 -0
- package/qtty-js/qtty/qtty-core/tests/diesel.rs +461 -0
- package/qtty-js/qtty/qtty-core/tests/integers.rs +632 -0
- package/qtty-js/qtty/qtty-core/tests/no_cross_unit_ops.rs +35 -0
- package/qtty-js/qtty/qtty-core/tests/pyo3.rs +334 -0
- package/qtty-js/qtty/qtty-core/tests/quantity_f32.rs +276 -0
- package/qtty-js/qtty/qtty-core/tests/scalar_decimal.rs +258 -0
- package/qtty-js/qtty/qtty-core/tests/scalar_f32.rs +286 -0
- package/qtty-js/qtty/qtty-core/tests/scalar_f64_real.rs +287 -0
- package/qtty-js/qtty/qtty-core/tests/scalar_rational.rs +260 -0
- package/qtty-js/qtty/qtty-core/tests/serde.rs +256 -0
- package/qtty-js/qtty/qtty-core/tests/tiberius.rs +208 -0
- package/qtty-js/qtty/qtty-derive/Cargo.toml +23 -0
- package/qtty-js/qtty/qtty-derive/README.md +8 -0
- package/qtty-js/qtty/qtty-derive/src/lib.rs +340 -0
- package/qtty-js/qtty/qtty-ffi/ARCHITECTURE.md +3 -0
- package/qtty-js/qtty/qtty-ffi/Cargo.toml +31 -0
- package/qtty-js/qtty/qtty-ffi/README.md +9 -0
- package/qtty-js/qtty/qtty-ffi/build.rs +326 -0
- package/qtty-js/qtty/qtty-ffi/cbindgen.toml +105 -0
- package/qtty-js/qtty/qtty-ffi/include/qtty_ffi.h +1126 -0
- package/qtty-js/qtty/qtty-ffi/src/ffi.rs +1251 -0
- package/qtty-js/qtty/qtty-ffi/src/ffi_serde.rs +294 -0
- package/qtty-js/qtty/qtty-ffi/src/helpers.rs +310 -0
- package/qtty-js/qtty/qtty-ffi/src/lib.rs +229 -0
- package/qtty-js/qtty/qtty-ffi/src/macros.rs +121 -0
- package/qtty-js/qtty/qtty-ffi/src/registry.rs +274 -0
- package/qtty-js/qtty/qtty-ffi/src/types.rs +620 -0
- package/qtty-js/qtty/qtty-ffi/tests/integration_tests.rs +842 -0
- package/qtty-js/qtty/qtty-ffi/units.csv +156 -0
- package/qtty-js/qtty/qtty-ffi/units.csv.md +3 -0
- package/qtty-js/qtty-node/.prettierignore +6 -0
- package/qtty-js/qtty-node/.prettierrc.json +6 -0
- package/qtty-js/qtty-node/README.md +250 -0
- package/qtty-js/qtty-node/c8.config.json +11 -0
- package/qtty-js/qtty-node/eslint.config.js +31 -0
- package/qtty-js/qtty-node/examples/arithmetic.mjs +64 -0
- package/qtty-js/qtty-node/examples/astronomy.mjs +90 -0
- package/qtty-js/qtty-node/examples/quickstart.mjs +36 -0
- package/qtty-js/qtty-node/examples/serialization.mjs +125 -0
- package/qtty-js/qtty-node/examples/unit_factories.mjs +74 -0
- package/qtty-js/qtty-node/index.d.ts +219 -0
- package/qtty-js/qtty-node/index.js +323 -0
- package/qtty-js/qtty-node/lib/DerivedQuantity.js +122 -0
- package/qtty-js/qtty-node/lib/Quantity.js +151 -0
- package/qtty-js/qtty-node/lib/backend.js +25 -0
- package/qtty-js/qtty-node/native.cjs +306 -0
- package/qtty-js/qtty-node/package-lock.json +3223 -0
- package/qtty-js/qtty-node/package.json +70 -0
- package/qtty-js/qtty-node/units.d.ts +299 -0
- package/qtty-js/qtty-node/units.js +210 -0
- package/qtty-js/qtty-web/Cargo.lock +767 -0
- package/qtty-js/qtty-web/Cargo.toml +21 -0
- package/qtty-js/qtty-web/index.d.ts +140 -0
- package/qtty-js/qtty-web/index.js +20 -0
- package/qtty-js/qtty-web/lib/DerivedQuantity.js +58 -0
- package/qtty-js/qtty-web/lib/Quantity.js +75 -0
- package/qtty-js/qtty-web/lib/backend.js +80 -0
- package/qtty-js/qtty-web/package.json +45 -0
- package/qtty-js/qtty-web/src/lib.rs +111 -0
- package/qtty-js/scripts/ci.sh +73 -0
- package/scripts/ci.sh +123 -0
- package/siderust-core/Cargo.lock +787 -0
- package/siderust-core/Cargo.toml +18 -0
- package/siderust-core/DEDUPLICATION.md +124 -0
- package/siderust-core/src/body.rs +120 -0
- package/siderust-core/src/events.rs +184 -0
- package/siderust-core/src/lib.rs +20 -0
- package/siderust-core/src/observer.rs +55 -0
- package/siderust-core/src/position.rs +213 -0
- package/siderust-node/.prettierignore +7 -0
- package/siderust-node/.prettierrc.json +6 -0
- package/siderust-node/Cargo.lock +906 -0
- package/siderust-node/Cargo.toml +29 -0
- package/siderust-node/README.md +109 -0
- package/siderust-node/__test__/index.test.mjs +248 -0
- package/siderust-node/build.rs +5 -0
- package/siderust-node/c8.config.json +3 -0
- package/siderust-node/eslint.config.js +31 -0
- package/siderust-node/examples/01_basic_coordinates.mjs +24 -0
- package/siderust-node/examples/02_coordinate_transformations.mjs +25 -0
- package/siderust-node/examples/03_all_frames_conversions.mjs +26 -0
- package/siderust-node/examples/04_all_center_conversions.mjs +24 -0
- package/siderust-node/examples/05_target_tracking.mjs +22 -0
- package/siderust-node/examples/06_night_events.mjs +18 -0
- package/siderust-node/examples/07_moon_properties.mjs +21 -0
- package/siderust-node/examples/08_solar_system.mjs +19 -0
- package/siderust-node/examples/09_star_observability.mjs +22 -0
- package/siderust-node/examples/10_time_periods.mjs +9 -0
- package/siderust-node/examples/11_serialization.mjs +31 -0
- package/siderust-node/examples/12_runtime_ephemeris.mjs +27 -0
- package/siderust-node/examples/13_coordinate_operations.mjs +20 -0
- package/siderust-node/index.d.ts +623 -0
- package/siderust-node/index.js +79 -0
- package/siderust-node/lib/Observer.js +112 -0
- package/siderust-node/lib/Star.js +118 -0
- package/siderust-node/lib/backend.js +63 -0
- package/siderust-node/lib/wrappers.js +566 -0
- package/siderust-node/main.js +20 -0
- package/siderust-node/native.cjs +360 -0
- package/siderust-node/package-lock.json +3261 -0
- package/siderust-node/package.json +71 -0
- package/siderust-node/src/body.rs +74 -0
- package/siderust-node/src/coordinates.rs +372 -0
- package/siderust-node/src/ephemeris.rs +462 -0
- package/siderust-node/src/events.rs +577 -0
- package/siderust-node/src/lib.rs +43 -0
- package/siderust-node/src/observer.rs +132 -0
- package/siderust-node/src/phase.rs +218 -0
- package/siderust-node/src/position.rs +292 -0
- package/siderust-node/src/star.rs +200 -0
- package/siderust-web/Cargo.lock +855 -0
- package/siderust-web/Cargo.toml +34 -0
- package/siderust-web/README.md +100 -0
- package/siderust-web/__test__/index.test.mjs +118 -0
- package/siderust-web/examples/github-pages/README.md +31 -0
- package/siderust-web/examples/github-pages/index.html +135 -0
- package/siderust-web/index.d.ts +311 -0
- package/siderust-web/index.js +66 -0
- package/siderust-web/lib/Observer.js +103 -0
- package/siderust-web/lib/Star.js +116 -0
- package/siderust-web/lib/backend.js +400 -0
- package/siderust-web/lib/wrappers.js +512 -0
- package/siderust-web/package.json +55 -0
- package/siderust-web/src/body.rs +69 -0
- package/siderust-web/src/coordinates.rs +302 -0
- package/siderust-web/src/ephemeris.rs +456 -0
- package/siderust-web/src/events.rs +520 -0
- package/siderust-web/src/lib.rs +51 -0
- package/siderust-web/src/observer.rs +117 -0
- package/siderust-web/src/phase.rs +190 -0
- package/siderust-web/src/position.rs +291 -0
- package/siderust-web/src/star.rs +178 -0
- package/tempoch-js/.github/workflows/ci.yml +142 -0
- package/tempoch-js/.gitmodules +3 -0
- package/tempoch-js/CHANGELOG.md +25 -0
- package/tempoch-js/LICENSE +661 -0
- package/tempoch-js/README.md +126 -0
- package/tempoch-js/package.json +20 -0
- package/tempoch-js/scripts/ci.sh +73 -0
- package/tempoch-js/tempoch/.github/workflows/ci.yml +113 -0
- package/tempoch-js/tempoch/CHANGELOG.md +82 -0
- package/tempoch-js/tempoch/Cargo.lock +947 -0
- package/tempoch-js/tempoch/Cargo.toml +3 -0
- package/tempoch-js/tempoch/LICENSE +661 -0
- package/tempoch-js/tempoch/README.md +76 -0
- package/tempoch-js/tempoch/tempoch/Cargo.toml +27 -0
- package/tempoch-js/tempoch/tempoch/examples/periods.rs +45 -0
- package/tempoch-js/tempoch/tempoch/examples/quickstart.rs +13 -0
- package/tempoch-js/tempoch/tempoch/src/lib.rs +49 -0
- package/tempoch-js/tempoch/tempoch/tests/integration.rs +57 -0
- package/tempoch-js/tempoch/tempoch-core/Cargo.toml +24 -0
- package/tempoch-js/tempoch/tempoch-core/src/delta_t.rs +345 -0
- package/tempoch-js/tempoch/tempoch-core/src/instant.rs +811 -0
- package/tempoch-js/tempoch/tempoch-core/src/julian_date_ext.rs +142 -0
- package/tempoch-js/tempoch/tempoch-core/src/lib.rs +81 -0
- package/tempoch-js/tempoch/tempoch-core/src/period.rs +1168 -0
- package/tempoch-js/tempoch/tempoch-core/src/scales.rs +779 -0
- package/tempoch-js/tempoch/tempoch-ffi/Cargo.lock +889 -0
- package/tempoch-js/tempoch/tempoch-ffi/Cargo.toml +26 -0
- package/tempoch-js/tempoch/tempoch-ffi/build.rs +24 -0
- package/tempoch-js/tempoch/tempoch-ffi/cbindgen.toml +30 -0
- package/tempoch-js/tempoch/tempoch-ffi/src/error.rs +19 -0
- package/tempoch-js/tempoch/tempoch-ffi/src/lib.rs +82 -0
- package/tempoch-js/tempoch/tempoch-ffi/src/period.rs +101 -0
- package/tempoch-js/tempoch/tempoch-ffi/src/time.rs +711 -0
- package/tempoch-js/tempoch/tempoch-ffi/tests/ffi.rs +265 -0
- package/tempoch-js/tempoch-node/.prettierignore +6 -0
- package/tempoch-js/tempoch-node/.prettierrc.json +6 -0
- package/tempoch-js/tempoch-node/Cargo.lock +496 -0
- package/tempoch-js/tempoch-node/Cargo.toml +29 -0
- package/tempoch-js/tempoch-node/README.md +265 -0
- package/tempoch-js/tempoch-node/__test__/index.test.mjs +598 -0
- package/tempoch-js/tempoch-node/build.rs +5 -0
- package/tempoch-js/tempoch-node/c8.config.json +3 -0
- package/tempoch-js/tempoch-node/eslint.config.js +31 -0
- package/tempoch-js/tempoch-node/examples/periods.mjs +79 -0
- package/tempoch-js/tempoch-node/examples/quickstart.mjs +71 -0
- package/tempoch-js/tempoch-node/examples/timescales.mjs +92 -0
- package/tempoch-js/tempoch-node/index.d.ts +280 -0
- package/tempoch-js/tempoch-node/index.js +32 -0
- package/tempoch-js/tempoch-node/lib/JulianDate.js +176 -0
- package/tempoch-js/tempoch-node/lib/ModifiedJulianDate.js +156 -0
- package/tempoch-js/tempoch-node/lib/Period.js +133 -0
- package/tempoch-js/tempoch-node/lib/backend.js +38 -0
- package/tempoch-js/tempoch-node/lib/qttyCompat.js +92 -0
- package/tempoch-js/tempoch-node/native.cjs +317 -0
- package/tempoch-js/tempoch-node/package-lock.json +3223 -0
- package/tempoch-js/tempoch-node/package.json +56 -0
- package/tempoch-js/tempoch-node/src/lib.rs +573 -0
- package/tempoch-js/tempoch-web/Cargo.toml +23 -0
- package/tempoch-js/tempoch-web/index.d.ts +95 -0
- package/tempoch-js/tempoch-web/index.js +27 -0
- package/tempoch-js/tempoch-web/lib/JulianDate.js +170 -0
- package/tempoch-js/tempoch-web/lib/ModifiedJulianDate.js +145 -0
- package/tempoch-js/tempoch-web/lib/Period.js +121 -0
- package/tempoch-js/tempoch-web/lib/backend.js +118 -0
- package/tempoch-js/tempoch-web/package.json +46 -0
- package/tempoch-js/tempoch-web/src/lib.rs +184 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
//! Diesel ORM support for `Quantity` types (feature-gated).
|
|
2
|
+
//!
|
|
3
|
+
//! This module is enabled by the `diesel` feature. It provides serialization, deserialization,
|
|
4
|
+
//! and query support for `Quantity<U, S>` types when used with Diesel ORM.
|
|
5
|
+
//!
|
|
6
|
+
//! # Supported Scalar Types
|
|
7
|
+
//!
|
|
8
|
+
//! - `f64` - maps to SQL DOUBLE PRECISION
|
|
9
|
+
//! - `f32` - maps to SQL REAL (FLOAT)
|
|
10
|
+
//!
|
|
11
|
+
//! Note: Decimal and Rational scalar types are not supported for Diesel integration as they
|
|
12
|
+
//! don't have direct SQL type representations. Use f64 or f32 for database storage.
|
|
13
|
+
//!
|
|
14
|
+
//! # Supported Operations
|
|
15
|
+
//!
|
|
16
|
+
//! - **Serialization/Deserialization**: `Quantity<U, S>` maps to SQL DOUBLE PRECISION or REAL
|
|
17
|
+
//! - **Nullable columns**: `Option<Quantity<U, S>>` automatically supported
|
|
18
|
+
//! - **Query parameters**: Use in WHERE clauses and INSERT statements
|
|
19
|
+
//! - **Result loading**: Use in SELECT queries with `Queryable` structs
|
|
20
|
+
//! - **Backend-agnostic**: Works with PostgreSQL, SQLite, MySQL, and other Diesel backends
|
|
21
|
+
//!
|
|
22
|
+
//! # Examples
|
|
23
|
+
//!
|
|
24
|
+
//! ```rust,ignore
|
|
25
|
+
//! use qtty::Degrees;
|
|
26
|
+
//! use diesel::prelude::*;
|
|
27
|
+
//!
|
|
28
|
+
//! #[derive(Queryable, Selectable)]
|
|
29
|
+
//! #[diesel(table_name = observations)]
|
|
30
|
+
//! pub struct Observation {
|
|
31
|
+
//! pub id: i32,
|
|
32
|
+
//! pub altitude: Degrees, // Direct use of Quantity type
|
|
33
|
+
//! pub azimuth: Degrees,
|
|
34
|
+
//! pub min_altitude: Option<Degrees>, // Optional fields work too
|
|
35
|
+
//! }
|
|
36
|
+
//!
|
|
37
|
+
//! #[derive(Insertable)]
|
|
38
|
+
//! #[diesel(table_name = observations)]
|
|
39
|
+
//! pub struct NewObservation {
|
|
40
|
+
//! pub altitude: Degrees,
|
|
41
|
+
//! pub azimuth: Degrees,
|
|
42
|
+
//! pub min_altitude: Option<Degrees>,
|
|
43
|
+
//! }
|
|
44
|
+
//! ```
|
|
45
|
+
|
|
46
|
+
use crate::scalar::Real;
|
|
47
|
+
use crate::{Quantity, Unit};
|
|
48
|
+
use diesel::{
|
|
49
|
+
backend::Backend,
|
|
50
|
+
deserialize::{self, FromSql as DieselFromSql},
|
|
51
|
+
expression::AsExpression,
|
|
52
|
+
query_builder::QueryId,
|
|
53
|
+
serialize::{self, Output, ToSql as DieselToSql},
|
|
54
|
+
sql_types::{Double, Float, Nullable},
|
|
55
|
+
Queryable,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
59
|
+
// Core FromSql/ToSql implementations for f64 (Double)
|
|
60
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
61
|
+
|
|
62
|
+
/// Deserialize `Quantity<U, f64>` from SQL DOUBLE PRECISION (f64) for any Diesel backend.
|
|
63
|
+
impl<U, DB> DieselFromSql<Double, DB> for Quantity<U, f64>
|
|
64
|
+
where
|
|
65
|
+
U: Unit,
|
|
66
|
+
DB: Backend,
|
|
67
|
+
f64: DieselFromSql<Double, DB>,
|
|
68
|
+
{
|
|
69
|
+
fn from_sql(bytes: DB::RawValue<'_>) -> deserialize::Result<Self> {
|
|
70
|
+
let value = f64::from_sql(bytes)?;
|
|
71
|
+
Ok(Quantity::new(value))
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/// Serialize `Quantity<U, f64>` to SQL DOUBLE PRECISION (f64) for any Diesel backend.
|
|
76
|
+
impl<U, DB> DieselToSql<Double, DB> for Quantity<U, f64>
|
|
77
|
+
where
|
|
78
|
+
U: Unit,
|
|
79
|
+
DB: Backend,
|
|
80
|
+
f64: DieselToSql<Double, DB>,
|
|
81
|
+
{
|
|
82
|
+
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> serialize::Result {
|
|
83
|
+
<f64 as DieselToSql<Double, DB>>::to_sql(self.value_ref(), out)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
88
|
+
// Core FromSql/ToSql implementations for f32 (Float)
|
|
89
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
90
|
+
|
|
91
|
+
/// Deserialize `Quantity<U, f32>` from SQL REAL (f32) for any Diesel backend.
|
|
92
|
+
impl<U, DB> DieselFromSql<Float, DB> for Quantity<U, f32>
|
|
93
|
+
where
|
|
94
|
+
U: Unit,
|
|
95
|
+
DB: Backend,
|
|
96
|
+
f32: DieselFromSql<Float, DB>,
|
|
97
|
+
{
|
|
98
|
+
fn from_sql(bytes: DB::RawValue<'_>) -> deserialize::Result<Self> {
|
|
99
|
+
let value = f32::from_sql(bytes)?;
|
|
100
|
+
Ok(Quantity::new(value))
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/// Serialize `Quantity<U, f32>` to SQL REAL (f32) for any Diesel backend.
|
|
105
|
+
impl<U, DB> DieselToSql<Float, DB> for Quantity<U, f32>
|
|
106
|
+
where
|
|
107
|
+
U: Unit,
|
|
108
|
+
DB: Backend,
|
|
109
|
+
f32: DieselToSql<Float, DB>,
|
|
110
|
+
{
|
|
111
|
+
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> serialize::Result {
|
|
112
|
+
<f32 as DieselToSql<Float, DB>>::to_sql(self.value_ref(), out)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
117
|
+
// Nullable column support for f64
|
|
118
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
119
|
+
|
|
120
|
+
/// Support for nullable columns: `Option<Quantity<U, f64>>` maps to SQL DOUBLE PRECISION NULL.
|
|
121
|
+
impl<U, DB> DieselFromSql<Nullable<Double>, DB> for Quantity<U, f64>
|
|
122
|
+
where
|
|
123
|
+
U: Unit,
|
|
124
|
+
DB: Backend,
|
|
125
|
+
f64: DieselFromSql<Double, DB>,
|
|
126
|
+
{
|
|
127
|
+
fn from_sql(bytes: DB::RawValue<'_>) -> deserialize::Result<Self> {
|
|
128
|
+
let value = f64::from_sql(bytes)?;
|
|
129
|
+
Ok(Quantity::new(value))
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
impl<U, DB> DieselToSql<Nullable<Double>, DB> for Quantity<U, f64>
|
|
134
|
+
where
|
|
135
|
+
U: Unit,
|
|
136
|
+
DB: Backend,
|
|
137
|
+
f64: DieselToSql<Double, DB>,
|
|
138
|
+
{
|
|
139
|
+
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> serialize::Result {
|
|
140
|
+
<f64 as DieselToSql<Double, DB>>::to_sql(self.value_ref(), out)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
145
|
+
// Nullable column support for f32
|
|
146
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
147
|
+
|
|
148
|
+
/// Support for nullable columns: `Option<Quantity<U, f32>>` maps to SQL REAL NULL.
|
|
149
|
+
impl<U, DB> DieselFromSql<Nullable<Float>, DB> for Quantity<U, f32>
|
|
150
|
+
where
|
|
151
|
+
U: Unit,
|
|
152
|
+
DB: Backend,
|
|
153
|
+
f32: DieselFromSql<Float, DB>,
|
|
154
|
+
{
|
|
155
|
+
fn from_sql(bytes: DB::RawValue<'_>) -> deserialize::Result<Self> {
|
|
156
|
+
let value = f32::from_sql(bytes)?;
|
|
157
|
+
Ok(Quantity::new(value))
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
impl<U, DB> DieselToSql<Nullable<Float>, DB> for Quantity<U, f32>
|
|
162
|
+
where
|
|
163
|
+
U: Unit,
|
|
164
|
+
DB: Backend,
|
|
165
|
+
f32: DieselToSql<Float, DB>,
|
|
166
|
+
{
|
|
167
|
+
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> serialize::Result {
|
|
168
|
+
<f32 as DieselToSql<Float, DB>>::to_sql(self.value_ref(), out)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
173
|
+
// AsExpression implementations for f64
|
|
174
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
175
|
+
|
|
176
|
+
/// Enable `Quantity<U, f64>` in WHERE clauses and INSERT statements.
|
|
177
|
+
impl<U: Unit> AsExpression<Double> for Quantity<U, f64> {
|
|
178
|
+
type Expression = <f64 as AsExpression<Double>>::Expression;
|
|
179
|
+
|
|
180
|
+
fn as_expression(self) -> Self::Expression {
|
|
181
|
+
AsExpression::<Double>::as_expression(self.value())
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
impl<U: Unit> AsExpression<Double> for &Quantity<U, f64> {
|
|
186
|
+
type Expression = <f64 as AsExpression<Double>>::Expression;
|
|
187
|
+
|
|
188
|
+
fn as_expression(self) -> Self::Expression {
|
|
189
|
+
AsExpression::<Double>::as_expression(self.value())
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/// Enable `Quantity<U, f64>` in nullable (Option) columns.
|
|
194
|
+
impl<U: Unit> AsExpression<Nullable<Double>> for Quantity<U, f64> {
|
|
195
|
+
type Expression = <f64 as AsExpression<Nullable<Double>>>::Expression;
|
|
196
|
+
|
|
197
|
+
fn as_expression(self) -> Self::Expression {
|
|
198
|
+
AsExpression::<Nullable<Double>>::as_expression(self.value())
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
impl<U: Unit> AsExpression<Nullable<Double>> for &Quantity<U, f64> {
|
|
203
|
+
type Expression = <f64 as AsExpression<Nullable<Double>>>::Expression;
|
|
204
|
+
|
|
205
|
+
fn as_expression(self) -> Self::Expression {
|
|
206
|
+
AsExpression::<Nullable<Double>>::as_expression(self.value())
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
211
|
+
// AsExpression implementations for f32
|
|
212
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
213
|
+
|
|
214
|
+
/// Enable `Quantity<U, f32>` in WHERE clauses and INSERT statements.
|
|
215
|
+
impl<U: Unit> AsExpression<Float> for Quantity<U, f32> {
|
|
216
|
+
type Expression = <f32 as AsExpression<Float>>::Expression;
|
|
217
|
+
|
|
218
|
+
fn as_expression(self) -> Self::Expression {
|
|
219
|
+
AsExpression::<Float>::as_expression(self.value())
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
impl<U: Unit> AsExpression<Float> for &Quantity<U, f32> {
|
|
224
|
+
type Expression = <f32 as AsExpression<Float>>::Expression;
|
|
225
|
+
|
|
226
|
+
fn as_expression(self) -> Self::Expression {
|
|
227
|
+
AsExpression::<Float>::as_expression(self.value())
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/// Enable `Quantity<U, f32>` in nullable (Option) columns.
|
|
232
|
+
impl<U: Unit> AsExpression<Nullable<Float>> for Quantity<U, f32> {
|
|
233
|
+
type Expression = <f32 as AsExpression<Nullable<Float>>>::Expression;
|
|
234
|
+
|
|
235
|
+
fn as_expression(self) -> Self::Expression {
|
|
236
|
+
AsExpression::<Nullable<Float>>::as_expression(self.value())
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
impl<U: Unit> AsExpression<Nullable<Float>> for &Quantity<U, f32> {
|
|
241
|
+
type Expression = <f32 as AsExpression<Nullable<Float>>>::Expression;
|
|
242
|
+
|
|
243
|
+
fn as_expression(self) -> Self::Expression {
|
|
244
|
+
AsExpression::<Nullable<Float>>::as_expression(self.value())
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
249
|
+
// Queryable implementations for f64
|
|
250
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
251
|
+
|
|
252
|
+
/// Enable `Quantity<U, f64>` to be used in Diesel's `Queryable` derive.
|
|
253
|
+
impl<U, DB> Queryable<Double, DB> for Quantity<U, f64>
|
|
254
|
+
where
|
|
255
|
+
U: Unit,
|
|
256
|
+
DB: Backend,
|
|
257
|
+
f64: Queryable<Double, DB>,
|
|
258
|
+
{
|
|
259
|
+
type Row = <f64 as Queryable<Double, DB>>::Row;
|
|
260
|
+
|
|
261
|
+
fn build(row: Self::Row) -> deserialize::Result<Self> {
|
|
262
|
+
let value = <f64 as Queryable<Double, DB>>::build(row)?;
|
|
263
|
+
Ok(Quantity::new(value))
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
impl<U, DB> Queryable<Nullable<Double>, DB> for Quantity<U, f64>
|
|
268
|
+
where
|
|
269
|
+
U: Unit,
|
|
270
|
+
DB: Backend,
|
|
271
|
+
f64: Queryable<Nullable<Double>, DB>,
|
|
272
|
+
{
|
|
273
|
+
type Row = <f64 as Queryable<Nullable<Double>, DB>>::Row;
|
|
274
|
+
|
|
275
|
+
fn build(row: Self::Row) -> deserialize::Result<Self> {
|
|
276
|
+
let value = <f64 as Queryable<Nullable<Double>, DB>>::build(row)?;
|
|
277
|
+
Ok(Quantity::new(value))
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
282
|
+
// Queryable implementations for f32
|
|
283
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
284
|
+
|
|
285
|
+
/// Enable `Quantity<U, f32>` to be used in Diesel's `Queryable` derive.
|
|
286
|
+
impl<U, DB> Queryable<Float, DB> for Quantity<U, f32>
|
|
287
|
+
where
|
|
288
|
+
U: Unit,
|
|
289
|
+
DB: Backend,
|
|
290
|
+
f32: Queryable<Float, DB>,
|
|
291
|
+
{
|
|
292
|
+
type Row = <f32 as Queryable<Float, DB>>::Row;
|
|
293
|
+
|
|
294
|
+
fn build(row: Self::Row) -> deserialize::Result<Self> {
|
|
295
|
+
let value = <f32 as Queryable<Float, DB>>::build(row)?;
|
|
296
|
+
Ok(Quantity::new(value))
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
impl<U, DB> Queryable<Nullable<Float>, DB> for Quantity<U, f32>
|
|
301
|
+
where
|
|
302
|
+
U: Unit,
|
|
303
|
+
DB: Backend,
|
|
304
|
+
f32: Queryable<Nullable<Float>, DB>,
|
|
305
|
+
{
|
|
306
|
+
type Row = <f32 as Queryable<Nullable<Float>, DB>>::Row;
|
|
307
|
+
|
|
308
|
+
fn build(row: Self::Row) -> deserialize::Result<Self> {
|
|
309
|
+
let value = <f32 as Queryable<Nullable<Float>, DB>>::build(row)?;
|
|
310
|
+
Ok(Quantity::new(value))
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/// QueryId implementation for query caching support.
|
|
315
|
+
impl<U: Unit, S: Real> QueryId for Quantity<U, S> {
|
|
316
|
+
type QueryId = Self;
|
|
317
|
+
const HAS_STATIC_QUERY_ID: bool = false;
|
|
318
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//! PyO3 trait implementations for `Quantity` types (feature-gated).
|
|
2
|
+
//!
|
|
3
|
+
//! This module is enabled by the `pyo3` feature. It provides `IntoPyObject` and `FromPyObject`
|
|
4
|
+
//! implementations that convert `Quantity<U, S>` to/from Python floats.
|
|
5
|
+
|
|
6
|
+
use crate::scalar::Real;
|
|
7
|
+
use crate::{Quantity, Unit};
|
|
8
|
+
use pyo3::prelude::*;
|
|
9
|
+
|
|
10
|
+
impl<'py, U: Unit, S: Real> pyo3::conversion::IntoPyObject<'py> for Quantity<U, S> {
|
|
11
|
+
type Target = pyo3::types::PyFloat;
|
|
12
|
+
type Output = pyo3::Bound<'py, pyo3::types::PyFloat>;
|
|
13
|
+
type Error = core::convert::Infallible;
|
|
14
|
+
|
|
15
|
+
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
|
|
16
|
+
Ok(pyo3::types::PyFloat::new(py, self.value().to_f64()))
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
impl<'a, 'py, U: Unit, S: Real> pyo3::conversion::FromPyObject<'a, 'py> for Quantity<U, S> {
|
|
21
|
+
type Error = pyo3::PyErr;
|
|
22
|
+
|
|
23
|
+
fn extract(obj: pyo3::Borrowed<'a, 'py, PyAny>) -> Result<Self, Self::Error> {
|
|
24
|
+
let value = <f64 as pyo3::conversion::FromPyObject<'a, 'py>>::extract(obj)?;
|
|
25
|
+
Ok(Quantity::new(S::from_f64(value)))
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
//! Serde support for `Quantity` types (feature-gated).
|
|
2
|
+
//!
|
|
3
|
+
//! This module is enabled by the `serde` feature. It provides serialization and deserialization
|
|
4
|
+
//! for `Quantity<U, S>` types, including helper modules for different serialization formats.
|
|
5
|
+
|
|
6
|
+
use crate::scalar::{Real, Scalar};
|
|
7
|
+
use crate::{Quantity, Unit};
|
|
8
|
+
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
|
9
|
+
|
|
10
|
+
// Default serde: serialize as f64 (backward compatible)
|
|
11
|
+
impl<U: Unit, S: Real> Serialize for Quantity<U, S> {
|
|
12
|
+
fn serialize<Ser>(&self, serializer: Ser) -> core::result::Result<Ser::Ok, Ser::Error>
|
|
13
|
+
where
|
|
14
|
+
Ser: Serializer,
|
|
15
|
+
{
|
|
16
|
+
// Strategy A: Always serialize as f64 for backward compatibility
|
|
17
|
+
self.value().to_f64().serialize(serializer)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
impl<'de, U: Unit, S: Real> Deserialize<'de> for Quantity<U, S> {
|
|
22
|
+
fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
|
|
23
|
+
where
|
|
24
|
+
D: Deserializer<'de>,
|
|
25
|
+
{
|
|
26
|
+
// Strategy A: Deserialize from f64 and convert
|
|
27
|
+
let value = f64::deserialize(deserializer)?;
|
|
28
|
+
Ok(Quantity::new(S::from_f64(value)))
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/// Serde helper module for serializing the raw scalar value.
|
|
33
|
+
///
|
|
34
|
+
/// This module serializes the scalar type directly instead of converting to f64.
|
|
35
|
+
/// Use this when you need to preserve the exact scalar representation.
|
|
36
|
+
///
|
|
37
|
+
/// # Example
|
|
38
|
+
///
|
|
39
|
+
/// ```rust,ignore
|
|
40
|
+
/// use qtty_core::length::Meters;
|
|
41
|
+
/// use serde::{Serialize, Deserialize};
|
|
42
|
+
///
|
|
43
|
+
/// #[derive(Serialize, Deserialize)]
|
|
44
|
+
/// struct Config {
|
|
45
|
+
/// #[serde(with = "qtty_core::serde_scalar")]
|
|
46
|
+
/// distance: Meters, // Serializes the scalar directly
|
|
47
|
+
/// }
|
|
48
|
+
/// ```
|
|
49
|
+
pub mod serde_scalar {
|
|
50
|
+
use super::*;
|
|
51
|
+
|
|
52
|
+
/// Serializes the quantity's scalar value directly.
|
|
53
|
+
#[allow(dead_code)]
|
|
54
|
+
pub fn serialize<U, S, Ser>(
|
|
55
|
+
quantity: &Quantity<U, S>,
|
|
56
|
+
serializer: Ser,
|
|
57
|
+
) -> Result<Ser::Ok, Ser::Error>
|
|
58
|
+
where
|
|
59
|
+
U: Unit,
|
|
60
|
+
S: Scalar + Serialize,
|
|
61
|
+
Ser: Serializer,
|
|
62
|
+
{
|
|
63
|
+
quantity.value_ref().serialize(serializer)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/// Deserializes the quantity from a scalar value directly.
|
|
67
|
+
#[allow(dead_code)]
|
|
68
|
+
pub fn deserialize<'de, U, S, D>(deserializer: D) -> Result<Quantity<U, S>, D::Error>
|
|
69
|
+
where
|
|
70
|
+
U: Unit,
|
|
71
|
+
S: Scalar + Deserialize<'de>,
|
|
72
|
+
D: Deserializer<'de>,
|
|
73
|
+
{
|
|
74
|
+
let value = S::deserialize(deserializer)?;
|
|
75
|
+
Ok(Quantity::new(value))
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/// Serde helper module for serializing quantities with unit information.
|
|
80
|
+
///
|
|
81
|
+
/// Use this with the `#[serde(with = "...")]` attribute to preserve unit symbols
|
|
82
|
+
/// in serialized data. This is useful for external APIs, configuration files, or
|
|
83
|
+
/// self-documenting data formats.
|
|
84
|
+
///
|
|
85
|
+
/// # Examples
|
|
86
|
+
///
|
|
87
|
+
/// ```rust
|
|
88
|
+
/// use qtty_core::length::Meters;
|
|
89
|
+
/// use serde::{Serialize, Deserialize};
|
|
90
|
+
///
|
|
91
|
+
/// #[derive(Serialize, Deserialize)]
|
|
92
|
+
/// struct Config {
|
|
93
|
+
/// #[serde(with = "qtty_core::serde_with_unit")]
|
|
94
|
+
/// max_distance: Meters, // Serializes as {"value": 100.0, "unit": "m"}
|
|
95
|
+
///
|
|
96
|
+
/// min_distance: Meters, // Serializes as 50.0 (default, compact)
|
|
97
|
+
/// }
|
|
98
|
+
/// ```
|
|
99
|
+
#[cfg(feature = "std")]
|
|
100
|
+
pub mod serde_with_unit {
|
|
101
|
+
extern crate alloc;
|
|
102
|
+
use alloc::format;
|
|
103
|
+
use alloc::string::String;
|
|
104
|
+
|
|
105
|
+
use super::*;
|
|
106
|
+
use serde::de::{self, Deserializer, MapAccess, Visitor};
|
|
107
|
+
use serde::ser::{SerializeStruct, Serializer};
|
|
108
|
+
|
|
109
|
+
/// Serializes a `Quantity<U, S>` as a struct with `value` and `unit` fields.
|
|
110
|
+
///
|
|
111
|
+
/// # Example JSON Output
|
|
112
|
+
/// ```json
|
|
113
|
+
/// {"value": 42.5, "unit": "m"}
|
|
114
|
+
/// ```
|
|
115
|
+
pub fn serialize<U, S, Ser>(
|
|
116
|
+
quantity: &Quantity<U, S>,
|
|
117
|
+
serializer: Ser,
|
|
118
|
+
) -> Result<Ser::Ok, Ser::Error>
|
|
119
|
+
where
|
|
120
|
+
U: Unit,
|
|
121
|
+
S: Real,
|
|
122
|
+
Ser: Serializer,
|
|
123
|
+
{
|
|
124
|
+
let mut state = serializer.serialize_struct("Quantity", 2)?;
|
|
125
|
+
state.serialize_field("value", &quantity.value().to_f64())?;
|
|
126
|
+
state.serialize_field("unit", U::SYMBOL)?;
|
|
127
|
+
state.end()
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/// Deserializes a `Quantity<U, S>` from a struct with `value` and optionally `unit` fields.
|
|
131
|
+
///
|
|
132
|
+
/// The `unit` field is validated if present but not required for backwards compatibility.
|
|
133
|
+
/// If provided and doesn't match `U::SYMBOL`, an error is returned.
|
|
134
|
+
pub fn deserialize<'de, U, S, D>(deserializer: D) -> Result<Quantity<U, S>, D::Error>
|
|
135
|
+
where
|
|
136
|
+
U: Unit,
|
|
137
|
+
S: Real,
|
|
138
|
+
D: Deserializer<'de>,
|
|
139
|
+
{
|
|
140
|
+
#[derive(Deserialize)]
|
|
141
|
+
#[serde(field_identifier, rename_all = "lowercase")]
|
|
142
|
+
enum Field {
|
|
143
|
+
Value,
|
|
144
|
+
Unit,
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
struct QuantityVisitor<U, S>(core::marker::PhantomData<(U, S)>);
|
|
148
|
+
|
|
149
|
+
impl<'de, U: Unit, S: Real> Visitor<'de> for QuantityVisitor<U, S> {
|
|
150
|
+
type Value = Quantity<U, S>;
|
|
151
|
+
|
|
152
|
+
fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
|
|
153
|
+
formatter.write_str("struct Quantity with value and unit fields")
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
fn visit_map<V>(self, mut map: V) -> Result<Quantity<U, S>, V::Error>
|
|
157
|
+
where
|
|
158
|
+
V: MapAccess<'de>,
|
|
159
|
+
{
|
|
160
|
+
let mut value: Option<f64> = None;
|
|
161
|
+
let mut unit: Option<String> = None;
|
|
162
|
+
|
|
163
|
+
while let Some(key) = map.next_key()? {
|
|
164
|
+
match key {
|
|
165
|
+
Field::Value => {
|
|
166
|
+
if value.is_some() {
|
|
167
|
+
return Err(de::Error::duplicate_field("value"));
|
|
168
|
+
}
|
|
169
|
+
value = Some(map.next_value()?);
|
|
170
|
+
}
|
|
171
|
+
Field::Unit => {
|
|
172
|
+
if unit.is_some() {
|
|
173
|
+
return Err(de::Error::duplicate_field("unit"));
|
|
174
|
+
}
|
|
175
|
+
unit = Some(map.next_value()?);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
let value = value.ok_or_else(|| de::Error::missing_field("value"))?;
|
|
181
|
+
|
|
182
|
+
// Validate unit if provided (optional for backwards compatibility)
|
|
183
|
+
if let Some(ref unit_str) = unit {
|
|
184
|
+
if unit_str != U::SYMBOL {
|
|
185
|
+
return Err(de::Error::custom(format!(
|
|
186
|
+
"unit mismatch: expected '{}', found '{}'",
|
|
187
|
+
U::SYMBOL,
|
|
188
|
+
unit_str
|
|
189
|
+
)));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
Ok(Quantity::new(S::from_f64(value)))
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
deserializer.deserialize_struct(
|
|
198
|
+
"Quantity",
|
|
199
|
+
&["value", "unit"],
|
|
200
|
+
QuantityVisitor(core::marker::PhantomData),
|
|
201
|
+
)
|
|
202
|
+
}
|
|
203
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//! Tiberius SQL Server support for `Quantity` types (feature-gated).
|
|
2
|
+
//!
|
|
3
|
+
//! This module is enabled by the `tiberius` feature. It provides SQL Server database
|
|
4
|
+
//! integration for `Quantity<U, S>` types through the Tiberius driver.
|
|
5
|
+
|
|
6
|
+
use crate::scalar::Real;
|
|
7
|
+
use crate::{Quantity, Unit};
|
|
8
|
+
use tiberius::{ColumnData, FromSql, ToSql};
|
|
9
|
+
|
|
10
|
+
impl<U: Unit + Send + Sync, S: Real + Send + Sync> ToSql for Quantity<U, S> {
|
|
11
|
+
fn to_sql(&self) -> ColumnData<'_> {
|
|
12
|
+
ColumnData::F64(Some(self.value().to_f64()))
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
impl<U: Unit, S: Real> FromSql<'_> for Quantity<U, S> {
|
|
17
|
+
fn from_sql(value: &ColumnData<'_>) -> tiberius::Result<Option<Self>> {
|
|
18
|
+
match value {
|
|
19
|
+
ColumnData::F64(Some(val)) => Ok(Some(Quantity::new(S::from_f64(*val)))),
|
|
20
|
+
ColumnData::F32(Some(val)) => Ok(Some(Quantity::new(S::from_f64(*val as f64)))),
|
|
21
|
+
ColumnData::I16(Some(val)) => Ok(Some(Quantity::new(S::from_f64(*val as f64)))),
|
|
22
|
+
ColumnData::I32(Some(val)) => Ok(Some(Quantity::new(S::from_f64(*val as f64)))),
|
|
23
|
+
ColumnData::I64(Some(val)) => Ok(Some(Quantity::new(S::from_f64(*val as f64)))),
|
|
24
|
+
ColumnData::U8(Some(val)) => Ok(Some(Quantity::new(S::from_f64(*val as f64)))),
|
|
25
|
+
_ => Ok(None),
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|