1#![no_std]
2extern crate alloc;
3
4use wasm_bindgen::prelude::*;
5use alloc::string::{String, ToString};
6use core::ffi::CStr;
7use js_sys::{Object, Reflect};
8
9pub mod bindings;
11
12#[allow(dead_code, non_upper_case_globals, non_camel_case_types, non_snake_case)]
13pub mod swe_bindings {
14 pub use crate::bindings::*;
15
16 pub const SE_SUN: i32 = 0;
18 pub const SE_MOON: i32 = 1;
19 pub const SE_GREG_CAL: i32 = 1;
20 pub const SEFLG_SWIEPH: i32 = 2;
21 pub const SEFLG_SPEED: i32 = 256;
22 pub const SE_SIDM_LAHIRI: i32 = 1;
23 pub const SE_SIDM_RAMAN: i32 = 3;
24 pub const SE_SIDM_KRISHNAMURTI: i32 = 5;
25 pub const SE_SIDM_TRUE_CITRA: i32 = 27;
26}
27
28#[wasm_bindgen(js_name = swe_calc_ut)]
31pub fn js_swe_calc_ut(tjd_ut: f64, ipl: i32, iflag: i32) -> Result<JsValue, JsValue> {
32 let mut xx = [0.0; 6];
33 let mut serr = [0i8; 256];
34
35 let ret = unsafe {
36 swe_bindings::swe_calc_ut(tjd_ut, ipl, iflag, xx.as_mut_ptr(), serr.as_mut_ptr())
37 };
38
39 if ret < 0 {
40 let err_msg = unsafe { CStr::from_ptr(serr.as_ptr()).to_str().unwrap_or("Unknown error") };
41 return Err(JsValue::from_str(err_msg));
42 }
43
44 let obj = Object::new();
45 Reflect::set(&obj, &"longitude".into(), &xx[0].into())?;
46 Reflect::set(&obj, &"latitude".into(), &xx[1].into())?;
47 Reflect::set(&obj, &"distance".into(), &xx[2].into())?;
48 Reflect::set(&obj, &"speed_long".into(), &xx[3].into())?;
49 Reflect::set(&obj, &"speed_lat".into(), &xx[4].into())?;
50 Reflect::set(&obj, &"speed_dist".into(), &xx[5].into())?;
51 Reflect::set(&obj, &"rc_flags".into(), &ret.into())?;
52
53 Ok(obj.into())
54}
55
56#[wasm_bindgen(js_name = swe_julday)]
57pub fn js_swe_julday(year: i32, month: i32, day: i32, hour: f64, gregflag: i32) -> f64 {
58 unsafe {
59 swe_bindings::swe_julday(year, month, day, hour, gregflag)
60 }
61}
62
63#[wasm_bindgen(js_name = swe_revjul)]
64pub fn js_swe_revjul(tjd: f64, gregflag: i32) -> JsValue {
65 let mut year = 0;
66 let mut month = 0;
67 let mut day = 0;
68 let mut hour = 0.0;
69
70 unsafe {
71 swe_bindings::swe_revjul(tjd, gregflag, &mut year, &mut month, &mut day, &mut hour);
72 }
73
74 let obj = Object::new();
75 Reflect::set(&obj, &"year".into(), &year.into()).unwrap();
76 Reflect::set(&obj, &"month".into(), &month.into()).unwrap();
77 Reflect::set(&obj, &"day".into(), &day.into()).unwrap();
78 Reflect::set(&obj, &"hour".into(), &hour.into()).unwrap();
79 obj.into()
80}
81
82#[wasm_bindgen(js_name = swe_fixstar_ut)]
83pub fn js_swe_fixstar_ut(star: &str, tjd_ut: f64, iflag: i32) -> Result<JsValue, JsValue> {
84
85 let mut star_bytes = star.as_bytes().to_vec();
87 star_bytes.push(0);
88 let star_ptr = star_bytes.as_mut_ptr() as *mut i8;
89
90 let mut xx = [0.0; 6];
91 let mut serr = [0i8; 256];
92
93 let ret = unsafe {
94 swe_bindings::swe_fixstar_ut(star_ptr, tjd_ut, iflag, xx.as_mut_ptr(), serr.as_mut_ptr())
95 };
96
97 if ret < 0 {
98 let err_msg = unsafe { CStr::from_ptr(serr.as_ptr()).to_str().unwrap_or("Unknown error") };
99 return Err(JsValue::from_str(err_msg));
100 }
101
102 let obj = Object::new();
103 Reflect::set(&obj, &"name".into(), &JsValue::from_str(star))?;
104 Reflect::set(&obj, &"longitude".into(), &xx[0].into())?;
105 Reflect::set(&obj, &"latitude".into(), &xx[1].into())?;
106 Reflect::set(&obj, &"distance".into(), &xx[2].into())?;
107 Reflect::set(&obj, &"rc_flags".into(), &ret.into())?;
108
109 Ok(obj.into())
110}
111
112#[wasm_bindgen(js_name = swe_pheno_ut)]
113pub fn js_swe_pheno_ut(tjd_ut: f64, ipl: i32, iflag: i32) -> Result<JsValue, JsValue> {
114 let mut attr = [0.0; 20];
115 let mut serr = [0i8; 256];
116
117 let ret = unsafe {
118 swe_bindings::swe_pheno_ut(tjd_ut, ipl, iflag, attr.as_mut_ptr(), serr.as_mut_ptr())
119 };
120
121 if ret < 0 {
122 let err_msg = unsafe { CStr::from_ptr(serr.as_ptr()).to_str().unwrap_or("Unknown error") };
123 return Err(JsValue::from_str(err_msg));
124 }
125
126 let obj = Object::new();
127 Reflect::set(&obj, &"phase_angle".into(), &attr[0].into())?;
128 Reflect::set(&obj, &"phase".into(), &attr[1].into())?;
129 Reflect::set(&obj, &"elongation".into(), &attr[2].into())?;
130 Reflect::set(&obj, &"diameter_app".into(), &attr[3].into())?;
131 Reflect::set(&obj, &"magnitude".into(), &attr[4].into())?;
132
133 Ok(obj.into())
134}
135
136#[wasm_bindgen(js_name = swe_set_topo)]
137pub fn js_swe_set_topo(geolon: f64, geolat: f64, geoalt: f64) {
138 unsafe {
139 swe_bindings::swe_set_topo(geolon, geolat, geoalt);
140 }
141}
142
143#[wasm_bindgen(js_name = swe_set_sid_mode)]
144pub fn js_swe_set_sid_mode(sid_mode: i32, t0: f64, ayan_t0: f64) {
145 unsafe {
146 swe_bindings::swe_set_sid_mode(sid_mode, t0, ayan_t0);
147 }
148}
149
150#[wasm_bindgen(js_name = swe_get_ayanamsa_ut)]
151pub fn js_swe_get_ayanamsa_ut(tjd_ut: f64) -> f64 {
152 unsafe {
153 swe_bindings::swe_get_ayanamsa_ut(tjd_ut)
154 }
155}
156
157#[wasm_bindgen(js_name = swe_get_planet_name)]
158pub fn js_swe_get_planet_name(ipl: i32) -> String {
159 let mut spname = [0i8; 256];
160 unsafe {
161 swe_bindings::swe_get_planet_name(ipl, spname.as_mut_ptr());
162 CStr::from_ptr(spname.as_ptr()).to_str().unwrap_or("").to_string()
163 }
164}
165
166#[wasm_bindgen(js_name = swe_sidtime)]
167pub fn js_swe_sidtime(tjd_ut: f64) -> f64 {
168 unsafe {
169 swe_bindings::swe_sidtime(tjd_ut)
170 }
171}
172
173
174#[cfg(target_arch = "wasm32")]
177mod shims {
178 use super::*;
179
180 #[unsafe(no_mangle)]
181 pub unsafe extern "C" fn sin(x: f64) -> f64 { libm::sin(x) }
182 #[unsafe(no_mangle)]
183 pub unsafe extern "C" fn cos(x: f64) -> f64 { libm::cos(x) }
184 #[unsafe(no_mangle)]
185 pub unsafe extern "C" fn tan(x: f64) -> f64 { libm::tan(x) }
186 #[unsafe(no_mangle)]
187 pub unsafe extern "C" fn asin(x: f64) -> f64 { libm::asin(x) }
188 #[unsafe(no_mangle)]
189 pub unsafe extern "C" fn acos(x: f64) -> f64 { libm::acos(x) }
190 #[unsafe(no_mangle)]
191 pub unsafe extern "C" fn atan(x: f64) -> f64 { libm::atan(x) }
192 #[unsafe(no_mangle)]
193 pub unsafe extern "C" fn atan2(y: f64, x: f64) -> f64 { libm::atan2(y, x) }
194 #[unsafe(no_mangle)]
195 pub unsafe extern "C" fn sqrt(x: f64) -> f64 { libm::sqrt(x) }
196 #[unsafe(no_mangle)]
197 pub unsafe extern "C" fn log(x: f64) -> f64 { libm::log(x) }
198 #[unsafe(no_mangle)]
199 pub unsafe extern "C" fn exp(x: f64) -> f64 { libm::exp(x) }
200 #[unsafe(no_mangle)]
201 pub unsafe extern "C" fn pow(x: f64, y: f64) -> f64 { libm::pow(x, y) }
202 #[unsafe(no_mangle)]
203 pub unsafe extern "C" fn fabs(x: f64) -> f64 { libm::fabs(x) }
204 #[unsafe(no_mangle)]
205 pub unsafe extern "C" fn ceil(x: f64) -> f64 { libm::ceil(x) }
206 #[unsafe(no_mangle)]
207 pub unsafe extern "C" fn floor(x: f64) -> f64 { libm::floor(x) }
208 #[unsafe(no_mangle)]
209 pub unsafe extern "C" fn fmod(x: f64, y: f64) -> f64 { libm::fmod(x, y) }
210 #[unsafe(no_mangle)]
211 pub unsafe extern "C" fn log10(x: f64) -> f64 { libm::log10(x) }
212
213 const MAGIC: usize = 0xDEADBEEF;
214
215 #[unsafe(no_mangle)]
216 pub unsafe extern "C" fn malloc(size: usize) -> *mut u8 {
217 unsafe {
218 let header_size = 8;
219 let total_size = size + header_size;
220 let layout = alloc::alloc::Layout::from_size_align_unchecked(total_size, 8);
221 let ptr = alloc::alloc::alloc(layout);
222
223 if ptr.is_null() { return core::ptr::null_mut(); }
224
225 let header_ptr = ptr as *mut usize;
229 *header_ptr = MAGIC;
230 *header_ptr.add(1) = total_size;
231
232 ptr.add(header_size)
234 }
235 }
236
237 #[unsafe(no_mangle)]
238 pub unsafe extern "C" fn free(ptr: *mut u8) {
239 unsafe {
240 if ptr.is_null() { return; }
241
242 let header_size = 8;
243 let real_ptr = ptr.sub(header_size);
244 let header_ptr = real_ptr as *mut usize;
245
246 if *header_ptr != MAGIC {
248 return;
250 }
251
252 let total_size = *header_ptr.add(1);
253 let layout = alloc::alloc::Layout::from_size_align_unchecked(total_size, 8);
254
255 alloc::alloc::dealloc(real_ptr, layout);
256 }
257 }
258
259 #[unsafe(no_mangle)]
260 pub unsafe extern "C" fn calloc(nmemb: usize, size: usize) -> *mut u8 {
261 unsafe {
262 let total_size = nmemb * size;
263 let ptr = malloc(total_size); if !ptr.is_null() {
265 core::ptr::write_bytes(ptr, 0, total_size);
266 }
267 ptr
268 }
269 }
270
271 #[unsafe(no_mangle)]
272 pub unsafe extern "C" fn realloc(ptr: *mut u8, new_size: usize) -> *mut u8 {
273 unsafe {
274 if ptr.is_null() {
275 return malloc(new_size);
276 }
277 if new_size == 0 {
278 free(ptr);
279 return core::ptr::null_mut();
280 }
281
282 let header_size = 8;
283 let real_ptr = ptr.sub(header_size);
284 let header_ptr = real_ptr as *mut usize;
285
286 if *header_ptr != MAGIC {
288 return core::ptr::null_mut();
292 }
293
294 let old_total_size = *header_ptr.add(1);
295 let old_user_size = old_total_size - header_size;
296
297 let new_ptr = malloc(new_size);
298 if !new_ptr.is_null() {
299 let copy_size = if old_user_size < new_size { old_user_size } else { new_size };
300 core::ptr::copy_nonoverlapping(ptr, new_ptr, copy_size);
301 free(ptr);
302 }
303 new_ptr
304 }
305 }
306
307 #[unsafe(no_mangle)]
308 pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
309 unsafe {
310 core::ptr::copy_nonoverlapping(src, dest, n);
311 dest
312 }
313 }
314
315 #[unsafe(no_mangle)]
316 pub unsafe extern "C" fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8 {
317 unsafe {
318 core::ptr::write_bytes(s, c as u8, n);
319 s
320 }
321 }
322
323 #[unsafe(no_mangle)]
324 pub unsafe extern "C" fn strcpy(dest: *mut u8, src: *const u8) -> *mut u8 {
325 unsafe {
326 let mut i = 0;
327 loop {
328 let c = *src.add(i);
329 *dest.add(i) = c;
330 if c == 0 { break; }
331 i += 1;
332 }
333 dest
334 }
335 }
336
337 #[unsafe(no_mangle)]
338 pub unsafe extern "C" fn strncpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
339 unsafe {
340 let mut i = 0;
341 while i < n {
342 let c = *src.add(i);
343 *dest.add(i) = c;
344 if c == 0 {
345 while i < n {
346 *dest.add(i) = 0;
347 i += 1;
348 }
349 break;
350 }
351 i += 1;
352 }
353 dest
354 }
355 }
356
357 #[unsafe(no_mangle)]
358 pub unsafe extern "C" fn strlen(s: *const i8) -> usize {
359 unsafe {
360 let mut len = 0;
361 while *s.add(len) != 0 {
362 len += 1;
363 }
364 len
365 }
366 }
367
368 #[unsafe(no_mangle)]
369 pub unsafe extern "C" fn strcmp(s1: *const i8, s2: *const i8) -> i32 {
370 unsafe {
371 let mut i = 0;
372 loop {
373 let c1 = *s1.add(i);
374 let c2 = *s2.add(i);
375 if c1 != c2 { return (c1 - c2) as i32; }
376 if c1 == 0 { return 0; }
377 i += 1;
378 }
379 }
380 }
381
382 #[unsafe(no_mangle)]
383 pub unsafe extern "C" fn strncmp(s1: *const i8, s2: *const i8, n: usize) -> i32 {
384 unsafe {
385 let mut i = 0;
386 while i < n {
387 let c1 = *s1.add(i);
388 let c2 = *s2.add(i);
389 if c1 != c2 { return (c1 - c2) as i32; }
390 if c1 == 0 { return 0; }
391 i += 1;
392 }
393 0
394 }
395 }
396
397 #[unsafe(no_mangle)]
398 pub unsafe extern "C" fn strstr(haystack: *const i8, needle: *const i8) -> *const i8 {
399 unsafe {
400 let needle_len = strlen(needle);
401 if needle_len == 0 { return haystack; }
402 let mut h = haystack;
403 while *h != 0 {
404 if strncmp(h, needle, needle_len) == 0 {
405 return h;
406 }
407 h = h.add(1);
408 }
409 core::ptr::null()
410 }
411 }
412
413 #[unsafe(no_mangle)]
414 pub unsafe extern "C" fn abs(j: i32) -> i32 { j.abs() }
415 #[unsafe(no_mangle)]
416 pub unsafe extern "C" fn labs(j: i64) -> i64 { j.abs() }
417
418 #[unsafe(no_mangle)]
419 pub unsafe extern "C" fn atof(_str: *const i8) -> f64 { 0.0 }
420 #[unsafe(no_mangle)]
421 pub unsafe extern "C" fn atoi(_str: *const i8) -> i32 { 0 }
422 #[unsafe(no_mangle)]
423 pub unsafe extern "C" fn atol(_str: *const i8) -> i64 { 0 }
424
425 #[unsafe(no_mangle)]
426 pub unsafe extern "C" fn fopen(_filename: *const i8, _mode: *const i8) -> *mut u8 { core::ptr::null_mut() }
427 #[unsafe(no_mangle)]
428 pub unsafe extern "C" fn fclose(_stream: *mut u8) -> i32 { 0 }
429 #[unsafe(no_mangle)]
430 pub unsafe extern "C" fn fseek(_stream: *mut u8, _offset: i64, _whence: i32) -> i32 { 0 }
431 #[unsafe(no_mangle)]
432 pub unsafe extern "C" fn ftell(_stream: *mut u8) -> i64 { 0 }
433 #[unsafe(no_mangle)]
434 pub unsafe extern "C" fn fread(_ptr: *mut u8, _size: usize, _nmemb: usize, _stream: *mut u8) -> usize { 0 }
435 #[unsafe(no_mangle)]
436 pub unsafe extern "C" fn fwrite(_ptr: *const u8, _size: usize, nmemb: usize, _stream: *mut u8) -> usize { nmemb }
437
438 #[unsafe(no_mangle)]
439 pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
440 unsafe {
441 core::ptr::copy(src, dest, n);
442 dest
443 }
444 }
445 #[unsafe(no_mangle)]
446 pub unsafe extern "C" fn fgets(_str: *mut i8, _n: i32, _stream: *mut u8) -> *mut i8 { core::ptr::null_mut() }
447 #[unsafe(no_mangle)]
448 pub unsafe extern "C" fn fflush(_stream: *mut u8) -> i32 { 0 }
449 #[unsafe(no_mangle)]
450 pub unsafe extern "C" fn exit(_status: i32) { panic!("exit called") }
451
452 #[unsafe(no_mangle)]
453 pub unsafe extern "C" fn isspace(c: i32) -> i32 {
454 if (c as u8 as char).is_whitespace() { 1 } else { 0 }
455 }
456 #[unsafe(no_mangle)]
457 pub unsafe extern "C" fn isdigit(c: i32) -> i32 {
458 if (c as u8 as char).is_ascii_digit() { 1 } else { 0 }
459 }
460 #[unsafe(no_mangle)]
461 pub unsafe extern "C" fn isalpha(c: i32) -> i32 {
462 if (c as u8 as char).is_ascii_alphabetic() { 1 } else { 0 }
463 }
464 #[unsafe(no_mangle)]
465 pub unsafe extern "C" fn isalnum(c: i32) -> i32 {
466 if (c as u8 as char).is_ascii_alphanumeric() { 1 } else { 0 }
467 }
468 #[unsafe(no_mangle)]
469 pub unsafe extern "C" fn isupper(c: i32) -> i32 {
470 if (c as u8 as char).is_ascii_uppercase() { 1 } else { 0 }
471 }
472
473 #[unsafe(no_mangle)]
474 pub unsafe extern "C" fn fseeko(_stream: *mut u8, _offset: i64, _whence: i32) -> i32 { 0 }
475 #[unsafe(no_mangle)]
476 pub unsafe extern "C" fn ftello(_stream: *mut u8) -> i64 { 0 }
477
478 #[unsafe(no_mangle)]
479 pub unsafe extern "C" fn strpbrk(s: *const i8, accept: *const i8) -> *mut i8 {
480 unsafe {
481 let mut s_ptr = s;
482 while *s_ptr != 0 {
483 let mut a_ptr = accept;
484 while *a_ptr != 0 {
485 if *s_ptr == *a_ptr {
486 return s_ptr as *mut i8;
487 }
488 a_ptr = a_ptr.add(1);
489 }
490 s_ptr = s_ptr.add(1);
491 }
492 core::ptr::null_mut()
493 }
494 }
495
496 #[unsafe(no_mangle)]
497 pub unsafe extern "C" fn memchr(s: *const u8, c: i32, n: usize) -> *mut u8 {
498 unsafe {
499 let mut i = 0;
500 while i < n {
501 if *s.add(i) == c as u8 {
502 return s.add(i) as *mut u8;
503 }
504 i += 1;
505 }
506 core::ptr::null_mut()
507 }
508 }
509
510 #[unsafe(no_mangle)]
511 pub unsafe extern "C" fn strdup(s: *const i8) -> *mut i8 {
512 unsafe {
513 let len = strlen(s);
514 let layout = alloc::alloc::Layout::from_size_align_unchecked(len + 1, 8);
515 let ptr = alloc::alloc::alloc(layout) as *mut i8;
516 if !ptr.is_null() {
517 strcpy(ptr as *mut u8, s as *const u8);
518 }
519 ptr
520 }
521 }
522
523
524 #[unsafe(no_mangle)]
525 pub unsafe extern "C" fn strcat(dest: *mut i8, src: *const i8) -> *mut i8 {
526 unsafe {
527 let len = strlen(dest);
528 strcpy(dest.add(len) as *mut u8, src as *const u8);
529 dest
530 }
531 }
532
533 #[unsafe(no_mangle)]
534 pub unsafe extern "C" fn strchr(s: *const i8, c: i32) -> *mut i8 {
535 unsafe {
536 let mut s_ptr = s;
537 loop {
538 if *s_ptr == c as i8 { return s_ptr as *mut i8; }
539 if *s_ptr == 0 { return core::ptr::null_mut(); }
540 s_ptr = s_ptr.add(1);
541 }
542 }
543 }
544
545 #[unsafe(no_mangle)]
546 pub unsafe extern "C" fn strrchr(s: *const i8, c: i32) -> *mut i8 {
547 unsafe {
548 let mut last = core::ptr::null_mut();
549 let mut s_ptr = s;
550 loop {
551 if *s_ptr == c as i8 { last = s_ptr as *mut i8; }
552 if *s_ptr == 0 { return last; }
553 s_ptr = s_ptr.add(1);
554 }
555 }
556 }
557
558 #[unsafe(no_mangle)]
559 pub unsafe extern "C" fn tolower(c: i32) -> i32 {
560 (c as u8).to_ascii_lowercase() as i32
561 }
562
563 #[unsafe(no_mangle)]
565 pub unsafe extern "C" fn dlopen(_filename: *const i8, _flag: i32) -> *mut u8 { core::ptr::null_mut() }
566 #[unsafe(no_mangle)]
567 pub unsafe extern "C" fn dlerror() -> *mut i8 { core::ptr::null_mut() }
568 #[unsafe(no_mangle)]
569 pub unsafe extern "C" fn dlsym(_handle: *mut u8, _symbol: *const i8) -> *mut u8 { core::ptr::null_mut() }
570 #[unsafe(no_mangle)]
571 pub unsafe extern "C" fn dlclose(_handle: *mut u8) -> i32 { 0 }
572 #[unsafe(no_mangle)]
573 pub unsafe extern "C" fn dladdr(_addr: *const u8, _info: *mut u8) -> i32 { 0 }
574
575 #[unsafe(no_mangle)]
577 pub unsafe extern "C" fn getenv(_name: *const i8) -> *mut i8 { core::ptr::null_mut() }
578 #[unsafe(no_mangle)]
579 pub unsafe extern "C" fn qsort(_base: *mut u8, _nmemb: usize, _size: usize, _compar: *const u8) {}
580 #[unsafe(no_mangle)]
581 pub unsafe extern "C" fn bsearch(_key: *const u8, _base: *const u8, _nmemb: usize, _size: usize, _compar: *const u8) -> *mut u8 {
582 core::ptr::null_mut()
583 }
584
585 #[unsafe(no_mangle)]
587 pub unsafe extern "C" fn rewind(_stream: *mut u8) { }
588
589 #[unsafe(no_mangle)]
591 pub unsafe extern "C" fn readlink(_path: *const i8, _buf: *mut i8, _bufsiz: usize) -> isize { -1 }
592
593 #[unsafe(no_mangle)]
595 pub unsafe extern "C" fn stat(_path: *const i8, _buf: *mut u8) -> i32 { -1 }
596}