1#![feature(c_variadic)]
3#![allow(
4 non_camel_case_types,
5 non_snake_case,
6 dead_code,
7 unused_variables,
8 unused_assignments,
9 clippy::missing_safety_doc,
10 unreachable_code,
11 clippy::too_many_arguments,
12 clippy::needless_range_loop,
13 clippy::manual_range_contains
14)]
15#![deny(deprecated)]
16
17pub mod c_types;
18pub mod helpers;
19
20pub mod aliases;
21pub mod buffers;
22pub mod checksum;
23pub mod edithdu;
24pub mod fitsio;
25pub mod fitsio2;
26pub mod scalnull;
27
28pub mod cfileio;
32pub mod drvrfile;
33pub mod drvrgsiftp;
34pub mod drvrmem;
35pub mod drvrnet;
36
37#[cfg(feature = "shared_mem")]
38pub mod drvrsmem;
39
40pub mod editcol;
41pub mod eval_defs;
42pub mod eval_f;
43pub mod eval_l;
44pub mod eval_y;
45pub mod fits_hcompress;
46pub mod fits_hdecompress;
47pub mod fitscore;
48pub mod getcol;
49pub mod getcolb;
50pub mod getcold;
51pub mod getcole;
52pub mod getcoli;
53pub mod getcolj;
54pub mod getcolk;
55pub mod getcoll;
56pub mod getcols;
57pub mod getcolsb;
58pub mod getcolui;
59pub mod getcoluj;
60pub mod getcoluk;
61pub mod getkey;
62pub mod group;
63pub mod grparser;
64pub mod histo;
65pub mod imcompress;
66pub mod iraffits;
67pub mod modkey;
68pub mod putcol;
69pub mod putcolb;
70pub mod putcold;
71pub mod putcole;
72pub mod putcoli;
73pub mod putcolj;
74pub mod putcolk;
75pub mod putcoll;
76pub mod putcols;
77pub mod putcolsb;
78pub mod putcolu;
79pub mod putcolui;
80pub mod putcoluj;
81pub mod putcoluk;
82pub mod putkey;
83pub mod quantize;
84pub mod region;
85pub mod relibc;
86pub mod simplerng;
87pub mod swapproc;
88pub mod wcssub;
89pub mod wcsutil;
90pub mod wrappers;
91pub mod zcompress;
92pub mod zuncompress;
93
94use std::{
95 ffi::{CStr, CString},
96 marker::PhantomData,
97 str::FromStr,
98 sync::{Mutex, MutexGuard},
99};
100
101use bytemuck::cast_slice;
102use fitsio::{
103 FLEN_VALUE, LONGLONG, TBIT, TBYTE, TCOMPLEX, TDBLCOMPLEX, TDOUBLE, TFLOAT, TINT, TLOGICAL,
104 TLONG, TLONGLONG, TSBYTE, TSHORT, TSTRING, TUINT, TULONG, TULONGLONG, TUSHORT, ULONGLONG,
105};
106
107use crate::c_types::*;
108
109pub(crate) static MUTEX_LOCK: Mutex<bool> = Mutex::new(false);
110
111pub(crate) fn FFLOCK<'a>() -> MutexGuard<'a, bool> {
112 MUTEX_LOCK.lock().unwrap()
113}
114
115pub(crate) fn FFUNLOCK(p: MutexGuard<'_, bool>) {
116 drop(p);
117}
118
119pub trait ToRaw {
120 fn as_raw_mut(&mut self) -> *mut Self;
121}
122
123pub trait AsMutPtr<T> {
124 fn as_mut_ptr(&self) -> *mut T;
125}
126
127impl<T> AsMutPtr<T> for Option<&mut [T]> {
128 fn as_mut_ptr(&self) -> *mut T {
129 match self {
130 Some(v) => v.as_ptr() as *mut T, None => std::ptr::null_mut(),
132 }
133 }
134}
135
136#[inline(always)]
137pub fn bb(n: u8) -> c_char {
138 n as c_char
139}
140
141#[macro_export]
142macro_rules! int_snprintf {
143 ($dst:expr, $len:expr, $($arg:tt)*) => {
144 {
145 let s = format!($($arg)*);
146 let s_bytes = s.as_bytes();
147 let mut s_len = s_bytes.len();
148
149 s_len = cmp::min($len-1, s_len);
150
151 let w = cast_slice_mut::<c_char, u8>(&mut $dst[..s_len]);
152 w.copy_from_slice(&s_bytes[..s_len]);
153 $dst[s_len] = 0; s_len as isize
156 }
157 };
158}
159
160#[macro_export]
161macro_rules! slice_to_str {
162 ($e:expr) => {
163 CStr::from_bytes_until_nul(cast_slice($e))
164 .unwrap()
165 .to_str()
166 .unwrap()
167 };
168}
169
170#[macro_export]
171macro_rules! cs {
172 ($e: expr) => {
173 cast_slice($e.to_bytes_with_nul())
174 };
175}
176
177#[macro_export]
178macro_rules! nullable_slice_cstr {
179 ($e: ident) => {
180 let $e: Option<&[c_char]> = match $e.is_null() {
181 true => None,
182 false => Some(cast_slice(CStr::from_ptr($e).to_bytes_with_nul())),
183 };
184 };
185}
186
187#[macro_export]
188macro_rules! nullable_slice_cstr_mut {
189 ($e: ident) => {
190 let mut $e: Option<&mut [c_char]> = match $e.is_null() {
191 true => None,
192 false => {
193 let _c = CStr::from_ptr($e).to_bytes_with_nul();
194 let _l = _c.len();
195
196 Some(slice::from_raw_parts_mut($e, _l))
197 }
198 };
199 };
200}
201
202#[macro_export]
203macro_rules! raw_to_slice {
204 ($e: ident) => {
205 let $e: &[c_char] = cast_slice(CStr::from_ptr($e).to_bytes_with_nul());
206 };
207}
208
209pub(crate) struct TKeywords<'a> {
210 tfields: c_int, ttype: *const *const c_char, tform: *const *const c_char, tunit: *const *const c_char, marker: PhantomData<&'a ()>,
215}
216
217impl<'a> TKeywords<'a> {
218 pub fn new(
219 tfields: c_int,
220 ttype: *const *const c_char,
221 tform: *const *const c_char,
222 tunit: *const *const c_char,
223 ) -> Self {
224 TKeywords {
225 tfields,
226 ttype,
227 tform,
228 tunit,
229 marker: PhantomData,
230 }
231 }
232
233 pub unsafe fn tkeywords_to_vecs(
234 &'a self,
235 ) -> (
236 Vec<Option<&'a [c_char]>>,
237 Vec<&'a [c_char]>,
238 Option<Vec<Option<&'a [c_char]>>>,
239 ) {
240 unsafe {
241 let ttype = core::slice::from_raw_parts(self.ttype, self.tfields as usize);
243 let mut v_ttype = Vec::new();
244
245 for item in ttype {
246 let ttype_item = if item.is_null() {
247 None
248 } else {
249 Some(cast_slice(CStr::from_ptr(*item).to_bytes_with_nul()))
250 };
251 v_ttype.push(ttype_item);
252 }
253
254 let tform = core::slice::from_raw_parts(self.tform, self.tfields as usize);
256 let mut v_tform = Vec::new();
257
258 for item in tform {
259 let tform_item = cast_slice(CStr::from_ptr(*item).to_bytes_with_nul());
260 v_tform.push(tform_item);
261 }
262
263 let mut v_tunit = Vec::new();
265 let out_tunit = if self.tunit.is_null() {
266 None
267 } else {
268 let tunit = core::slice::from_raw_parts(self.tunit, self.tfields as usize);
269
270 for item in tunit {
271 let tunit_item = if item.is_null() {
272 None
273 } else {
274 Some(cast_slice(CStr::from_ptr(*item).to_bytes_with_nul()))
275 };
276 v_tunit.push(tunit_item);
277 }
278 Some(v_tunit)
279 };
280
281 (v_ttype, v_tform, out_tunit)
282 }
283 }
284}
285
286pub(crate) fn calculate_subsection_length(blc: &[c_long], trc: &[c_long], inc: &[c_long]) -> usize {
287 assert!(blc.len() == trc.len() && blc.len() == inc.len());
288
289 let len = blc.len();
290 let mut acc: usize = 1;
291 for ii in 0..len {
292 acc *= ((trc[ii] - blc[ii]) / inc[ii] + 1) as usize; }
294 acc
295}
296
297pub(crate) fn calculate_subsection_length_unit(blc: &[c_long], trc: &[c_long]) -> usize {
298 assert!(blc.len() == trc.len());
299
300 let len = blc.len();
301 let mut acc: usize = 1;
302 for ii in 0..len {
303 acc *= ((trc[ii] - blc[ii]) + 1) as usize; }
305 acc
306}
307
308pub(crate) fn vecs_to_slices<T>(vecs: &[Vec<T>]) -> Vec<&[T]> {
309 vecs.iter().map(Vec::as_slice).collect()
310}
311
312pub(crate) fn vecs_to_slices_mut<T>(vecs: &mut [Vec<T>]) -> Vec<&mut [T]> {
313 vecs.iter_mut().map(Vec::as_mut_slice).collect()
314}
315
316#[derive(Debug, PartialEq, Clone, Copy)]
317pub enum NullCheckType {
318 None = 0, SetPixel = 1, SetNullArray = 2, }
322
323#[derive(Debug, PartialEq, Clone)]
324pub enum NullValue {
325 Float(f32),
326 Double(f64),
327 Long(c_long),
328 ULong(c_ulong),
329 LONGLONG(LONGLONG),
330 ULONGLONG(ULONGLONG),
331 Int(c_int),
332 UInt(c_uint),
333 Short(c_short),
334 UShort(c_ushort),
335 Byte(i8),
336 UByte(c_uchar),
337 Logical(c_char),
338 String(CString),
339}
340
341impl NullValue {
342 pub fn get_value_as_f64(&self) -> f64 {
343 match self {
344 NullValue::Float(v) => *v as f64,
345 NullValue::Double(v) => *v,
346 NullValue::Long(v) => *v as f64,
347 NullValue::ULong(v) => *v as f64,
348 NullValue::LONGLONG(v) => *v as f64,
349 NullValue::ULONGLONG(v) => *v as f64,
350 NullValue::Int(v) => *v as f64,
351 NullValue::UInt(v) => *v as f64,
352 NullValue::Short(v) => *v as f64,
353 NullValue::UShort(v) => *v as f64,
354 NullValue::Byte(v) => *v as f64,
355 NullValue::UByte(v) => *v as f64,
356 NullValue::Logical(v) => *v as f64,
357 _ => 0.0,
358 }
359 }
360
361 pub fn from_raw_ptr(datatype: c_int, value: *const c_void) -> Option<Self> {
362 if value.is_null() {
363 return None;
364 }
365
366 match datatype {
367 TFLOAT => Some(NullValue::Float(unsafe { *(value as *const f32) })),
368 TDOUBLE => Some(NullValue::Double(unsafe { *(value as *const f64) })),
369 TLONG => Some(NullValue::Long(unsafe { *(value as *const c_long) })),
370 TULONG => Some(NullValue::ULong(unsafe { *(value as *const c_ulong) })),
371 TLONGLONG => Some(NullValue::LONGLONG(unsafe { *(value as *const LONGLONG) })),
372 TULONGLONG => Some(NullValue::ULONGLONG(unsafe {
373 *(value as *const ULONGLONG)
374 })),
375 TINT => Some(NullValue::Int(unsafe { *(value as *const c_int) })),
376 TUINT => Some(NullValue::UInt(unsafe { *(value as *const c_uint) })),
377 TSHORT => Some(NullValue::Short(unsafe { *(value as *const c_short) })),
378 TUSHORT => Some(NullValue::UShort(unsafe { *(value as *const c_ushort) })),
379 TBYTE => Some(NullValue::UByte(unsafe { *(value as *const c_uchar) })),
380 TSBYTE => Some(NullValue::Byte(unsafe { *(value as *const i8) })),
381 TLOGICAL => Some(NullValue::Logical(unsafe { *(value as *const c_char) })),
382 TSTRING => {
383 let cstr = unsafe { CStr::from_ptr(value as *const c_char) };
384 Some(NullValue::String(cstr.to_owned()))
385 }
386 _ => None, }
388 }
389}
390
391#[derive(Debug, PartialEq)]
392pub enum KeywordDatatype<'a> {
393 TBYTE(&'a c_uchar),
394 TSBYTE(&'a c_char),
395 TSHORT(&'a c_short),
396 TUSHORT(&'a c_ushort),
397 TINT(&'a c_int),
398 TUINT(&'a c_uint),
399 TLONG(&'a c_long),
400 TULONG(&'a c_ulong),
401 TFLOAT(&'a f32),
402 TDOUBLE(&'a f64),
403 TSTRING(&'a [c_char]),
404 TLOGICAL(&'a c_int),
405 TCOMPLEX(&'a [f32; 2]),
406 TDBLCOMPLEX(&'a [f64; 2]),
407 TULONGLONG(&'a ULONGLONG),
408 TLONGLONG(&'a LONGLONG),
409 INVALID(c_int),
410}
411
412impl KeywordDatatype<'_> {
413 pub fn from_datatype(datatype: c_int, value: *const c_void) -> Self {
414 match datatype {
415 TBYTE => KeywordDatatype::TBYTE(unsafe { &*(value as *const c_uchar) }),
416 TSBYTE => KeywordDatatype::TSBYTE(unsafe { &*(value as *const c_char) }),
417 TSHORT => KeywordDatatype::TSHORT(unsafe { &*(value as *const c_short) }),
418 TUSHORT => KeywordDatatype::TUSHORT(unsafe { &*(value as *const c_ushort) }),
419 TINT => KeywordDatatype::TINT(unsafe { &*(value as *const c_int) }),
420 TUINT => KeywordDatatype::TUINT(unsafe { &*(value as *const c_uint) }),
421 TLONG => KeywordDatatype::TLONG(unsafe { &*(value as *const c_long) }),
422 TULONG => KeywordDatatype::TULONG(unsafe { &*(value as *const c_ulong) }),
423 TFLOAT => KeywordDatatype::TFLOAT(unsafe { &*(value as *const f32) }),
424 TDOUBLE => KeywordDatatype::TDOUBLE(unsafe { &*(value as *const f64) }),
425 TSTRING => KeywordDatatype::TSTRING(unsafe {
426 cast_slice(CStr::from_ptr(value as *const c_char).to_bytes_with_nul())
427 }),
428 TLOGICAL => KeywordDatatype::TLOGICAL(unsafe { &*(value as *const c_int) }),
429 TCOMPLEX => KeywordDatatype::TCOMPLEX(unsafe { &*(value as *const [f32; 2]) }),
430 TDBLCOMPLEX => KeywordDatatype::TDBLCOMPLEX(unsafe { &*(value as *const [f64; 2]) }),
431 TULONGLONG => KeywordDatatype::TULONGLONG(unsafe { &*(value as *const ULONGLONG) }),
432 TLONGLONG => KeywordDatatype::TLONGLONG(unsafe { &*(value as *const LONGLONG) }),
433 _ => KeywordDatatype::INVALID(datatype),
434 }
435 }
436
437 pub fn to_datatype_code(&self) -> c_int {
438 match self {
439 KeywordDatatype::TBYTE(_) => TBYTE,
440 KeywordDatatype::TSBYTE(_) => TSBYTE,
441 KeywordDatatype::TSHORT(_) => TSHORT,
442 KeywordDatatype::TUSHORT(_) => TUSHORT,
443 KeywordDatatype::TINT(_) => TINT,
444 KeywordDatatype::TUINT(_) => TUINT,
445 KeywordDatatype::TLONG(_) => TLONG,
446 KeywordDatatype::TULONG(_) => TULONG,
447 KeywordDatatype::TFLOAT(_) => TFLOAT,
448 KeywordDatatype::TDOUBLE(_) => TDOUBLE,
449 KeywordDatatype::TSTRING(_) => TSTRING,
450 KeywordDatatype::TLOGICAL(_) => TLOGICAL,
451 KeywordDatatype::TCOMPLEX(_) => TCOMPLEX,
452 KeywordDatatype::TDBLCOMPLEX(_) => TDBLCOMPLEX,
453 KeywordDatatype::TULONGLONG(_) => TULONGLONG,
454 KeywordDatatype::TLONGLONG(_) => TLONGLONG,
455 KeywordDatatype::INVALID(x) => *x,
456 }
457 }
458}
459
460#[derive(Debug, PartialEq)]
461pub enum KeywordDatatypeMut<'a> {
462 TBYTE(&'a mut c_uchar),
463 TSBYTE(&'a mut c_char),
464 TSHORT(&'a mut c_short),
465 TUSHORT(&'a mut c_ushort),
466 TINT(&'a mut c_int),
467 TUINT(&'a mut c_uint),
468 TLONG(&'a mut c_long),
469 TULONG(&'a mut c_ulong),
470 TFLOAT(&'a mut f32),
471 TDOUBLE(&'a mut f64),
472 TSTRING(&'a mut [c_char; FLEN_VALUE]),
473 TLOGICAL(&'a mut c_int),
474 TCOMPLEX(&'a mut [f32; 2]),
475 TDBLCOMPLEX(&'a mut [f64; 2]),
476 TULONGLONG(&'a mut ULONGLONG),
477 TLONGLONG(&'a mut LONGLONG),
478 INVALID(c_int),
479}
480
481impl KeywordDatatypeMut<'_> {
482 pub fn from_datatype(datatype: c_int, value: *mut c_void) -> Self {
483 match datatype {
484 TBYTE => KeywordDatatypeMut::TBYTE(unsafe { &mut *(value as *mut c_uchar) }),
485 TSBYTE => KeywordDatatypeMut::TSBYTE(unsafe { &mut *(value as *mut c_char) }),
486 TSHORT => KeywordDatatypeMut::TSHORT(unsafe { &mut *(value as *mut c_short) }),
487 TUSHORT => KeywordDatatypeMut::TUSHORT(unsafe { &mut *(value as *mut c_ushort) }),
488 TINT => KeywordDatatypeMut::TINT(unsafe { &mut *(value as *mut c_int) }),
489 TUINT => KeywordDatatypeMut::TUINT(unsafe { &mut *(value as *mut c_uint) }),
490 TLONG => KeywordDatatypeMut::TLONG(unsafe { &mut *(value as *mut c_long) }),
491 TULONG => KeywordDatatypeMut::TULONG(unsafe { &mut *(value as *mut c_ulong) }),
492 TFLOAT => KeywordDatatypeMut::TFLOAT(unsafe { &mut *(value as *mut f32) }),
493 TDOUBLE => KeywordDatatypeMut::TDOUBLE(unsafe { &mut *(value as *mut f64) }),
494 TSTRING => {
495 KeywordDatatypeMut::TSTRING(unsafe { &mut *(value as *mut [c_char; FLEN_VALUE]) })
496 }
497 TLOGICAL => KeywordDatatypeMut::TLOGICAL(unsafe { &mut *(value as *mut c_int) }),
498 TCOMPLEX => KeywordDatatypeMut::TCOMPLEX(unsafe { &mut *(value as *mut [f32; 2]) }),
499 TDBLCOMPLEX => {
500 KeywordDatatypeMut::TDBLCOMPLEX(unsafe { &mut *(value as *mut [f64; 2]) })
501 }
502 TULONGLONG => {
503 KeywordDatatypeMut::TULONGLONG(unsafe { &mut *(value as *mut ULONGLONG) })
504 }
505 TLONGLONG => KeywordDatatypeMut::TLONGLONG(unsafe { &mut *(value as *mut LONGLONG) }),
506 _ => KeywordDatatypeMut::INVALID(datatype),
507 }
508 }
509
510 pub fn to_datatype_code(&self) -> c_int {
511 match self {
512 KeywordDatatypeMut::TBYTE(_) => TBYTE,
513 KeywordDatatypeMut::TSBYTE(_) => TSBYTE,
514 KeywordDatatypeMut::TSHORT(_) => TSHORT,
515 KeywordDatatypeMut::TUSHORT(_) => TUSHORT,
516 KeywordDatatypeMut::TINT(_) => TINT,
517 KeywordDatatypeMut::TUINT(_) => TUINT,
518 KeywordDatatypeMut::TLONG(_) => TLONG,
519 KeywordDatatypeMut::TULONG(_) => TULONG,
520 KeywordDatatypeMut::TFLOAT(_) => TFLOAT,
521 KeywordDatatypeMut::TDOUBLE(_) => TDOUBLE,
522 KeywordDatatypeMut::TSTRING(_) => TSTRING,
523 KeywordDatatypeMut::TLOGICAL(_) => TLOGICAL,
524 KeywordDatatypeMut::TCOMPLEX(_) => TCOMPLEX,
525 KeywordDatatypeMut::TDBLCOMPLEX(_) => TDBLCOMPLEX,
526 KeywordDatatypeMut::TULONGLONG(_) => TULONGLONG,
527 KeywordDatatypeMut::TLONGLONG(_) => TLONGLONG,
528 KeywordDatatypeMut::INVALID(x) => *x,
529 }
530 }
531}
532
533pub(crate) fn bytes_per_datatype(datatype: c_int) -> Option<usize> {
534 match datatype {
535 TBIT => Some(1),
536 TBYTE => Some(1),
537 TLOGICAL => Some(1),
538 TSBYTE => Some(1),
539 TUSHORT => Some(2),
540 TSHORT => Some(2),
541 TUINT => Some(4),
542 TINT => Some(4),
543 TULONG => Some(std::mem::size_of::<c_ulong>()),
544 TLONG => Some(std::mem::size_of::<c_long>()),
545 TULONGLONG => Some(8),
546 TLONGLONG => Some(8),
547 TFLOAT => Some(4),
548 TDOUBLE => Some(8),
549 TCOMPLEX => Some(8),
550 TDBLCOMPLEX => Some(16),
551 TSTRING => Some(std::mem::size_of::<usize>()), _ => None,
553 }
554}
555
556fn atoi<F: FromStr>(input: &str) -> Result<F, <F as FromStr>::Err> {
558 let input = input.trim();
559 let i = input
560 .find(|c: char| !c.is_numeric() && c != '-' && c != '+')
561 .unwrap_or(input.len());
562 input[..i].parse::<F>()
563}
564
565fn fmt_f64(num: f64, precision: usize, exp_pad: usize) -> String {
567 let mut num = format!("{num:.precision$E}");
568 let exp = num.split_off(num.find('E').unwrap());
570
571 let (sign, exp) = if exp.starts_with("E-") {
572 ('-', &exp[2..])
573 } else {
574 ('+', &exp[1..])
575 };
576 num.push_str(&format!("E{sign}{exp:0>exp_pad$}"));
577
578 num.to_string()
579}
580
581const WB_MODE: *const c_char = c"wb".as_ptr().cast::<c_char>();
582const RB_MODE: *const c_char = c"rb".as_ptr().cast::<c_char>();
583
584#[cfg(not(target_os = "windows"))]
585unsafe extern "C" {
586
587 pub unsafe static mut stdin: *mut FILE;
588
589 pub unsafe static mut stdout: *mut FILE;
590
591 pub unsafe static mut stderr: *mut FILE;
592}
593
594#[cfg(windows)]
595unsafe extern "C" {
596 pub unsafe fn __acrt_iob_func(idx: libc::c_uint) -> *mut FILE;
597}
598
599#[macro_export]
600#[cfg(not(target_os = "windows"))]
601macro_rules! STDIN {
602 () => {
603 $crate::stdin
604 };
605}
606
607#[macro_export]
608#[cfg(windows)]
609macro_rules! STDIN {
610 () => {
611 $crate::__acrt_iob_func(0)
612 };
613}
614
615#[macro_export]
616#[cfg(not(target_os = "windows"))]
617macro_rules! STDOUT {
618 () => {
619 $crate::stdout
620 };
621}
622
623#[macro_export]
624#[cfg(windows)]
625macro_rules! STDOUT {
626 () => {
627 $crate::__acrt_iob_func(1)
628 };
629}
630
631#[macro_export]
632#[cfg(not(target_os = "windows"))]
633macro_rules! STDERR {
634 () => {
635 $crate::stderr
636 };
637}
638
639#[macro_export]
640#[cfg(windows)]
641macro_rules! STDERR {
642 () => {
643 $crate::__acrt_iob_func(2)
644 };
645}
646
647#[cfg(test)]
648mod tests {
649 use std::{ffi::CString, slice};
650
651 use crate::cs;
652 use bytemuck::cast_slice;
653 use cfileio::{ffclos_safer, ffinit_safer};
654
655 use putkey::ffcrim_safer;
656 use tempfile::Builder;
657
658 use crate::{
659 fitsio::{USHORT_IMG, fitsfile},
660 helpers::testhelpers::with_temp_file,
661 };
662
663 use super::*;
664
665 use crate::aliases::rust_api::{fits_update_key, fits_write_img};
666
667 #[test]
668 fn test_write_image() {
669 unsafe {
670 with_temp_file(|filename| {
671 let bitpix = USHORT_IMG;
672 let naxis = 2;
673 const NAXES: [c_long; 2] = [300, 200];
674 let mut storage: [[u16; NAXES[0] as usize]; NAXES[1] as usize] =
675 [[0; NAXES[0] as usize]; NAXES[1] as usize];
676 let mut fptr: Option<Box<fitsfile>> = None;
677 let mut status = 0;
678
679 let tempfile = Builder::new()
680 .prefix("my-temporary-note")
681 .suffix(".fits")
682 .tempfile()
683 .unwrap();
684
685 let tdir = Builder::new().prefix("rsfitsio-").tempdir().unwrap();
686 let abc = Builder::new().prefix("prefix").tempfile();
687 let tdir_path = tdir.path();
688 let filename = tdir_path.join("test.fits");
689
690 let filename_str = filename.to_str().expect("cannot create string filename");
691 let filename_cstr = CString::new(filename_str).unwrap();
692
693 status = ffinit_safer(
694 &mut fptr,
695 cast_slice(filename_cstr.as_bytes_with_nul()),
696 &mut status,
697 );
698 assert_eq!(status, 0);
699
700 let mut fptr = fptr.unwrap();
701
702 status = ffcrim_safer(&mut fptr, bitpix, naxis, &NAXES, &mut status);
703 assert_eq!(status, 0);
704
705 for jj in 0..(NAXES[1] as usize) {
706 for ii in 0..(NAXES[0] as usize) {
707 storage[jj][ii] = (ii + jj) as u16;
708 }
709 }
710
711 let fpixel = 1; let nelements = NAXES[0] * NAXES[1]; let s = slice::from_raw_parts(
716 storage.as_ptr() as *mut u16,
717 (NAXES[0] * NAXES[1]) as usize,
718 );
719 fits_write_img(
720 &mut fptr,
721 TUSHORT,
722 fpixel,
723 nelements as LONGLONG,
724 cast_slice(s),
725 &mut status,
726 );
727 assert_eq!(status, 0);
728
729 let exposure = 1500;
732 fits_update_key(
733 &mut fptr,
734 KeywordDatatype::TLONG(&exposure),
735 cs!(c"EXPOSURE"),
736 Some(cs!(c"Total Exposure Time")),
737 &mut status,
738 );
739 assert_eq!(status, 0);
740
741 ffclos_safer(fptr, &mut status); assert_eq!(status, 0);
743 });
744 }
745 }
746}