#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
extern crate chrono;
extern crate libc;
extern crate num;
use chrono::Utc;
use chrono::NaiveDate;
use chrono::NaiveDateTime;
use chrono::DateTime;
use chrono::Duration;
use std::ffi::CString;
use std::path::Path;
use libc::c_char;
extern crate glob;
include!("bindings.rs");
unsafe impl Send for ms_record {}
unsafe impl Sync for ms_record {}
#[derive(Debug)]
pub struct ms_record(*mut MSRecord);
macro_rules! cast {
($x:ident, $t:ty) => { ($x as *mut _) as *mut $t };
(ptr, $x:ident, $t:ty) => { ((&mut $x) as *mut _) as *mut *mut $t };
}
pub fn fmin<T: num::Float>(v: &[T]) -> T {
let mut vf = v[0];
for vi in v { if *vi < vf { vf = *vi; } }
vf
}
pub fn fmax<T: num::Float>(v: &[T]) -> T {
let mut vf = v[0];
for vi in v { if *vi > vf { vf = *vi; } }
vf
}
pub fn utc_to_f64(t: &DateTime<Utc>) -> f64 {
t.timestamp() as f64 + t.timestamp_subsec_nanos() as f64 / 1e9
}
pub fn f64_to_utc(t: f64) -> DateTime<Utc> {
let i = t.trunc() as i64;
let f = (t.fract() * 1e9) as u32;
let t = NaiveDateTime::from_timestamp(i,f);
DateTime::<Utc>::from_utc(t,Utc)
}
impl BTime {
pub fn as_mut_ptr(&mut self) -> *mut BTime {
self as *mut BTime
}
pub fn zero() -> BTime {
BTime { year:0,day:0,hour:0,min:0,sec:0,fract:0,unused:0}
}
pub fn to_datetime(&self) -> DateTime<Utc> {
let d = NaiveDate::from_yo(self.year as i32, self.day as u32)
.and_hms_micro(self.hour as u32, self.min as u32,
self.sec as u32, self.fract as u32 *100);
DateTime::<Utc>::from_utc(d, Utc)
}
}
pub enum Data<'a> {
Int(&'a [i32]),
Float(&'a [f32]),
Double(&'a [f64]),
Ascii(&'a [u8]),
}
impl <'a> Data<'a> {
pub fn to_f64(&self) -> Vec<f64> {
match self {
&Data::Int(y) => y.iter().map(|&i| i as f64).collect(),
&Data::Float(y) => y.iter().map(|&i| i as f64).collect(),
&Data::Double(y) => y.iter().map(|&i| i).collect(),
&Data::Ascii(_y) => vec![],
}
}
}
impl ms_record {
pub fn ptr(&self) -> MSRecord {
unsafe { *self.0 }
}
pub fn null() -> *mut MSRecord {
let p = unsafe { msr_init(std::ptr::null_mut()) } as *mut MSRecord;
p
}
pub fn read<S>(file: S) -> ms_record
where S: AsRef<Path>
{
let sfile : String = file.as_ref().to_string_lossy().into_owned();
let cfile = CString::new(sfile).unwrap();
let verbose : flag = 1;
let dataflag : flag = 1;
let skipnotdata : flag = 1;
let mut pmsr = ms_record::null();
let mut pmsfp = std::ptr::null_mut() as *mut MSFileParam;
let retcode = unsafe{
ms_readmsr_r ( ((&mut pmsfp) as *mut _) as *mut *mut MSFileParam,
((&mut pmsr) as *mut _) as *mut *mut MSRecord,
cfile.as_ptr(),
0,
std::ptr::null_mut(), std::ptr::null_mut(), skipnotdata,
dataflag,
verbose)
};
if retcode != MS_NOERROR as i32 {
println!("retcode: {}", retcode);
}
ms_record ( pmsr )
}
pub fn header(&self) -> fsdh_s {
let m = self.ptr();
unsafe { * (m.fsdh as *mut fsdh_s) as fsdh_s }
}
pub fn start(&self) -> DateTime<Utc> {
self.header().start_time.to_datetime()
}
pub fn end(&self) -> DateTime<Utc> {
let n = self.npts();
let b = self.start();
let dt = self.delta();
b + Duration::microseconds( ( (n-1) as f64 * dt * 1e6) as i64 )
}
pub fn end1(&self) -> DateTime<Utc> {
let n = self.npts();
let b = self.start();
let dt = self.delta();
b + Duration::microseconds( ( n as f64 * dt * 1e6) as i64 )
}
pub fn delta(&self) -> f64 {
let m = self.ptr();
1.0 / m.samprate
}
pub fn data_type(&self) -> char {
let m = self.ptr();
m.sampletype as u8 as char
}
pub fn dtype(&self) -> char {
let m = self.ptr();
m.sampletype as u8 as char
}
pub fn npts(&self) -> usize {
let m = self.ptr();
m.numsamples as usize
}
pub fn time(&self) -> Vec<DateTime<Utc>> {
let n = self.npts();
let b = self.start();
let dt = self.delta();
(0..n)
.map(|i| (i as f64) * dt * 1e6)
.map(|i| b + Duration::microseconds(i as i64))
.collect::<Vec<DateTime<Utc>>>()
}
fn data(&self) -> Option<Data> {
use std::slice::from_raw_parts_mut;
let m = self.ptr();
let p = m.datasamples;
let n = self.npts();
let y = match self.dtype() {
'i' => {
let y : &[i32] = unsafe {from_raw_parts_mut(p as *mut i32, n) };
Data::Int(y)
},
'f' => {
let y : &[f32] = unsafe { from_raw_parts_mut(p as *mut f32, n) };
Data::Float(y)
},
'd' => {
let y : &[f64] = unsafe { from_raw_parts_mut(p as *mut f64, n) };
Data::Double(y)
},
'a' => {
let y : &[u8] = unsafe { from_raw_parts_mut(p as *mut u8, n) };
Data::Ascii(y)
}
_ => {
println!("Unknown data type: {}", self.dtype());
return None;
},
};
Some(y)
}
fn check_data_type(&self, want: char) {
if self.dtype() != want {
panic!("Incorrect data type: requested: '{}, current: '{}'",
want, self.dtype());
}
}
pub fn data_f64(&self) -> &[f64] {
use std::slice::from_raw_parts_mut;
self.check_data_type('d');
let n = self.npts() as usize;
let p = self.ptr().datasamples;
unsafe { from_raw_parts_mut(p as *mut f64, n) }
}
pub fn data_f32(&self) -> &[f32] {
use std::slice::from_raw_parts_mut;
self.check_data_type('f');
let n = self.npts() as usize;
let p = self.ptr().datasamples;
unsafe { from_raw_parts_mut(p as *mut f32, n) }
}
pub fn data_i32(&self) -> &[i32] {
use std::slice::from_raw_parts_mut;
self.check_data_type('i');
let n = self.npts() as usize;
let p = self.ptr().datasamples;
unsafe { from_raw_parts_mut(p as *mut i32, n) }
}
pub fn min(&self) -> f64 {
match self.data_type() {
'i' => *self.data_i32().iter().min().unwrap() as f64,
'f' => fmin(self.data_f32()) as f64,
'd' => fmin(self.data_f64()) as f64,
'a' => panic!("attempt to take min of ascii data"),
_ => panic!("unknown data type: {}", self.data_type()),
}
}
pub fn max(&self) -> f64 {
match self.data_type() {
'i' => *self.data_i32().iter().max().unwrap() as f64,
'f' => fmax(self.data_f32()) as f64,
'd' => fmax(self.data_f64()) as f64,
'a' => panic!("attempt to take min of ascii data"),
_ => panic!("unknown data type: {}", self.data_type()),
}
}
pub fn id(&self) -> String {
let m = self.ptr();
let net = i8_to_string(&m.network);
let sta = i8_to_string(&m.station);
let loc = i8_to_string(&m.location);
let cha = i8_to_string(&m.channel);
format!("{}_{}_{}_{}", net, sta, loc, cha)
}
pub fn parse(record: &[u8]) -> ms_record {
let verbose = 1;
let data = 1;
let mut rec = record.to_vec();
let prec = &mut rec[..];
let c_rec = cast!(prec, c_char);
let mut pmsr = ms_record::null();
let ppmsr = cast!(ptr, pmsr, MSRecord);
let ret = unsafe { msr_parse(c_rec, record.len() as i32, ppmsr, 0, data, verbose) };
if ret != MS_NOERROR as i32 {
println!("retcode: {}", ret);
}
ms_record( pmsr )
}
pub fn as_string(&self) -> Option<String> {
match self.data() {
Some(Data::Ascii(x)) => Some(String::from_utf8(x.to_vec()).unwrap()),
_ => None
}
}
}
fn i8_to_string(vin: &[i8]) -> String {
let v : Vec<u8> = vin.iter()
.map(|x| *x as u8) .filter(|x| *x != 0u8) .collect();
String::from_utf8(v).unwrap() }
use std::fmt;
impl fmt::Display for ms_record {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let v = self.ptr();
let s = self.id();
write!(f, "{}, {}, {}, {}, {} samples, {} Hz, {}", s, v.sequence_number,
v.dataquality as u8 as char, v.reclen, v.samplecnt,
v.samprate, self.start())
}
}
impl Drop for ms_record {
fn drop(&mut self) {
unsafe {
ms_readmsr (&mut (self.0 as *mut _),
std::ptr::null_mut(),
0,
std::ptr::null_mut(),
std::ptr::null_mut(),
0, 0, 0);
}
}
}
#[cfg(test)]
mod tests {
}