swiss_eph/
lib.rs

1//! Complete FFI bindings to the Swiss Ephemeris library.
2//!
3//! This crate provides raw, unsafe bindings to all functions and constants
4//! exported by the Swiss Ephemeris C library.
5//!
6//! # Safety
7//! All functions in this crate are `unsafe` as they call into C code.
8//! Callers must ensure proper buffer sizes and valid pointers.
9//!
10//! # Safe API
11//! For a safe, idiomatic Rust API, use the `safe` module.
12//!
13//! # License
14//! AGPL-3.0 (inherited from Swiss Ephemeris)
15
16#![allow(non_camel_case_types)]
17#![allow(non_upper_case_globals)]
18
19use std::os::raw::{c_char, c_double, c_int};
20#[cfg(target_arch = "wasm32")]
21use wasm_bindgen::prelude::*;
22
23pub mod safe;
24
25// =============================================================================
26// WASM-only Memory Management and Exports
27// These are only compiled for WASM targets to avoid conflicts with native
28// system allocators and duplicate symbol errors.
29// =============================================================================
30
31#[cfg(target_arch = "wasm32")]
32mod wasm_exports {
33    use super::*;
34    use std::os::raw::{c_char, c_double};
35
36#[cfg(not(target_os = "wasi"))]
37mod alloc_exports {
38    use super::*;
39
40    #[export_name = "malloc"]
41    pub unsafe extern "C" fn custom_malloc(size: usize) -> *mut u8 {
42        let actual_size = size + 8;
43        let layout = std::alloc::Layout::from_size_align_unchecked(actual_size, 8);
44        let ptr = std::alloc::alloc(layout);
45        if ptr.is_null() {
46            return ptr;
47        }
48        *(ptr as *mut usize) = size;
49        ptr.add(8)
50    }
51
52    #[export_name = "free"]
53    pub unsafe extern "C" fn custom_free(ptr: *mut u8) {
54        if ptr.is_null() {
55            return;
56        }
57        let actual_ptr = ptr.sub(8);
58        let size = *(actual_ptr as *const usize);
59        let layout = std::alloc::Layout::from_size_align_unchecked(size + 8, 8);
60        std::alloc::dealloc(actual_ptr, layout);
61    }
62}
63
64    #[export_name = "wasm_swe_calc_ut"]
65    pub unsafe extern "C" fn __swe_calc_ut(
66        tjd_ut: c_double,
67        ipl: int32,
68        iflag: int32,
69        xx: *mut c_double,
70        serr: *mut c_char,
71    ) -> int32 {
72        swe_calc_ut(tjd_ut, ipl, iflag, xx, serr)
73    }
74
75    #[export_name = "wasm_swe_calc"]
76    pub unsafe extern "C" fn __swe_calc(
77        tjd: c_double,
78        ipl: int32,
79        iflag: int32,
80        xx: *mut c_double,
81        serr: *mut c_char,
82    ) -> int32 {
83        swe_calc(tjd, ipl, iflag, xx, serr)
84    }
85
86    #[export_name = "wasm_swe_set_ephe_path"]
87    pub unsafe extern "C" fn __swe_set_ephe_path(path: *mut c_char) {
88        swe_set_ephe_path(path)
89    }
90
91    #[export_name = "wasm_swe_version"]
92    pub unsafe extern "C" fn __swe_version(s: *mut c_char) -> *mut c_char {
93        swe_version(s)
94    }
95
96    #[export_name = "wasm_swe_close"]
97    pub unsafe extern "C" fn __swe_close() {
98        swe_close()
99    }
100
101    #[export_name = "wasm_swe_julday"]
102    pub unsafe extern "C" fn __swe_julday(
103        year: c_int,
104        month: c_int,
105        day: c_int,
106        hour: c_double,
107        gregflag: c_int,
108    ) -> c_double {
109        swe_julday(year, month, day, hour, gregflag)
110    }
111
112    #[export_name = "wasm_swe_revjul"]
113    pub unsafe extern "C" fn __swe_revjul(
114        jd: c_double,
115        gregflag: c_int,
116        year: *mut c_int,
117        month: *mut c_int,
118        day: *mut c_int,
119        hour: *mut c_double,
120    ) {
121        swe_revjul(jd, gregflag, year, month, day, hour)
122    }
123
124    #[export_name = "wasm_swe_houses"]
125    pub unsafe extern "C" fn __swe_houses(
126        tjd_ut: c_double,
127        geolat: c_double,
128        geolon: c_double,
129        hsys: c_int,
130        cusps: *mut c_double,
131        ascmc: *mut c_double,
132    ) -> c_int {
133        swe_houses(tjd_ut, geolat, geolon, hsys, cusps, ascmc)
134    }
135
136    #[export_name = "wasm_swe_sidtime"]
137    pub unsafe extern "C" fn __swe_sidtime(tjd_ut: c_double) -> c_double {
138        swe_sidtime(tjd_ut)
139    }
140
141    #[export_name = "wasm_swe_set_topo"]
142    pub unsafe extern "C" fn __swe_set_topo(geolon: c_double, geolat: c_double, geoalt: c_double) {
143        swe_set_topo(geolon, geolat, geoalt)
144    }
145}
146
147// =============================================================================
148// Type definitions (from sweodef.h)
149// =============================================================================
150
151/// 32-bit signed integer
152pub type int32 = c_int;
153/// 64-bit signed integer  
154pub type int64 = i64;
155/// 32-bit unsigned integer
156pub type uint32 = u32;
157/// 16-bit signed integer
158pub type int16 = i16;
159/// Real with at least 64-bit precision
160pub type REAL8 = c_double;
161/// Signed integer with at least 32-bit precision
162pub type INT4 = c_int;
163/// Unsigned integer with at least 32-bit precision
164pub type UINT4 = u32;
165/// Boolean type
166pub type AS_BOOL = c_int;
167/// Unsigned 16-bit integer
168pub type UINT2 = u16;
169/// Centiseconds used for angles and times
170pub type centisec = int32;
171/// Alias for centisec
172pub type CSEC = centisec;
173
174// =============================================================================
175// Calendar constants
176// =============================================================================
177pub const SE_JUL_CAL: c_int = 0;
178pub const SE_GREG_CAL: c_int = 1;
179
180// =============================================================================
181// Planet numbers for swe_calc()
182// =============================================================================
183pub const SE_ECL_NUT: c_int = -1;
184pub const SE_SUN: c_int = 0;
185pub const SE_MOON: c_int = 1;
186pub const SE_MERCURY: c_int = 2;
187pub const SE_VENUS: c_int = 3;
188pub const SE_MARS: c_int = 4;
189pub const SE_JUPITER: c_int = 5;
190pub const SE_SATURN: c_int = 6;
191pub const SE_URANUS: c_int = 7;
192pub const SE_NEPTUNE: c_int = 8;
193pub const SE_PLUTO: c_int = 9;
194pub const SE_MEAN_NODE: c_int = 10;
195pub const SE_TRUE_NODE: c_int = 11;
196pub const SE_MEAN_APOG: c_int = 12;
197pub const SE_OSCU_APOG: c_int = 13;
198pub const SE_EARTH: c_int = 14;
199pub const SE_CHIRON: c_int = 15;
200pub const SE_PHOLUS: c_int = 16;
201pub const SE_CERES: c_int = 17;
202pub const SE_PALLAS: c_int = 18;
203pub const SE_JUNO: c_int = 19;
204pub const SE_VESTA: c_int = 20;
205pub const SE_INTP_APOG: c_int = 21;
206pub const SE_INTP_PERG: c_int = 22;
207pub const SE_NPLANETS: c_int = 23;
208pub const SE_PLMOON_OFFSET: c_int = 9000;
209pub const SE_AST_OFFSET: c_int = 10000;
210pub const SE_VARUNA: c_int = SE_AST_OFFSET + 20000;
211pub const SE_FICT_OFFSET: c_int = 40;
212pub const SE_FICT_OFFSET_1: c_int = 39;
213pub const SE_FICT_MAX: c_int = 999;
214pub const SE_NFICT_ELEM: c_int = 15;
215pub const SE_COMET_OFFSET: c_int = 1000;
216pub const SE_NALL_NAT_POINTS: c_int = SE_NPLANETS + SE_NFICT_ELEM;
217
218// Hamburger/Uranian planets
219pub const SE_CUPIDO: c_int = 40;
220pub const SE_HADES: c_int = 41;
221pub const SE_ZEUS: c_int = 42;
222pub const SE_KRONOS: c_int = 43;
223pub const SE_APOLLON: c_int = 44;
224pub const SE_ADMETOS: c_int = 45;
225pub const SE_VULKANUS: c_int = 46;
226pub const SE_POSEIDON: c_int = 47;
227pub const SE_ISIS: c_int = 48;
228pub const SE_NIBIRU: c_int = 49;
229pub const SE_HARRINGTON: c_int = 50;
230pub const SE_NEPTUNE_LEVERRIER: c_int = 51;
231pub const SE_NEPTUNE_ADAMS: c_int = 52;
232pub const SE_PLUTO_LOWELL: c_int = 53;
233pub const SE_PLUTO_PICKERING: c_int = 54;
234pub const SE_VULCAN: c_int = 55;
235pub const SE_WHITE_MOON: c_int = 56;
236pub const SE_PROSERPINA: c_int = 57;
237pub const SE_WALDEMATH: c_int = 58;
238pub const SE_FIXSTAR: c_int = -10;
239
240pub const SE_FNAME_DE200: &str = "de200.eph";
241pub const SE_FNAME_DE403: &str = "de403.eph";
242pub const SE_FNAME_DE404: &str = "de404.eph";
243pub const SE_FNAME_DE405: &str = "de405.eph";
244pub const SE_FNAME_DE406: &str = "de406.eph";
245pub const SE_FNAME_DE431: &str = "de431.eph";
246pub const SE_FNAME_DFT: &str = SE_FNAME_DE431;
247pub const SE_FNAME_DFT2: &str = SE_FNAME_DE406;
248
249pub const SE_STARFILE_OLD: &str = "fixstars.cat";
250pub const SE_STARFILE: &str = "sefstars.txt";
251pub const SE_ASTNAMFILE: &str = "seasnam.txt";
252pub const SE_FICTFILE: &str = "seorbel.txt";
253
254pub const SE_DE_NUMBER: c_int = 431;
255
256// House/angle identifiers
257pub const SE_ASC: c_int = 0;
258pub const SE_MC: c_int = 1;
259pub const SE_ARMC: c_int = 2;
260pub const SE_VERTEX: c_int = 3;
261pub const SE_EQUASC: c_int = 4;
262pub const SE_COASC1: c_int = 5;
263pub const SE_COASC2: c_int = 6;
264pub const SE_POLASC: c_int = 7;
265pub const SE_NASCMC: c_int = 8;
266
267// =============================================================================
268// Calculation flags for swe_calc()
269// =============================================================================
270pub const SEFLG_JPLEPH: int32 = 1;
271pub const SEFLG_SWIEPH: int32 = 2;
272pub const SEFLG_MOSEPH: int32 = 4;
273pub const SEFLG_HELCTR: int32 = 8;
274pub const SEFLG_TRUEPOS: int32 = 16;
275pub const SEFLG_J2000: int32 = 32;
276pub const SEFLG_NONUT: int32 = 64;
277pub const SEFLG_SPEED3: int32 = 128;
278pub const SEFLG_SPEED: int32 = 256;
279pub const SEFLG_NOGDEFL: int32 = 512;
280pub const SEFLG_NOABERR: int32 = 1024;
281pub const SEFLG_ASTROMETRIC: int32 = SEFLG_NOABERR | SEFLG_NOGDEFL;
282pub const SEFLG_EQUATORIAL: int32 = 2 * 1024;
283pub const SEFLG_XYZ: int32 = 4 * 1024;
284pub const SEFLG_RADIANS: int32 = 8 * 1024;
285pub const SEFLG_BARYCTR: int32 = 16 * 1024;
286pub const SEFLG_TOPOCTR: int32 = 32 * 1024;
287pub const SEFLG_ORBEL_AA: int32 = SEFLG_TOPOCTR;
288pub const SEFLG_TROPICAL: int32 = 0;
289pub const SEFLG_SIDEREAL: int32 = 64 * 1024;
290pub const SEFLG_ICRS: int32 = 128 * 1024;
291pub const SEFLG_DPSIDEPS_1980: int32 = 256 * 1024;
292pub const SEFLG_JPLHOR: int32 = SEFLG_DPSIDEPS_1980;
293pub const SEFLG_JPLHOR_APPROX: int32 = 512 * 1024;
294pub const SEFLG_CENTER_BODY: int32 = 1024 * 1024;
295pub const SEFLG_DEFAULTEPH: int32 = SEFLG_SWIEPH;
296
297// =============================================================================
298// Sidereal modes (ayanamsas)
299// =============================================================================
300pub const SE_SIDM_FAGAN_BRADLEY: c_int = 0;
301pub const SE_SIDM_LAHIRI: c_int = 1;
302pub const SE_SIDM_DELUCE: c_int = 2;
303pub const SE_SIDM_RAMAN: c_int = 3;
304pub const SE_SIDM_USHASHASHI: c_int = 4;
305pub const SE_SIDM_KRISHNAMURTI: c_int = 5;
306pub const SE_SIDM_DJWHAL_KHUL: c_int = 6;
307pub const SE_SIDM_YUKTESHWAR: c_int = 7;
308pub const SE_SIDM_JN_BHASIN: c_int = 8;
309pub const SE_SIDM_BABYL_KUGLER1: c_int = 9;
310pub const SE_SIDM_BABYL_KUGLER2: c_int = 10;
311pub const SE_SIDM_BABYL_KUGLER3: c_int = 11;
312pub const SE_SIDM_BABYL_HUBER: c_int = 12;
313pub const SE_SIDM_BABYL_ETPSC: c_int = 13;
314pub const SE_SIDM_ALDEBARAN_15TAU: c_int = 14;
315pub const SE_SIDM_HIPPARCHOS: c_int = 15;
316pub const SE_SIDM_SASSANIAN: c_int = 16;
317pub const SE_SIDM_GALCENT_0SAG: c_int = 17;
318pub const SE_SIDM_J2000: c_int = 18;
319pub const SE_SIDM_J1900: c_int = 19;
320pub const SE_SIDM_B1950: c_int = 20;
321pub const SE_SIDM_SURYASIDDHANTA: c_int = 21;
322pub const SE_SIDM_SURYASIDDHANTA_MSUN: c_int = 22;
323pub const SE_SIDM_ARYABHATA: c_int = 23;
324pub const SE_SIDM_ARYABHATA_MSUN: c_int = 24;
325pub const SE_SIDM_SS_REVATI: c_int = 25;
326pub const SE_SIDM_SS_CITRA: c_int = 26;
327pub const SE_SIDM_TRUE_CITRA: c_int = 27;
328pub const SE_SIDM_TRUE_REVATI: c_int = 28;
329pub const SE_SIDM_TRUE_PUSHYA: c_int = 29;
330pub const SE_SIDM_GALCENT_RGILBRAND: c_int = 30;
331pub const SE_SIDM_GALEQU_IAU1958: c_int = 31;
332pub const SE_SIDM_GALEQU_TRUE: c_int = 32;
333pub const SE_SIDM_GALEQU_MULA: c_int = 33;
334pub const SE_SIDM_GALALIGN_MARDYKS: c_int = 34;
335pub const SE_SIDM_TRUE_MULA: c_int = 35;
336pub const SE_SIDM_GALCENT_MULA_WILHELM: c_int = 36;
337pub const SE_SIDM_ARYABHATA_522: c_int = 37;
338pub const SE_SIDM_BABYL_BRITTON: c_int = 38;
339pub const SE_SIDM_TRUE_SHEORAN: c_int = 39;
340pub const SE_SIDM_GALCENT_COCHRANE: c_int = 40;
341pub const SE_SIDM_GALEQU_FIORENZA: c_int = 41;
342pub const SE_SIDM_VALENS_MOON: c_int = 42;
343pub const SE_SIDM_LAHIRI_1940: c_int = 43;
344pub const SE_SIDM_LAHIRI_VP285: c_int = 44;
345pub const SE_SIDM_KRISHNAMURTI_VP291: c_int = 45;
346pub const SE_SIDM_LAHIRI_ICRC: c_int = 46;
347pub const SE_SIDM_USER: c_int = 255;
348pub const SE_NSIDM_PREDEF: c_int = 47;
349
350// Sidereal mode bits
351pub const SE_SIDBITS: c_int = 256;
352pub const SE_SIDBIT_ECL_T0: c_int = 256;
353pub const SE_SIDBIT_SSY_PLANE: c_int = 512;
354pub const SE_SIDBIT_USER_UT: c_int = 1024;
355pub const SE_SIDBIT_ECL_DATE: c_int = 2048;
356pub const SE_SIDBIT_NO_PREC_OFFSET: c_int = 4096;
357pub const SE_SIDBIT_PREC_ORIG: c_int = 8192;
358
359// =============================================================================
360// Node/apse bits
361// =============================================================================
362pub const SE_NODBIT_MEAN: c_int = 1;
363pub const SE_NODBIT_OSCU: c_int = 2;
364pub const SE_NODBIT_OSCU_BAR: c_int = 4;
365pub const SE_NODBIT_FOPOINT: c_int = 256;
366
367// =============================================================================
368// Eclipse flags
369// =============================================================================
370pub const SE_ECL_CENTRAL: int32 = 1;
371pub const SE_ECL_NONCENTRAL: int32 = 2;
372pub const SE_ECL_TOTAL: int32 = 4;
373pub const SE_ECL_ANNULAR: int32 = 8;
374pub const SE_ECL_PARTIAL: int32 = 16;
375pub const SE_ECL_ANNULAR_TOTAL: int32 = 32;
376pub const SE_ECL_HYBRID: int32 = 32;
377pub const SE_ECL_PENUMBRAL: int32 = 64;
378pub const SE_ECL_VISIBLE: int32 = 128;
379pub const SE_ECL_MAX_VISIBLE: int32 = 256;
380pub const SE_ECL_1ST_VISIBLE: int32 = 512;
381pub const SE_ECL_PARTBEG_VISIBLE: int32 = 512;
382pub const SE_ECL_2ND_VISIBLE: int32 = 1024;
383pub const SE_ECL_TOTBEG_VISIBLE: int32 = 1024;
384pub const SE_ECL_3RD_VISIBLE: int32 = 2048;
385pub const SE_ECL_TOTEND_VISIBLE: int32 = 2048;
386pub const SE_ECL_4TH_VISIBLE: int32 = 4096;
387pub const SE_ECL_PARTEND_VISIBLE: int32 = 4096;
388pub const SE_ECL_PENUMBBEG_VISIBLE: int32 = 8192;
389pub const SE_ECL_PENUMBEND_VISIBLE: int32 = 16384;
390pub const SE_ECL_OCC_BEG_DAYLIGHT: int32 = 8192;
391pub const SE_ECL_OCC_END_DAYLIGHT: int32 = 16384;
392pub const SE_ECL_ALLTYPES_SOLAR: int32 = SE_ECL_CENTRAL | SE_ECL_NONCENTRAL | SE_ECL_TOTAL | SE_ECL_ANNULAR | SE_ECL_PARTIAL | SE_ECL_ANNULAR_TOTAL;
393pub const SE_ECL_ALLTYPES_LUNAR: int32 = SE_ECL_TOTAL | SE_ECL_PARTIAL | SE_ECL_PENUMBRAL;
394pub const SE_ECL_ONE_TRY: int32 = 32 * 1024;
395
396// =============================================================================
397// Rise/transit flags
398// =============================================================================
399pub const SE_CALC_RISE: c_int = 1;
400pub const SE_CALC_SET: c_int = 2;
401pub const SE_CALC_MTRANSIT: c_int = 4;
402pub const SE_CALC_ITRANSIT: c_int = 8;
403pub const SE_BIT_DISC_CENTER: c_int = 256;
404pub const SE_BIT_DISC_BOTTOM: c_int = 8192;
405pub const SE_BIT_GEOCTR_NO_ECL_LAT: c_int = 128;
406pub const SE_BIT_NO_REFRACTION: c_int = 512;
407pub const SE_BIT_CIVIL_TWILIGHT: c_int = 1024;
408pub const SE_BIT_NAUTIC_TWILIGHT: c_int = 2048;
409pub const SE_BIT_ASTRO_TWILIGHT: c_int = 4096;
410pub const SE_BIT_FIXED_DISC_SIZE: c_int = 16384;
411pub const SE_BIT_FORCE_SLOW_METHOD: c_int = 32768;
412pub const SE_BIT_HINDU_RISING: c_int = SE_BIT_DISC_CENTER | SE_BIT_NO_REFRACTION | SE_BIT_GEOCTR_NO_ECL_LAT;
413
414// Azimuth/altitude conversion
415pub const SE_ECL2HOR: c_int = 0;
416pub const SE_EQU2HOR: c_int = 1;
417pub const SE_HOR2ECL: c_int = 0;
418pub const SE_HOR2EQU: c_int = 1;
419
420// Refraction
421pub const SE_TRUE_TO_APP: c_int = 0;
422pub const SE_APP_TO_TRUE: c_int = 1;
423
424// =============================================================================
425// Heliacal event types
426// =============================================================================
427pub const SE_HELIACAL_RISING: c_int = 1;
428pub const SE_HELIACAL_SETTING: c_int = 2;
429pub const SE_MORNING_FIRST: c_int = SE_HELIACAL_RISING;
430pub const SE_EVENING_LAST: c_int = SE_HELIACAL_SETTING;
431pub const SE_EVENING_FIRST: c_int = 3;
432pub const SE_MORNING_LAST: c_int = 4;
433pub const SE_ACRONYCHAL_RISING: c_int = 5;
434pub const SE_ACRONYCHAL_SETTING: c_int = 6;
435pub const SE_COSMICAL_SETTING: c_int = SE_ACRONYCHAL_SETTING;
436
437// Heliacal flags
438pub const SE_HELFLAG_LONG_SEARCH: int32 = 128;
439pub const SE_HELFLAG_HIGH_PRECISION: int32 = 256;
440pub const SE_HELFLAG_OPTICAL_PARAMS: int32 = 512;
441pub const SE_HELFLAG_NO_DETAILS: int32 = 1024;
442pub const SE_HELFLAG_SEARCH_1_PERIOD: int32 = 1 << 11;
443pub const SE_HELFLAG_VISLIM_DARK: int32 = 1 << 12;
444pub const SE_HELFLAG_VISLIM_NOMOON: int32 = 1 << 13;
445pub const SE_HELFLAG_VISLIM_PHOTOPIC: int32 = 1 << 14;
446pub const SE_HELFLAG_VISLIM_SCOTOPIC: int32 = 1 << 15;
447pub const SE_HELFLAG_AV: int32 = 1 << 16;
448pub const SE_HELFLAG_AVKIND_VR: int32 = 1 << 16;
449pub const SE_HELFLAG_AVKIND_PTO: int32 = 1 << 17;
450pub const SE_HELFLAG_AVKIND_MIN7: int32 = 1 << 18;
451pub const SE_HELFLAG_AVKIND_MIN9: int32 = 1 << 19;
452pub const SE_HELFLAG_AVKIND: int32 = SE_HELFLAG_AVKIND_VR | SE_HELFLAG_AVKIND_PTO | SE_HELFLAG_AVKIND_MIN7 | SE_HELFLAG_AVKIND_MIN9;
453pub const SE_HELIACAL_AVKIND: int32 = SE_HELFLAG_AVKIND;
454
455pub const SE_HELIACAL_HIGH_PRECISION: int32 = SE_HELFLAG_HIGH_PRECISION;
456pub const SE_HELIACAL_LONG_SEARCH: int32 = SE_HELFLAG_LONG_SEARCH;
457pub const SE_HELIACAL_NO_DETAILS: int32 = SE_HELFLAG_NO_DETAILS;
458pub const SE_HELIACAL_OPTICAL_PARAMS: int32 = SE_HELFLAG_OPTICAL_PARAMS;
459pub const SE_HELIACAL_SEARCH_1_PERIOD: int32 = SE_HELFLAG_SEARCH_1_PERIOD;
460pub const SE_HELIACAL_VISLIM_DARK: int32 = SE_HELFLAG_VISLIM_DARK;
461pub const SE_HELIACAL_VISLIM_NOMOON: int32 = SE_HELFLAG_VISLIM_NOMOON;
462pub const SE_HELIACAL_VISLIM_PHOTOPIC: int32 = SE_HELFLAG_VISLIM_PHOTOPIC;
463
464pub const SE_PHOTOPIC_FLAG: c_int = 0;
465pub const SE_SCOTOPIC_FLAG: c_int = 1;
466pub const SE_MIXEDOPIC_FLAG: c_int = 2;
467
468// =============================================================================
469// Split degree flags
470// =============================================================================
471pub const SE_SPLIT_DEG_ROUND_SEC: c_int = 1;
472pub const SE_SPLIT_DEG_ROUND_MIN: c_int = 2;
473pub const SE_SPLIT_DEG_ROUND_DEG: c_int = 4;
474pub const SE_SPLIT_DEG_ZODIACAL: c_int = 8;
475pub const SE_SPLIT_DEG_NAKSHATRA: c_int = 1024;
476pub const SE_SPLIT_DEG_KEEP_SIGN: c_int = 16;
477pub const SE_SPLIT_DEG_KEEP_DEG: c_int = 32;
478
479// =============================================================================
480// Unit conversions
481// =============================================================================
482pub const SE_AUNIT_TO_KM: c_double = 149597870.700;
483pub const SE_AUNIT_TO_LIGHTYEAR: c_double = 1.0 / 63241.07708427;
484pub const SE_AUNIT_TO_PARSEC: c_double = 1.0 / 206264.8062471;
485
486// Degree constants (in centiseconds)
487pub const DEG: centisec = 360000;
488pub const DEG7_30: centisec = 2700000;
489pub const DEG15: centisec = 15 * DEG;
490pub const DEG24: centisec = 24 * DEG;
491pub const DEG30: centisec = 30 * DEG;
492pub const DEG60: centisec = 60 * DEG;
493pub const DEG90: centisec = 90 * DEG;
494pub const DEG120: centisec = 120 * DEG;
495pub const DEG150: centisec = 150 * DEG;
496pub const DEG180: centisec = 180 * DEG;
497pub const DEG270: centisec = 270 * DEG;
498pub const DEG360: centisec = 360 * DEG;
499
500pub const SE_MAX_STNAME: usize = 256;
501
502// =============================================================================
503// Delta T models
504// =============================================================================
505pub const SE_TIDAL_DE200: c_double = -23.8946;
506pub const SE_TIDAL_DE403: c_double = -25.580;
507pub const SE_TIDAL_DE404: c_double = -25.580;
508pub const SE_TIDAL_DE405: c_double = -25.826;
509pub const SE_TIDAL_DE406: c_double = -25.826;
510pub const SE_TIDAL_DE421: c_double = -25.85;
511pub const SE_TIDAL_DE422: c_double = -25.85;
512pub const SE_TIDAL_DE430: c_double = -25.82;
513pub const SE_TIDAL_DE431: c_double = -25.80;
514pub const SE_TIDAL_DE441: c_double = -25.936;
515pub const SE_TIDAL_DEFAULT: c_double = SE_TIDAL_DE431;
516pub const SE_TIDAL_AUTOMATIC: c_double = 999999.0;
517pub const SE_TIDAL_26: c_double = -26.0;
518pub const SE_TIDAL_STEPHENSON_2016: c_double = -25.85;
519pub const SE_TIDAL_MOSEPH: c_double = SE_TIDAL_DE404;
520pub const SE_TIDAL_SWIEPH: c_double = SE_TIDAL_DEFAULT;
521pub const SE_TIDAL_JPLEPH: c_double = SE_TIDAL_DEFAULT;
522
523pub const SE_MODEL_DELTAT: c_int = 0;
524pub const SE_MODEL_PREC_LONGTERM: c_int = 1;
525pub const SE_MODEL_PREC_SHORTTERM: c_int = 2;
526pub const SE_MODEL_NUT: c_int = 3;
527pub const SE_MODEL_BIAS: c_int = 4;
528pub const SE_MODEL_JPLHOR_MODE: c_int = 5;
529pub const SE_MODEL_JPLHORA_MODE: c_int = 6;
530pub const SE_MODEL_SIDT: c_int = 7;
531pub const SE_DELTAT_AUTOMATIC: c_double = -1E-10;
532
533// =============================================================================
534// FFI Function declarations
535// =============================================================================
536
537#[link(name = "swisseph")]
538extern "C" {
539    // Version and path
540    pub fn swe_version(s: *mut c_char) -> *mut c_char;
541    pub fn swe_get_library_path(s: *mut c_char) -> *mut c_char;
542
543    // Core calculation functions
544    pub fn swe_calc(tjd: c_double, ipl: c_int, iflag: int32, xx: *mut c_double, serr: *mut c_char) -> int32;
545    pub fn swe_calc_ut(tjd_ut: c_double, ipl: int32, iflag: int32, xx: *mut c_double, serr: *mut c_char) -> int32;
546    pub fn swe_calc_pctr(tjd: c_double, ipl: int32, iplctr: int32, iflag: int32, xxret: *mut c_double, serr: *mut c_char) -> int32;
547
548    // Fixed stars
549    pub fn swe_fixstar(star: *mut c_char, tjd: c_double, iflag: int32, xx: *mut c_double, serr: *mut c_char) -> int32;
550    pub fn swe_fixstar_ut(star: *mut c_char, tjd_ut: c_double, iflag: int32, xx: *mut c_double, serr: *mut c_char) -> int32;
551    pub fn swe_fixstar_mag(star: *mut c_char, mag: *mut c_double, serr: *mut c_char) -> int32;
552    pub fn swe_fixstar2(star: *mut c_char, tjd: c_double, iflag: int32, xx: *mut c_double, serr: *mut c_char) -> int32;
553    pub fn swe_fixstar2_ut(star: *mut c_char, tjd_ut: c_double, iflag: int32, xx: *mut c_double, serr: *mut c_char) -> int32;
554    pub fn swe_fixstar2_mag(star: *mut c_char, mag: *mut c_double, serr: *mut c_char) -> int32;
555
556    // Configuration
557    pub fn swe_close();
558    pub fn swe_set_ephe_path(path: *const c_char);
559    pub fn swe_set_jpl_file(fname: *const c_char);
560    pub fn swe_get_planet_name(ipl: c_int, spname: *mut c_char) -> *mut c_char;
561    pub fn swe_set_topo(geolon: c_double, geolat: c_double, geoalt: c_double);
562    pub fn swe_set_sid_mode(sid_mode: int32, t0: c_double, ayan_t0: c_double);
563
564    // Ayanamsa
565    pub fn swe_get_ayanamsa_ex(tjd_et: c_double, iflag: int32, daya: *mut c_double, serr: *mut c_char) -> int32;
566    pub fn swe_get_ayanamsa_ex_ut(tjd_ut: c_double, iflag: int32, daya: *mut c_double, serr: *mut c_char) -> int32;
567    pub fn swe_get_ayanamsa(tjd_et: c_double) -> c_double;
568    pub fn swe_get_ayanamsa_ut(tjd_ut: c_double) -> c_double;
569    pub fn swe_get_ayanamsa_name(isidmode: int32) -> *const c_char;
570
571    // Date/time functions
572    pub fn swe_date_conversion(y: c_int, m: c_int, d: c_int, utime: c_double, c: c_char, tjd: *mut c_double) -> c_int;
573    pub fn swe_julday(year: c_int, month: c_int, day: c_int, hour: c_double, gregflag: c_int) -> c_double;
574    pub fn swe_revjul(jd: c_double, gregflag: c_int, jyear: *mut c_int, jmon: *mut c_int, jday: *mut c_int, jut: *mut c_double);
575    pub fn swe_utc_to_jd(iyear: int32, imonth: int32, iday: int32, ihour: int32, imin: int32, dsec: c_double, gregflag: int32, dret: *mut c_double, serr: *mut c_char) -> int32;
576    pub fn swe_jdet_to_utc(tjd_et: c_double, gregflag: int32, iyear: *mut int32, imonth: *mut int32, iday: *mut int32, ihour: *mut int32, imin: *mut int32, dsec: *mut c_double);
577    pub fn swe_jdut1_to_utc(tjd_ut: c_double, gregflag: int32, iyear: *mut int32, imonth: *mut int32, iday: *mut int32, ihour: *mut int32, imin: *mut int32, dsec: *mut c_double);
578    pub fn swe_utc_time_zone(iyear: int32, imonth: int32, iday: int32, ihour: int32, imin: int32, dsec: c_double, d_timezone: c_double, iyear_out: *mut int32, imonth_out: *mut int32, iday_out: *mut int32, ihour_out: *mut int32, imin_out: *mut int32, dsec_out: *mut c_double);
579
580    // House calculation
581    pub fn swe_houses(tjd_ut: c_double, geolat: c_double, geolon: c_double, hsys: c_int, cusps: *mut c_double, ascmc: *mut c_double) -> c_int;
582    pub fn swe_houses_ex(tjd_ut: c_double, iflag: int32, geolat: c_double, geolon: c_double, hsys: c_int, cusps: *mut c_double, ascmc: *mut c_double) -> c_int;
583    pub fn swe_houses_ex2(tjd_ut: c_double, iflag: int32, geolat: c_double, geolon: c_double, hsys: c_int, cusps: *mut c_double, ascmc: *mut c_double, cusp_speed: *mut c_double, ascmc_speed: *mut c_double, serr: *mut c_char) -> c_int;
584    pub fn swe_houses_armc(armc: c_double, geolat: c_double, eps: c_double, hsys: c_int, cusps: *mut c_double, ascmc: *mut c_double) -> c_int;
585    pub fn swe_houses_armc_ex2(armc: c_double, geolat: c_double, eps: c_double, hsys: c_int, cusps: *mut c_double, ascmc: *mut c_double, cusp_speed: *mut c_double, ascmc_speed: *mut c_double, serr: *mut c_char) -> c_int;
586    pub fn swe_house_pos(armc: c_double, geolat: c_double, eps: c_double, hsys: c_int, xpin: *mut c_double, serr: *mut c_char) -> c_double;
587    pub fn swe_house_name(hsys: c_int) -> *const c_char;
588
589    // Eclipse functions
590    pub fn swe_sol_eclipse_where(tjd: c_double, ifl: int32, geopos: *mut c_double, attr: *mut c_double, serr: *mut c_char) -> int32;
591    pub fn swe_sol_eclipse_how(tjd: c_double, ifl: int32, geopos: *mut c_double, attr: *mut c_double, serr: *mut c_char) -> int32;
592    pub fn swe_sol_eclipse_when_loc(tjd_start: c_double, ifl: int32, geopos: *mut c_double, tret: *mut c_double, attr: *mut c_double, backward: int32, serr: *mut c_char) -> int32;
593    pub fn swe_sol_eclipse_when_glob(tjd_start: c_double, ifl: int32, ifltype: int32, tret: *mut c_double, backward: int32, serr: *mut c_char) -> int32;
594    pub fn swe_lun_occult_where(tjd: c_double, ipl: int32, starname: *mut c_char, ifl: int32, geopos: *mut c_double, attr: *mut c_double, serr: *mut c_char) -> int32;
595    pub fn swe_lun_occult_when_loc(tjd_start: c_double, ipl: int32, starname: *mut c_char, ifl: int32, geopos: *mut c_double, tret: *mut c_double, attr: *mut c_double, backward: int32, serr: *mut c_char) -> int32;
596    pub fn swe_lun_occult_when_glob(tjd_start: c_double, ipl: int32, starname: *mut c_char, ifl: int32, ifltype: int32, tret: *mut c_double, backward: int32, serr: *mut c_char) -> int32;
597    pub fn swe_lun_eclipse_how(tjd_ut: c_double, ifl: int32, geopos: *mut c_double, attr: *mut c_double, serr: *mut c_char) -> int32;
598    pub fn swe_lun_eclipse_when(tjd_start: c_double, ifl: int32, ifltype: int32, tret: *mut c_double, backward: int32, serr: *mut c_char) -> int32;
599    pub fn swe_lun_eclipse_when_loc(tjd_start: c_double, ifl: int32, geopos: *mut c_double, tret: *mut c_double, attr: *mut c_double, backward: int32, serr: *mut c_char) -> int32;
600
601    // Rise/set/transit
602    pub fn swe_rise_trans(tjd_ut: c_double, ipl: int32, starname: *mut c_char, epheflag: int32, rsmi: int32, geopos: *mut c_double, atpress: c_double, attemp: c_double, tret: *mut c_double, serr: *mut c_char) -> int32;
603    pub fn swe_rise_trans_true_hor(tjd_ut: c_double, ipl: int32, starname: *mut c_char, epheflag: int32, rsmi: int32, geopos: *mut c_double, atpress: c_double, attemp: c_double, horhgt: c_double, tret: *mut c_double, serr: *mut c_char) -> int32;
604
605    // Phenomena
606    pub fn swe_pheno(tjd: c_double, ipl: int32, iflag: int32, attr: *mut c_double, serr: *mut c_char) -> int32;
607    pub fn swe_pheno_ut(tjd_ut: c_double, ipl: int32, iflag: int32, attr: *mut c_double, serr: *mut c_char) -> int32;
608
609    // Azimuth/altitude
610    pub fn swe_azalt(tjd_ut: c_double, calc_flag: int32, geopos: *mut c_double, atpress: c_double, attemp: c_double, xin: *mut c_double, xaz: *mut c_double);
611    pub fn swe_azalt_rev(tjd_ut: c_double, calc_flag: int32, geopos: *mut c_double, xin: *mut c_double, xout: *mut c_double);
612    pub fn swe_refrac(inalt: c_double, atpress: c_double, attemp: c_double, calc_flag: int32) -> c_double;
613    pub fn swe_refrac_extended(inalt: c_double, geoalt: c_double, atpress: c_double, attemp: c_double, lapse_rate: c_double, calc_flag: int32, dret: *mut c_double) -> c_double;
614    pub fn swe_set_lapse_rate(lapse_rate: c_double);
615
616    // Nodes and apsides
617    pub fn swe_nod_aps(tjd_et: c_double, ipl: int32, iflag: int32, method: int32, xnasc: *mut c_double, xndsc: *mut c_double, xperi: *mut c_double, xaphe: *mut c_double, serr: *mut c_char) -> int32;
618    pub fn swe_nod_aps_ut(tjd_ut: c_double, ipl: int32, iflag: int32, method: int32, xnasc: *mut c_double, xndsc: *mut c_double, xperi: *mut c_double, xaphe: *mut c_double, serr: *mut c_char) -> int32;
619    pub fn swe_get_orbital_elements(tjd_et: c_double, ipl: int32, iflag: int32, dret: *mut c_double, serr: *mut c_char) -> int32;
620    pub fn swe_orbit_max_min_true_distance(tjd_et: c_double, ipl: int32, iflag: int32, dmax: *mut c_double, dmin: *mut c_double, dtrue: *mut c_double, serr: *mut c_char) -> int32;
621
622    // Delta T
623    pub fn swe_deltat(tjd: c_double) -> c_double;
624    pub fn swe_deltat_ex(tjd: c_double, iflag: int32, serr: *mut c_char) -> c_double;
625    pub fn swe_time_equ(tjd: c_double, te: *mut c_double, serr: *mut c_char) -> int32;
626    pub fn swe_lmt_to_lat(tjd_lmt: c_double, geolon: c_double, tjd_lat: *mut c_double, serr: *mut c_char) -> int32;
627    pub fn swe_lat_to_lmt(tjd_lat: c_double, geolon: c_double, tjd_lmt: *mut c_double, serr: *mut c_char) -> int32;
628
629    // Sidereal time
630    pub fn swe_sidtime0(tjd_ut: c_double, eps: c_double, nut: c_double) -> c_double;
631    pub fn swe_sidtime(tjd_ut: c_double) -> c_double;
632    pub fn swe_set_interpolate_nut(do_interpolate: AS_BOOL);
633
634    // Coordinate transformation
635    pub fn swe_cotrans(xpo: *mut c_double, xpn: *mut c_double, eps: c_double);
636    pub fn swe_cotrans_sp(xpo: *mut c_double, xpn: *mut c_double, eps: c_double);
637
638    // Tidal acceleration
639    pub fn swe_get_tid_acc() -> c_double;
640    pub fn swe_set_tid_acc(t_acc: c_double);
641    pub fn swe_set_delta_t_userdef(dt: c_double);
642
643    // Normalization
644    pub fn swe_degnorm(x: c_double) -> c_double;
645    pub fn swe_radnorm(x: c_double) -> c_double;
646    pub fn swe_rad_midp(x1: c_double, x0: c_double) -> c_double;
647    pub fn swe_deg_midp(x1: c_double, x0: c_double) -> c_double;
648    pub fn swe_split_deg(ddeg: c_double, roundflag: int32, ideg: *mut int32, imin: *mut int32, isec: *mut int32, dsecfr: *mut c_double, isgn: *mut int32);
649
650    // Centisec functions
651    pub fn swe_csnorm(p: centisec) -> centisec;
652    pub fn swe_difcsn(p1: centisec, p2: centisec) -> centisec;
653    pub fn swe_difdegn(p1: c_double, p2: c_double) -> c_double;
654    pub fn swe_difcs2n(p1: centisec, p2: centisec) -> centisec;
655    pub fn swe_difdeg2n(p1: c_double, p2: c_double) -> c_double;
656    pub fn swe_difrad2n(p1: c_double, p2: c_double) -> c_double;
657    pub fn swe_csroundsec(x: centisec) -> centisec;
658    pub fn swe_d2l(x: c_double) -> int32;
659    pub fn swe_day_of_week(jd: c_double) -> c_int;
660    pub fn swe_cs2timestr(t: CSEC, sep: c_int, suppress_zero: AS_BOOL, a: *mut c_char) -> *mut c_char;
661    pub fn swe_cs2lonlatstr(t: CSEC, pchar: c_char, mchar: c_char, s: *mut c_char) -> *mut c_char;
662    pub fn swe_cs2degstr(t: CSEC, a: *mut c_char) -> *mut c_char;
663
664    // Heliacal events
665    pub fn swe_heliacal_ut(tjdstart_ut: c_double, geopos: *mut c_double, datm: *mut c_double, dobs: *mut c_double, object_name: *mut c_char, type_event: int32, iflag: int32, dret: *mut c_double, serr: *mut c_char) -> int32;
666    pub fn swe_heliacal_pheno_ut(tjd_ut: c_double, geopos: *mut c_double, datm: *mut c_double, dobs: *mut c_double, object_name: *mut c_char, type_event: int32, helflag: int32, darr: *mut c_double, serr: *mut c_char) -> int32;
667    pub fn swe_vis_limit_mag(tjdut: c_double, geopos: *mut c_double, datm: *mut c_double, dobs: *mut c_double, object_name: *mut c_char, helflag: int32, dret: *mut c_double, serr: *mut c_char) -> int32;
668    pub fn swe_heliacal_angle(tjdut: c_double, dgeo: *mut c_double, datm: *mut c_double, dobs: *mut c_double, helflag: int32, mag: c_double, azi_obj: c_double, azi_sun: c_double, azi_moon: c_double, alt_moon: c_double, dret: *mut c_double, serr: *mut c_char) -> int32;
669    pub fn swe_topo_arcus_visionis(tjdut: c_double, dgeo: *mut c_double, datm: *mut c_double, dobs: *mut c_double, helflag: int32, mag: c_double, azi_obj: c_double, alt_obj: c_double, azi_sun: c_double, azi_moon: c_double, alt_moon: c_double, dret: *mut c_double, serr: *mut c_char) -> int32;
670
671    // Cross functions
672    pub fn swe_solcross(x2cross: c_double, jd_et: c_double, flag: int32, serr: *mut c_char) -> c_double;
673    pub fn swe_solcross_ut(x2cross: c_double, jd_ut: c_double, flag: int32, serr: *mut c_char) -> c_double;
674    pub fn swe_mooncross(x2cross: c_double, jd_et: c_double, flag: int32, serr: *mut c_char) -> c_double;
675    pub fn swe_mooncross_ut(x2cross: c_double, jd_ut: c_double, flag: int32, serr: *mut c_char) -> c_double;
676    pub fn swe_mooncross_node(jd_et: c_double, flag: int32, xlon: *mut c_double, xlat: *mut c_double, serr: *mut c_char) -> c_double;
677    pub fn swe_mooncross_node_ut(jd_ut: c_double, flag: int32, xlon: *mut c_double, xlat: *mut c_double, serr: *mut c_char) -> c_double;
678    pub fn swe_helio_cross(ipl: int32, x2cross: c_double, jd_et: c_double, iflag: int32, dir: int32, jd_cross: *mut c_double, serr: *mut c_char) -> int32;
679    pub fn swe_helio_cross_ut(ipl: int32, x2cross: c_double, jd_ut: c_double, iflag: int32, dir: int32, jd_cross: *mut c_double, serr: *mut c_char) -> int32;
680
681    // Gauquelin
682    pub fn swe_gauquelin_sector(t_ut: c_double, ipl: int32, starname: *mut c_char, iflag: int32, imeth: int32, geopos: *mut c_double, atpress: c_double, attemp: c_double, dgsect: *mut c_double, serr: *mut c_char) -> int32;
683
684    // Models
685    pub fn swe_set_astro_models(samod: *mut c_char, iflag: int32);
686    pub fn swe_get_astro_models(samod: *mut c_char, sdet: *mut c_char, iflag: int32);
687    pub fn swe_get_current_file_data(ifno: c_int, tfstart: *mut c_double, tfend: *mut c_double, denum: *mut c_int) -> *const c_char;
688}
689
690#[cfg(test)]
691mod tests {
692    use super::*;
693
694    #[test]
695    fn test_julday() {
696        unsafe {
697            let jd = swe_julday(2000, 1, 1, 12.0, SE_GREG_CAL);
698            // J2000.0 = 2451545.0
699            assert!((jd - 2451545.0).abs() < 0.0001);
700        }
701    }
702
703    #[test]
704    fn test_version() {
705        unsafe {
706            let mut buf = [0i8; 256];
707            swe_version(buf.as_mut_ptr());
708            // Version should start with a digit
709            assert!(buf[0] >= b'0' as i8 && buf[0] <= b'9' as i8);
710        }
711    }
712}