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,326 @@
|
|
|
1
|
+
use std::env;
|
|
2
|
+
use std::fs;
|
|
3
|
+
use std::path::PathBuf;
|
|
4
|
+
|
|
5
|
+
fn main() {
|
|
6
|
+
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
|
|
7
|
+
let out_dir = env::var("OUT_DIR").unwrap();
|
|
8
|
+
|
|
9
|
+
// Re-run if units.csv changes
|
|
10
|
+
println!("cargo:rerun-if-changed=units.csv");
|
|
11
|
+
|
|
12
|
+
// Parse units from CSV
|
|
13
|
+
let units = parse_units_csv(&crate_dir);
|
|
14
|
+
|
|
15
|
+
// Generate code files
|
|
16
|
+
generate_unit_enum(&units, &out_dir);
|
|
17
|
+
generate_unit_names(&units, &out_dir);
|
|
18
|
+
generate_unit_names_cstr(&units, &out_dir);
|
|
19
|
+
generate_unit_symbols(&units, &out_dir);
|
|
20
|
+
generate_from_u32(&units, &out_dir);
|
|
21
|
+
generate_registry(&units, &out_dir);
|
|
22
|
+
generate_unit_conversions(&units, &out_dir);
|
|
23
|
+
|
|
24
|
+
eprintln!(
|
|
25
|
+
"cargo:warning=Generated FFI bindings for {} units from units.csv",
|
|
26
|
+
units.len()
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
// Generate C header (existing functionality)
|
|
30
|
+
generate_c_header(&crate_dir);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
#[derive(Debug, Clone)]
|
|
34
|
+
struct UnitDef {
|
|
35
|
+
name: String,
|
|
36
|
+
symbol: String,
|
|
37
|
+
dimension: String,
|
|
38
|
+
discriminant: u32,
|
|
39
|
+
ratio: String,
|
|
40
|
+
/// Optional Rust type path for auto-generating From/TryFrom impls.
|
|
41
|
+
/// When present, generates `impl_unit_ffi!(rust_type, UnitId::name)`.
|
|
42
|
+
rust_type: Option<String>,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
fn parse_units_csv(crate_dir: &str) -> Vec<UnitDef> {
|
|
46
|
+
let csv_path = PathBuf::from(crate_dir).join("units.csv");
|
|
47
|
+
let content = fs::read_to_string(&csv_path).expect("Failed to read units.csv");
|
|
48
|
+
|
|
49
|
+
let mut units = Vec::new();
|
|
50
|
+
|
|
51
|
+
for line in content.lines() {
|
|
52
|
+
let line = line.trim();
|
|
53
|
+
|
|
54
|
+
// Skip comments and empty lines
|
|
55
|
+
if line.is_empty() || line.starts_with('#') {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
let parts: Vec<&str> = line.splitn(6, ',').collect();
|
|
60
|
+
if parts.len() < 5 {
|
|
61
|
+
eprintln!("cargo:warning=Skipping invalid line: {}", line);
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Optional 6th field: Rust type path for From/TryFrom generation
|
|
66
|
+
let rust_type = if parts.len() >= 6 {
|
|
67
|
+
let rt = parts[5].trim();
|
|
68
|
+
if rt.is_empty() {
|
|
69
|
+
None
|
|
70
|
+
} else {
|
|
71
|
+
Some(rt.to_string())
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
None
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
units.push(UnitDef {
|
|
78
|
+
discriminant: parts[0]
|
|
79
|
+
.parse()
|
|
80
|
+
.unwrap_or_else(|_| panic!("Invalid discriminant: {}", parts[0])),
|
|
81
|
+
dimension: parts[1].to_string(),
|
|
82
|
+
name: parts[2].to_string(),
|
|
83
|
+
symbol: parts[3].to_string(),
|
|
84
|
+
ratio: parts[4].to_string(),
|
|
85
|
+
rust_type,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
units
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
fn generate_unit_enum(units: &[UnitDef], out_dir: &str) {
|
|
93
|
+
let mut code = String::from("// Auto-generated from units.csv\n");
|
|
94
|
+
code.push_str("/// Unit identifier for FFI.\n");
|
|
95
|
+
code.push_str("///\n");
|
|
96
|
+
code.push_str("/// Each variant corresponds to a specific unit supported by the FFI layer.\n");
|
|
97
|
+
code.push_str(
|
|
98
|
+
"/// All discriminant values are explicitly assigned and are part of the ABI contract.\n",
|
|
99
|
+
);
|
|
100
|
+
code.push_str("#[repr(u32)]\n");
|
|
101
|
+
code.push_str("#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]\n");
|
|
102
|
+
code.push_str(
|
|
103
|
+
"#[cfg_attr(feature = \"pyo3\", pyo3::pyclass(eq, eq_int, from_py_object, module = \"qtty\"))]\n",
|
|
104
|
+
);
|
|
105
|
+
code.push_str("pub enum UnitId {\n");
|
|
106
|
+
|
|
107
|
+
for unit in units {
|
|
108
|
+
code.push_str(&format!(" /// {} ({})\n", unit.name, unit.symbol));
|
|
109
|
+
code.push_str(&format!(" {} = {},\n", unit.name, unit.discriminant));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
code.push_str("}\n\n");
|
|
113
|
+
|
|
114
|
+
// Add pickle support methods when pyo3 feature is enabled
|
|
115
|
+
code.push_str("#[cfg(feature = \"pyo3\")]\n");
|
|
116
|
+
code.push_str("#[pyo3::pymethods]\n");
|
|
117
|
+
code.push_str("impl UnitId {\n");
|
|
118
|
+
code.push_str(" #[new]\n");
|
|
119
|
+
code.push_str(" fn __new__(value: u32) -> pyo3::PyResult<Self> {\n");
|
|
120
|
+
code.push_str(" Self::from_u32(value).ok_or_else(|| {\n");
|
|
121
|
+
code.push_str(" pyo3::exceptions::PyValueError::new_err(format!(\"Invalid UnitId: {}\", value))\n");
|
|
122
|
+
code.push_str(" })\n");
|
|
123
|
+
code.push_str(" }\n");
|
|
124
|
+
code.push_str(" \n");
|
|
125
|
+
code.push_str(" fn __getnewargs__(&self) -> (u32,) {\n");
|
|
126
|
+
code.push_str(" (*self as u32,)\n");
|
|
127
|
+
code.push_str(" }\n");
|
|
128
|
+
code.push('\n');
|
|
129
|
+
code.push_str(" fn __hash__(&self) -> u64 {\n");
|
|
130
|
+
code.push_str(" *self as u64\n");
|
|
131
|
+
code.push_str(" }\n");
|
|
132
|
+
code.push('\n');
|
|
133
|
+
code.push_str(" fn __repr__(&self) -> String {\n");
|
|
134
|
+
code.push_str(" format!(\"Unit.{}\", self.name())\n");
|
|
135
|
+
code.push_str(" }\n");
|
|
136
|
+
code.push('\n');
|
|
137
|
+
// scalar * Unit → Quantity (e.g. 9.58 * Unit.Second)
|
|
138
|
+
code.push_str(" /// Multiply a scalar by a unit to create a Quantity.\n");
|
|
139
|
+
code.push_str(" ///\n");
|
|
140
|
+
code.push_str(" /// Example: `9.58 * Unit.Second` → `Quantity(9.58, Unit.Second)`\n");
|
|
141
|
+
code.push_str(" fn __mul__<'py>(&self, py: pyo3::Python<'py>, scalar: f64) -> pyo3::PyResult<pyo3::Bound<'py, pyo3::PyAny>> {\n");
|
|
142
|
+
code.push_str(" use pyo3::types::PyAnyMethods;\n");
|
|
143
|
+
code.push_str(" let qtty = py.import(\"qtty\")?;\n");
|
|
144
|
+
code.push_str(" let cls = qtty.getattr(\"Quantity\")?;\n");
|
|
145
|
+
code.push_str(" cls.call1((scalar, *self))\n");
|
|
146
|
+
code.push_str(" }\n");
|
|
147
|
+
code.push('\n');
|
|
148
|
+
code.push_str(
|
|
149
|
+
" /// Right multiplication: `Unit.Second * 9.58` → `Quantity(9.58, Unit.Second)`\n",
|
|
150
|
+
);
|
|
151
|
+
code.push_str(" fn __rmul__<'py>(&self, py: pyo3::Python<'py>, scalar: f64) -> pyo3::PyResult<pyo3::Bound<'py, pyo3::PyAny>> {\n");
|
|
152
|
+
code.push_str(" self.__mul__(py, scalar)\n");
|
|
153
|
+
code.push_str(" }\n");
|
|
154
|
+
code.push_str("}\n");
|
|
155
|
+
|
|
156
|
+
let dest_path = PathBuf::from(out_dir).join("unit_id_enum.rs");
|
|
157
|
+
fs::write(&dest_path, code).expect("Failed to write unit_id_enum.rs");
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
fn generate_unit_names(units: &[UnitDef], out_dir: &str) {
|
|
161
|
+
let mut code = String::from("// Auto-generated from units.csv\n");
|
|
162
|
+
code.push_str("match self {\n");
|
|
163
|
+
|
|
164
|
+
for unit in units {
|
|
165
|
+
code.push_str(&format!(
|
|
166
|
+
" UnitId::{} => \"{}\",\n",
|
|
167
|
+
unit.name, unit.name
|
|
168
|
+
));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
code.push_str("}\n");
|
|
172
|
+
|
|
173
|
+
let dest_path = PathBuf::from(out_dir).join("unit_names.rs");
|
|
174
|
+
fs::write(&dest_path, code).expect("Failed to write unit_names.rs");
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
fn generate_unit_names_cstr(units: &[UnitDef], out_dir: &str) {
|
|
178
|
+
let mut code = String::from("// Auto-generated from units.csv\n");
|
|
179
|
+
code.push_str("match self {\n");
|
|
180
|
+
|
|
181
|
+
for unit in units {
|
|
182
|
+
code.push_str(&format!(
|
|
183
|
+
" UnitId::{} => c\"{}\".as_ptr(),\n",
|
|
184
|
+
unit.name, unit.name
|
|
185
|
+
));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
code.push_str("}\n");
|
|
189
|
+
|
|
190
|
+
let dest_path = PathBuf::from(out_dir).join("unit_names_cstr.rs");
|
|
191
|
+
fs::write(&dest_path, code).expect("Failed to write unit_names_cstr.rs");
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
fn generate_unit_symbols(units: &[UnitDef], out_dir: &str) {
|
|
195
|
+
let mut code = String::from("// Auto-generated from units.csv\n");
|
|
196
|
+
code.push_str("match self {\n");
|
|
197
|
+
|
|
198
|
+
for unit in units {
|
|
199
|
+
code.push_str(&format!(
|
|
200
|
+
" UnitId::{} => \"{}\",\n",
|
|
201
|
+
unit.name, unit.symbol
|
|
202
|
+
));
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
code.push_str("}\n");
|
|
206
|
+
|
|
207
|
+
let dest_path = PathBuf::from(out_dir).join("unit_symbols.rs");
|
|
208
|
+
fs::write(&dest_path, code).expect("Failed to write unit_symbols.rs");
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
fn generate_from_u32(units: &[UnitDef], out_dir: &str) {
|
|
212
|
+
let mut code = String::from("// Auto-generated from units.csv\n");
|
|
213
|
+
code.push_str("match value {\n");
|
|
214
|
+
|
|
215
|
+
for unit in units {
|
|
216
|
+
code.push_str(&format!(
|
|
217
|
+
" {} => Some(UnitId::{}),\n",
|
|
218
|
+
unit.discriminant, unit.name
|
|
219
|
+
));
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
code.push_str(" _ => None,\n}\n");
|
|
223
|
+
|
|
224
|
+
let dest_path = PathBuf::from(out_dir).join("unit_from_u32.rs");
|
|
225
|
+
fs::write(&dest_path, code).expect("Failed to write unit_from_u32.rs");
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
fn generate_registry(units: &[UnitDef], out_dir: &str) {
|
|
229
|
+
let mut code = String::from("// Auto-generated from units.csv\n");
|
|
230
|
+
code.push_str("match id {\n");
|
|
231
|
+
|
|
232
|
+
for unit in units {
|
|
233
|
+
code.push_str(&format!(" UnitId::{} => Some(UnitMeta {{\n", unit.name));
|
|
234
|
+
code.push_str(&format!(" dim: DimensionId::{},\n", unit.dimension));
|
|
235
|
+
code.push_str(&format!(" scale_to_canonical: {},\n", unit.ratio));
|
|
236
|
+
code.push_str(&format!(" name: \"{}\",\n", unit.name));
|
|
237
|
+
code.push_str(" }),\n");
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
code.push_str("}\n");
|
|
241
|
+
|
|
242
|
+
let dest_path = PathBuf::from(out_dir).join("unit_registry.rs");
|
|
243
|
+
fs::write(&dest_path, code).expect("Failed to write unit_registry.rs");
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
fn generate_unit_conversions(units: &[UnitDef], out_dir: &str) {
|
|
247
|
+
let mut code = String::from("// Auto-generated From/TryFrom impls from units.csv\n");
|
|
248
|
+
code.push_str("// Each `impl_unit_ffi!` invocation generates:\n");
|
|
249
|
+
code.push_str("// impl From<RustType> for QttyQuantity\n");
|
|
250
|
+
code.push_str("// impl TryFrom<QttyQuantity> for RustType\n\n");
|
|
251
|
+
|
|
252
|
+
let mut count = 0;
|
|
253
|
+
for unit in units {
|
|
254
|
+
if let Some(ref rust_type) = unit.rust_type {
|
|
255
|
+
code.push_str(&format!(
|
|
256
|
+
"crate::impl_unit_ffi!({}, crate::UnitId::{});\n",
|
|
257
|
+
rust_type, unit.name
|
|
258
|
+
));
|
|
259
|
+
count += 1;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
eprintln!(
|
|
264
|
+
"cargo:warning=Generated From/TryFrom impls for {} of {} units",
|
|
265
|
+
count,
|
|
266
|
+
units.len()
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
let dest_path = PathBuf::from(out_dir).join("unit_conversions.rs");
|
|
270
|
+
fs::write(&dest_path, code).expect("Failed to write unit_conversions.rs");
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
fn generate_c_header(crate_dir: &str) {
|
|
274
|
+
if env::var("DOCS_RS").is_ok() {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Skip header regeneration on stable toolchain: cbindgen needs nightly
|
|
279
|
+
// (-Zunpretty=expanded) to see macro-generated items (e.g. UnitId enum).
|
|
280
|
+
// The header is maintained manually for stable builds.
|
|
281
|
+
let rustc = env::var("RUSTC").unwrap_or_else(|_| "rustc".to_string());
|
|
282
|
+
let is_nightly = std::process::Command::new(&rustc)
|
|
283
|
+
.arg("--version")
|
|
284
|
+
.output()
|
|
285
|
+
.map(|o| String::from_utf8_lossy(&o.stdout).contains("nightly"))
|
|
286
|
+
.unwrap_or(false);
|
|
287
|
+
|
|
288
|
+
if !is_nightly {
|
|
289
|
+
eprintln!("cargo:warning=Skipping cbindgen header regeneration (stable toolchain); header maintained manually.");
|
|
290
|
+
println!("cargo:rerun-if-changed=src/");
|
|
291
|
+
println!("cargo:rerun-if-changed=cbindgen.toml");
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
let out_dir = PathBuf::from(crate_dir).join("include");
|
|
296
|
+
|
|
297
|
+
if let Err(e) = std::fs::create_dir_all(&out_dir) {
|
|
298
|
+
eprintln!("cargo:warning=Failed to create include directory: {}", e);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
let config_path = PathBuf::from(crate_dir).join("cbindgen.toml");
|
|
303
|
+
let config = match cbindgen::Config::from_file(&config_path) {
|
|
304
|
+
Ok(c) => c,
|
|
305
|
+
Err(e) => {
|
|
306
|
+
eprintln!("cargo:warning=Failed to read cbindgen.toml: {}", e);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
let header_path = out_dir.join("qtty_ffi.h");
|
|
312
|
+
match cbindgen::Builder::new()
|
|
313
|
+
.with_crate(crate_dir)
|
|
314
|
+
.with_config(config)
|
|
315
|
+
.generate()
|
|
316
|
+
{
|
|
317
|
+
Ok(bindings) => {
|
|
318
|
+
bindings.write_to_file(&header_path);
|
|
319
|
+
println!("cargo:rerun-if-changed=src/");
|
|
320
|
+
println!("cargo:rerun-if-changed=cbindgen.toml");
|
|
321
|
+
}
|
|
322
|
+
Err(e) => {
|
|
323
|
+
eprintln!("cargo:warning=Failed to generate C header: {}", e);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# cbindgen configuration for qtty-ffi
|
|
2
|
+
# See https://github.com/mozilla/cbindgen/blob/master/docs.md
|
|
3
|
+
|
|
4
|
+
# Language configuration
|
|
5
|
+
language = "C"
|
|
6
|
+
|
|
7
|
+
# Include doc comments in header
|
|
8
|
+
documentation = true
|
|
9
|
+
documentation_style = "c"
|
|
10
|
+
|
|
11
|
+
# Header configuration
|
|
12
|
+
header = """
|
|
13
|
+
/**
|
|
14
|
+
* @file qtty_ffi.h
|
|
15
|
+
* @brief C-compatible FFI bindings for qtty physical quantities and unit conversions.
|
|
16
|
+
*
|
|
17
|
+
* This header provides the C API for the qtty-ffi library, enabling C/C++ code
|
|
18
|
+
* to construct and convert physical quantities using qtty's conversion logic.
|
|
19
|
+
*
|
|
20
|
+
* # Example Usage
|
|
21
|
+
*
|
|
22
|
+
* @code{.c}
|
|
23
|
+
* #include "qtty_ffi.h"
|
|
24
|
+
* #include <stdio.h>
|
|
25
|
+
*
|
|
26
|
+
* int main() {
|
|
27
|
+
* qtty_quantity_t meters, kilometers;
|
|
28
|
+
*
|
|
29
|
+
* // Create a quantity: 1000 meters
|
|
30
|
+
* int32_t status = qtty_quantity_make(1000.0, UNIT_ID_METER, &meters);
|
|
31
|
+
* if (status != QTTY_OK) {
|
|
32
|
+
* fprintf(stderr, "Failed to create quantity\\n");
|
|
33
|
+
* return 1;
|
|
34
|
+
* }
|
|
35
|
+
*
|
|
36
|
+
* // Convert to kilometers
|
|
37
|
+
* status = qtty_quantity_convert(meters, UNIT_ID_KILOMETER, &kilometers);
|
|
38
|
+
* if (status == QTTY_OK) {
|
|
39
|
+
* printf("1000 meters = %.2f kilometers\\n", kilometers.value);
|
|
40
|
+
* }
|
|
41
|
+
*
|
|
42
|
+
* return 0;
|
|
43
|
+
* }
|
|
44
|
+
* @endcode
|
|
45
|
+
*
|
|
46
|
+
* # Thread Safety
|
|
47
|
+
*
|
|
48
|
+
* All functions are thread-safe. The library contains no global mutable state.
|
|
49
|
+
*
|
|
50
|
+
* # ABI Stability
|
|
51
|
+
*
|
|
52
|
+
* Enum discriminant values and struct layouts are part of the ABI contract
|
|
53
|
+
* and will not change in backward-compatible releases.
|
|
54
|
+
*
|
|
55
|
+
* @version 1.0
|
|
56
|
+
*/
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
trailer = """
|
|
60
|
+
/* End of qtty_ffi.h */
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
# Include guards
|
|
64
|
+
include_guard = "QTTY_FFI_H"
|
|
65
|
+
|
|
66
|
+
# C++ compatibility
|
|
67
|
+
cpp_compat = true
|
|
68
|
+
|
|
69
|
+
# Use stdint types
|
|
70
|
+
usize_is_size_t = true
|
|
71
|
+
|
|
72
|
+
[defines]
|
|
73
|
+
|
|
74
|
+
[export]
|
|
75
|
+
include = [
|
|
76
|
+
"UnitId", "DimensionId", "QttyQuantity", "QttyDerivedQuantity",
|
|
77
|
+
"QTTY_OK", "QTTY_ERR_UNKNOWN_UNIT", "QTTY_ERR_INCOMPATIBLE_DIM",
|
|
78
|
+
"QTTY_ERR_NULL_OUT", "QTTY_ERR_INVALID_VALUE", "QTTY_ERR_BUFFER_TOO_SMALL",
|
|
79
|
+
"QTTY_FMT_DEFAULT", "QTTY_FMT_LOWER_EXP", "QTTY_FMT_UPPER_EXP",
|
|
80
|
+
]
|
|
81
|
+
exclude = ["UnitMeta"]
|
|
82
|
+
|
|
83
|
+
[export.rename]
|
|
84
|
+
"QttyQuantity" = "qtty_quantity_t"
|
|
85
|
+
"QttyDerivedQuantity" = "qtty_derived_quantity_t"
|
|
86
|
+
|
|
87
|
+
[fn]
|
|
88
|
+
rename_args = "SnakeCase"
|
|
89
|
+
|
|
90
|
+
[struct]
|
|
91
|
+
rename_fields = "SnakeCase"
|
|
92
|
+
|
|
93
|
+
[enum]
|
|
94
|
+
rename_variants = "ScreamingSnakeCase"
|
|
95
|
+
prefix_with_name = true
|
|
96
|
+
|
|
97
|
+
[parse]
|
|
98
|
+
parse_deps = false
|
|
99
|
+
include = ["qtty-ffi"]
|
|
100
|
+
|
|
101
|
+
[parse.expand]
|
|
102
|
+
crates = ["qtty-ffi"]
|
|
103
|
+
|
|
104
|
+
[macro_expansion]
|
|
105
|
+
bitflags = false
|