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