1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
//! A library for SuperDARN DMAP file I/O.
//!
//! [![github]](https://github.com/SuperDARNCanada/dmap) [![crates-io]](https://crates.io/crates/darn-dmap) [![docs-rs]](crate)
//!
//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
//!
//! <br>
//!
//! This library also has a Python API using pyo3.
//!
//! For more information about DMAP files, see [RST](https://radar-software-toolkit-rst.readthedocs.io/en/latest/)
//! or [pyDARNio](https://pydarnio.readthedocs.io/en/latest/).
//!
//! The main feature of this crate is the [`Record`] trait, which defines a valid DMAP record and functions for
//! reading from and writing to byte streams. The SuperDARN file formats IQDAT, RAWACF, FITACF, GRID, MAP, and SND are
//! all supported with structs that implement [`Record`], namely:
//!
//! - [`IqdatRecord`]
//! - [`RawacfRecord`]
//! - [`FitacfRecord`]
//! - [`GridRecord`]
//! - [`MapRecord`]
//! - [`SndRecord`]
//!
//! Each struct has a list of required and optional fields that it uses to verify the integrity of the record.
//! Only fields listed in the required and optional lists are allowed, no required field can be missing, and
//! each field has an expected primitive type. Additionally, each format has groupings of vector fields which
//! must all share the same shape; e.g. `acfd` and `xcfd` in a RAWACF file.
//!
//! There is also a generic [`DmapRecord`] struct which has no knowledge of required or optional fields. When reading from
//! a byte stream, the parsed data will be identical when using both a specific format like [`RawacfRecord`] and the generic
//! [`DmapRecord`]; however, when writing to a byte stream, the output may differ. Since [`DmapRecord`] has no knowledge of
//! the expected primitive type for each field, it defaults to a type that fits the data. For example, the `stid` field may
//! be saved as an `i8` when using [`DmapRecord`] instead of an `i16` which [`RawacfRecord`] specifies it must be.
//!
//! <div class="note">
//! Each type of record has a specific field ordering hard-coded by this library. This is the order in which fields are written to file,
//! and may not match the ordering of fields generated by RST. This also means that round-trip I/O (i.e. reading a file and
//! writing back out to a new file) is not guaranteed to generate an identical file; however, it is guaranteed that all the
//! information is the same, just not necessarily in the same order.
//! </div>
//!
//! <br>
//!
//! # Examples
//!
//! Convenience functions for reading from and writing to a file exist to simplify the most common use cases.
//! This is defined by [`Record::read_file`]
//! ```
//! use dmap::*;
//! use std::path::PathBuf;
//!
//! # fn main() -> Result<(), DmapError> {
//! let path = PathBuf::from("tests/test_files/test.rawacf");
//! let rawacf_data = RawacfRecord::read_file(&path)?;
//! let unchecked_data = DmapRecord::read_file(&path)?;
//!
//! assert_eq!(rawacf_data.len(), unchecked_data.len());
//! assert_eq!(rawacf_data[0].get(&"stid".to_string()), unchecked_data[0].get(&"stid".to_string()));
//!
//! // Write the records to a file
//! let out_path = PathBuf::from("tests/test_files/output.rawacf");
//! RawacfRecord::write_to_file(&rawacf_data, &out_path, false)?;
//! # std::fs::remove_file(out_path)?;
//! # Ok(())
//! # }
//! ```
//! You can read from anything that implements the `Read` trait using the functions exposed by the [`Record`] trait.
//! Detection and decompression of bz2 is also conducted automatically.
//! ```
//! use dmap::*;
//! use std::fs::File;
//! use itertools::izip;
//!
//! # fn main() -> Result<(), DmapError> {
//! let file = File::open("tests/test_files/test.rawacf.bz2")?; // `File` implements the `Read` trait
//! let rawacf_data = RawacfRecord::read_records(file)?;
//!
//! let uncompressed_data = RawacfRecord::read_file("tests/test_files/test.rawacf")?;
//! assert_eq!(rawacf_data.len(), uncompressed_data.len());
//! for (left, right) in izip!(rawacf_data, uncompressed_data) {
//! assert_eq!(left, right)
//! }
//! # Ok(())
//! # }
//! ```
pub
pub
pub
pub use crateDmapError;
pub use crateDmapRecord;
pub use crateFitacfRecord;
pub use crateGridRecord;
pub use crateIqdatRecord;
pub use crateMapRecord;
pub use crateRawacfRecord;
pub use crateSndRecord;
pub use crateRecord;